2026-09-03 - (/loop) Two formatter bugs, in the padding nobody had tested
differential 263 -> 286 cases
libc bugs found this week +2
Arrived by hand again - the seventeenth wakeup that did not fire.
sprintf
had no cases, and twenty-three of them found two bugs
sprintf/width-zero-negative: buffer is 30302d3432…, expected 2d30303432…
sprintf/precision: returned 0x2, glibc returned 0x3
%05d of -42 rendered
00-42. Padding was applied uniformly after
rendering, so a negative number got its zero fill in front of its sign.
ISO C 7.21.6.1 puts the 0 fill after the sign:
-0042. Nothing could have caught it by reading - the length
is right, the digits are right, and only the order of two characters is
wrong.
%.3d of 42 rendered 42.
Precision was read, applied to %s where it truncates, and
to nothing else. For d i o u x X it is the minimum
number of digits, so 042 and a return of 3. Two more
rules came with it: a specified precision makes the 0 flag
ignored, and a precision of zero with a value of zero renders nothing at
all.
D511. Both watched failing separately, by reverting each half of the fix on its own - one break would have left the other half unproven.
Why these cases found what the existing ones could not
snprintf has had cases since the differential was built
and every one formats %d with no flags.
The interesting failures in a formatter are not in any one conversion,
they are in the specifier parser. So the format string is a case
input here, and the twenty-three cases sweep conversions and
flags rather than values - %d %i %u %x %X %o %p %c %%,
width, left-justified, zero-padded, precision, and a width narrower than
the value.
That shape is worth more than either bug.
Housekeeping the cases forced
run in the differential test grew an if
block per shape and hit the 100-line ceiling twice
while these were being added. Consolidated into one match
naming which replay each function takes: adding a shape is now a line,
and a reader asking how memcpy is replayed has a list
rather than a chain.
Check 11 held again - run_format takes its
implementation by name from a constant rather than from the case, but
only because sprintf is the sole function on that path; the
comment says so in case a second one arrives.
State
cargo test --workspace green - 119 suites, 1998
tests, 0 failures. Differential 286 cases, all
agreeing. clippy --tests clean, fmt clean, identity scan
clean on both.
Nothing committed. The day holds worklogs 292-360 and D466-D511.
Next: vsnprintf is the last uncovered
differential function and needs a va_list. The
wide-character family and an interleaved-sequence shape both still need
a record-format decision.