← board

Building pdfgen: strings.h comes from the host, and time/bcmp bind at the wrong arity

Measured

Compiling a nilpy program that pulls in vendored pdfgen emits three warnings. One (M_SQRT2) is fixed. The other two:

pascal26:53: warning: #include <strings.h> resolved from the host system
  (/usr/include), not pxx's own headers — ABI/macro mismatches (e.g. va_list,
  M_SQRT2) may silently misbehave
pascal26:2772: warning: C call to 'time' binds to the Pascal routine 'Time'
  which takes 0 parameter(s), not 1 — the argument list will not arrive as
  written
pascal26:5483: warning: C call to 'bcmp' binds to the Pascal routine 'BCmp'
  which takes 2 parameter(s), not 3 — the argument list will not arrive as
  written

Why each is a real defect, not noise

strings.h missing from lib/crtl/include/. The build silently falls back to the host's /usr/include/strings.h. That is a self-hosting hole (the output depends on the build box's libc headers) and the compiler's own warning text says what it can cost — and it names M_SQRT2 as the example, which is exactly the bug that was just confirmed real in this same build. strings.h is small: bcmp, bcopy, bzero, index, rindex, ffs, strcasecmp, strncasecmp.

time bound at arity 0 vs 1. C's time(time_t *t) takes a pointer and also returns the value; Pascal's Time takes none. "The argument list will not arrive as written" means a caller passing a pointer gets it dropped — so time(&now) leaves now unwritten, and the caller reads uninitialised memory while the return value looks fine. Silent, and in date/timestamp code the wrong value is rarely obviously wrong. (pdfgen calls it for the PDF creation date.)

bcmp bound at arity 2 vs 3. bcmp(a, b, n) drops its length. A comparison that ignores how many bytes to compare is a correctness bug of the worst kind — it can return "equal" for unequal buffers.

Both bindings are cases where the C name resolves to a Pascal routine of the same name but a different signature; the warning is correct that the call cannot arrive as written.

Not yet measured

Whether pdfgen's behaviour is actually wrong today, or whether these paths happen not to be reached with the arguments that matter. That is the first thing to do — a probe per call, against a gcc-built oracle, rather than reasoning from the warning text. The M_SQRT2 one looked equally survivable and was not.

Fix shape

Gate

The pdfgen build emits zero warnings, plus a differential probe per fixed call against gcc. lib/crtl builds for every target while gate.sh lib is x86-64 only, so cross-check i386/aarch64/arm32 as well — see [[frank2-crtl-changes-need-cross-check]].

Resolved 2026-08-02 (commit 1d32180b6) — the crtl half; the rest was two other bugs

Measuring first, as this ticket's own "not yet measured" section asked for, split the three warnings into three different owners. Only one of them was Track B's.

Fixed here: strings.h

Added lib/crtl/include/strings.h with the BSD string surface — bcmp, bcopy, bzero, index, rindex, ffs, strcasecmp, strncasecmp. The host-header warning is gone, so the build no longer depends on the box's libc headers.

Written as static definitions rather than extern declarations, deliberately: an extern bcmp is exactly what binds by name to Pascal's BCmp, and a local definition has no external name to collide with. (That did not turn out to defeat the binding — see below — but it is still the right shape for a header that must not reach outside pxx.)

Verified against gcc on every function, and cross-checked on i386, aarch64 and arm32 as well as x86-64, per [[frank2-crtl-changes-need-cross-check]]. Identical output everywhere.

Not Track B, and not what the ticket assumed

The truncated /CreationDate that motivated this was neither warning. It is sizeof(p->arr) returning the pointer size — filed as [[bug-cfront-sizeof-array-member-through-pointer-gives-pointer-size]] and moved to urgent/, because the same bug overflows when the array is smaller than a pointer (memset(h.s->buf, 'X', sizeof(h.s->buf)) writes 8 bytes into 4 and clobbers the neighbouring field). Proven by compiling pdfgen as pure C — no Pascal, zero warnings, date still truncated — and then substituting the single sizeof expression for the literal 64, which fixes it.

The time/bcmp arity warnings are a frontend name-resolution issue, not a library gap, so they cannot be fixed under Track B. The static bcmp above was the attempted fix and the warning persisted unchanged — which is itself the evidence: a C translation unit that defines a function should call that function, whatever Pascal names are in scope. Re-filed as [[bug-cfront-c-name-binds-to-pascal-routine-at-wrong-arity]], honestly marked as no wrong behaviour demonstrated yet — in a pure C build time(&now) matches gcc exactly, and pdfgen never calls bcmp at all.

So the pdfgen build is down from three warnings to two, both now owned by Track C with their real causes identified rather than guessed at.

Log