Skip to content

Treat appending an empty string as a no-op, not an error (0.6.5) - #36

Merged
xcomart merged 1 commit into
masterfrom
fix/empty-string-append
Aug 3, 2026
Merged

Treat appending an empty string as a no-op, not an error (0.6.5)#36
xcomart merged 1 commit into
masterfrom
fix/empty-string-append

Conversation

@xcomart

@xcomart xcomart commented Aug 3, 2026

Copy link
Copy Markdown
Owner

CMUTIL_StringAddNString folded two unrelated conditions into one branch: a NULL pointer, which is a genuine programming error, and a size of zero, which is not. Every empty append returned -1 and logged an ERROR with a stack trace.

The consequence surfaced through Replace. Removing a substring is spelled Replace(needle, ""), and the empty replacement made AddString fail, sending Replace to its failure path — it destroyed the result and returned NULL. Stripping the dash out of "UTF-8" is exactly the combination that broke, and callers that dereferenced the result crashed. This killed libcmdbm's MySQL/MariaDB module in normal use.

Changes

  • AddNString rejects NULL and returns the current size for a zero-size append. AddString, Replace and XmlSetName all follow from that one change.
  • InsertNString carried the same defect, fixed the same way — with the index validated before the size, because an out of bound index stays an error even when there is nothing to insert.
  • InsertString and InsertAnother were missing the NULL guard their Add counterparts already had, and crashed on a NULL argument instead of reporting it.
  • Replace dropped the return value of the AddString that appends the tail after the last match, while checking it inside the loop. Both are checked now.
  • The header documented only "New size of this string object", with nothing about error returns or empty input. The contract is now written down.

Tests

Regression coverage in string_test: empty and NULL append/insert, out of bound index with nothing to insert, Replace("UTF-8", "-", "") == "UTF8", needle at the start, at the end and consecutive ("--a--b--""ab"), and the source left unchanged. xml_test covers SetName("").

ctest 15/15, no build warnings.

CMUTIL_StringAddNString folded two unrelated conditions into one branch:
a NULL pointer, which is a genuine programming error, and a size of zero,
which is not. Appending nothing should quietly do nothing and report the
unchanged size. Instead every such call returned -1 and logged an ERROR
with a stack trace.

The consequence surfaced through Replace. Removing a substring is spelled
Replace(needle, ""), and the empty replacement made AddString fail, which
sent Replace to its failure path: it destroyed the result and returned
NULL. Stripping the dash out of "UTF-8" - a textbook use of Replace - was
exactly the combination that broke, and callers that dereferenced the
result crashed. XmlSetName has the same shape (Clear then AddString) and
logged an ERROR with a stack trace on every empty name, drowning real
errors in noise.

AddNString now rejects NULL and returns the current size for a zero-size
append. AddString, Replace and XmlSetName all follow from that one change.

InsertNString carried the same defect and is fixed the same way, with one
difference: the index is validated before the size is considered, because
an out of bound index stays an error even when there is nothing to insert.
InsertString and InsertAnother were missing the NULL guard their Add
counterparts already had, and crashed on a NULL argument instead of
reporting it.

Replace also dropped the return value of the AddString that appends the
tail after the last match, while checking it inside the loop. Both are
checked now.

The header documented only "New size of this string object" for these
methods, with nothing about error returns or empty input. The contract is
now written down: an empty append or insert is a no-op returning the
unchanged size, NULL returns -1, an out of bound index returns -1, and an
empty alter passed to Replace removes every occurrence of the needle.
@xcomart
xcomart merged commit f88a777 into master Aug 3, 2026
5 checks passed
@xcomart
xcomart deleted the fix/empty-string-append branch August 3, 2026 09:17
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.

1 participant