← board

tools/gcc_diff_probe.sh — gcc-oracle differential for crtl

What it is

56 cases over string.h, stdlib.h, ctype.h, stdio.h, time.h, unistd.h and integer edges. Each case is a whole C program run under gcc and under pxx (libc-free — a glibc-linked run would agree trivially); stdout+stderr and the exit code are compared.

Deliberately carried over from fpc_diff_probe.sh, because each was a lesson:

New here:

What it found

Native, first run — four crtl bugs, all fixed:

isprint used the whole space class, so isprint('\t') was true — every "safe to echo / needs escaping" test passed the control characters
fread one read() call, no loop (a short read on a pipe/socket lost data) and never set the EOF flag, so while (!feof(f)) did not terminate on the flag it tests
strftime on overflow returned the TRUNCATED length instead of 0, handing back "200" as a year
strtol/strtoull "0x" with no hex digit consumed the x; and "no conversion" left endptr past the whitespace/sign it had speculatively eaten instead of back at the start

--target i386, first run — two more, in different lanes:

__pxx_exit exit_group hardcoded to 231, x86-64's number. On i386/arm32 that is fgetxattr; on aarch64 it is not exit_group either. So C's exit(3) quietly failed an xattr call and the process exited 0 — every cross-target program reporting failure through exit() reported SUCCESS. Fixed here (Track B, lib/rtl/pxxcio.pas); return 3 from main was unaffected, which is why nothing caught it.
varargs width a bare pointer difference passed inline to a variadic function pushes 8 bytes on 32-bit and shifts every later argument. Filed as [[bug-a-pointer-difference-as-vararg-pushes-8-bytes-on-32bit]] — Track A, not fixed here.

Plus a harness bug in tools/run_target.sh: the i386 native-exec path sent the program's stderr to /dev/null, so every i386 run silently lost its diagnostics — including for tools/run_c_conformance.sh, which compares combined stdout+stderr. Fixed (and not by buffering it to a file and replaying it: that reorders it against stdout, and the interleaving is part of what callers compare).

Traps this harness walked into — worth knowing before adding a case

Twice the tool reported a divergence that was the case, not the compiler, and both times gcc was producing garbage too:

  1. printf("%ld %d\n", strtol(s, &e, 0), (int)(e - s)) — the call and the read of what it sets in one argument list is unspecified order, and gcc really does evaluate e - s first. Same shape as reading errno inline.
  2. printf("%ld %d\n", ftell(f), fgetc(f))fgetc moves the position, so the printed ftell depends on evaluation order. pxx orders arguments differently on arm32/aarch64 than on x86-64, all of it legal, which made it look like a cross-target bug.

Sequence the calls; never read a side effect in the argument list that causes it.

Status

Clean on native, i386, arm32 and aarch64 — 0 new divergences, with the two filed 32-bit bugs tagged known.

Gate

tools/gcc_diff_probe.sh exits 0; gate.sh quick + gate.sh lib green; c-testsuite 219/0/1 native and i386.