String ordering comparison ignores content on x86-64 under the byte-prefix mode
Silent wrong answers, no crash. Any sort, binary search, or ordered insert
over string[N] is wrong under the flag. = and <> are correct (fixed with
the field-compare work); only the ORDERING operators are affected.
Repro
program o2;
var a, b: string[10];
begin
a := 'abc'; b := 'abd';
WriteLn('abc vs abd : a<b=', a<b, ' a>b=', a>b, ' a=b=', a=b);
a := 'abd'; b := 'abc';
WriteLn('abd vs abc : a<b=', a<b, ' a>b=', a>b, ' a=b=', a=b);
a := 'zzz'; b := 'aaa';
WriteLn('zzz vs aaa : a<b=', a<b, ' a>b=', a>b, ' a=b=', a=b);
end.
Measured at 45f6639f5, compiler sha a43276f1ce47, exit 0 both modes.
| row | default | -dPXX_SHORTSTRING (x86-64) |
|---|---|---|
abc vs abd |
a<b=TRUE a>b=FALSE |
a<b=FALSE a>b=TRUE |
abd vs abc |
a<b=FALSE a>b=TRUE |
a<b=FALSE a>b=TRUE |
zzz vs aaa |
a<b=FALSE a>b=TRUE |
a<b=FALSE a>b=TRUE |
The answer is a<b=FALSE, a>b=TRUE for every input, which is what comparing
two fixed stack slots as integers looks like — the same shape as the CmpFusible
address comparison, in the ordering path rather than the equality path.
x86-64 only. i386, arm32, aarch64 and riscv32 all answer a<b=TRUE for
abc vs abd under the flag.
The guard trap — two of the three rows are RIGHT BY ACCIDENT
abd vs abc and zzz vs aaa both give the correct answer, because the
constant wrong answer happens to match. A probe built from either of those
pairs passes with the bug fully present. Only an ordering whose true answer is
a<b=TRUE distinguishes. Any content-blind comparison is right half the time by
construction — so an ordering probe needs BOTH directions, asserted, or it is not
a guard.
RESOLVED — 1c6234031
Cause: EmitAnsiStrCmp3Reg, the sibling helper never grepped for after fixing EmitAnsiStrCmpReg.
Re-verified at 05f50f9ae with the repro in this ticket, unchanged, against the FPC 3.2.2 oracle: exact match at default AND -dPXX_SHORTSTRING. Covered going forward by test/test_frozen_field_and_deref_readers.pas, wired into all 12 expected blocks (4 native modes; x86-64, aarch64, arm32, riscv32, xtensa x 2 modes) — the 32-bit targets included, since this is a width class and x86-64 is where width bugs hide.
Log
- 2026-09-03 — resolved; this names the commit that carried the resolve, which is not always the one that carried the change — commit 24a899f7a.