Skip to content

Preserve whitespace-prefixed multiline values when quotes are enabled - #102

Merged
brofield merged 1 commit into
brofield:masterfrom
fhgffy:fix-quoted-multiline-whitespace
Oct 4, 2026
Merged

brofield merged 1 commit into
brofield:masterfrom
fhgffy:fix-quoted-multiline-whitespace

Conversation

@fhgffy

@fhgffy fhgffy commented Oct 4, 2026

Copy link
Copy Markdown
Contributor

Summary

With SetQuotes(true) and SetMultiLine(true), a value beginning with whitespace is quoted before the writer checks for embedded newlines. For example, " first\nsecond" is saved as:

[section]
key = " first
second"

Reloading returns only " first, including the opening quote, and drops the second line.

Move the leading-whitespace check in IsSingleLineQuotedValue after its newline scan, so multiline values use the existing multiline serializer. Single-line whitespace and quoted-string handling stay the same.

The regression test covers leading space, tab, and newline, whitespace-only content, trailing whitespace, and an end-tag collision.

Validation

  • Unmodified upstream fd6db69efc40a687bf4ef81486b54066e34992dd: reproducer and new regression fail; existing 284 tests pass
  • Patched: 285 tests pass with GCC 14.2, C++17, Debug, warnings as errors
  • make format-check passes with clang-format 18.1.8; git diff --check passes
  • Independent standalone review: 15,652 char/wchar boundary checks pass under ASan/UBSan, including quote modes, CR/CRLF normalization, and tag collisions
  • Full sanitizer suite passes all 285 tests with ASAN_OPTIONS=detect_leaks=0:alloc_dealloc_mismatch=0

Without that allocation-mismatch adjustment, both pristine and patched full sanitizer test binaries abort before test bodies: the existing allocation-failure hooks return malloc storage from nothrow operator new, while GoogleTest frees a temporary buffer with operator delete. The standalone checks do not need that adjustment. Leak detection was disabled because it cannot run under the sandbox's ptrace environment. Windows, macOS, and ARM were not tested locally.

@fhgffy
fhgffy marked this pull request as ready for review October 4, 2026 05:09
@cursor

cursor Bot commented Oct 4, 2026

Copy link
Copy Markdown

Independently verified the functional bug on master (fd6db69) and the fix on this branch (fe0ba0d). No code changes from this review.

On the sanitizer / malloc note in the description: the diagnosis is correct, and it is pre-existing. It is not introduced by this PR.

tests/ts-regressions.cpp replaces only the nothrow operator new / operator new[] and returns __wrap_malloc() / __real_malloc() storage. It does not replace any operator delete / operator delete[], including the sized overloads.

The first abort is not GoogleTest calling new (std::nothrow) itself. testing::TestSuite::Run() calls std::stable_sort on its TestInfo* vector. libstdc++ std::get_temporary_buffer then does ::operator new(n, std::nothrow) (stl_tempbuf.h), which hits the test hook and gets malloc memory. The matching free is sized ::operator delete(p, n) from __return_temporary_buffer. ASan reports alloc-dealloc-mismatch (malloc vs operator delete) at the start of the first suite, before any test body runs.

Confirmed on both pristine master and this PR with GCC 13.3, ASan+UBSan. ASAN_OPTIONS=alloc_dealloc_mismatch=0 is a valid workaround for running the suite, not a fix. With detect_leaks=1:alloc_dealloc_mismatch=0, all 285 tests passed here, so leak detection is a separate environment limitation rather than something this hook inherently breaks.

A follow-up (not this PR) should pair those nothrow new replacements with matching delete/delete[] overloads that call free, including operator delete(void*, std::size_t). SimpleIni itself also uses new (std::nothrow) and delete[], so the same mismatch would fire in library paths if the suite ever got past the stable_sort abort.

@brofield
brofield merged commit 077ee64 into brofield:master Oct 4, 2026
7 checks passed
@brofield

brofield commented Oct 4, 2026

Copy link
Copy Markdown
Owner

Thanks for your contribution!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants