RAND_MAX: conforming vs. what code actually expects
Surfaced by the busybox 1.37.0 sweep. editors/awk.c is now the ONLY busybox
file blocked by something other than a missing crtl function:
pascal26:3416: error: #error in editors/awk.c:
Not implemented for this value of RAND_MAX
awk's source handles exactly two cases, RAND_MAX == 0x7fffffff and
RAND_MAX == 0x7fffffffffffffff, and #errors on anything else.
The state of things
lib/crtl/include/stdlib.h:
#define RAND_MAX 32767
lib/crtl/src/stdlib.c implements C99 7.20.2.2's own example generator and
returns (state / 65536) % 32768, i.e. [0, 32767]. The header comment there
is explicit that the SEQUENCE is not portable and that matching glibc's was
rejected deliberately — that reasoning is about the sequence, and says nothing
about the RANGE.
Why this is a question and not a bug
C99 7.20.2.1 requires only RAND_MAX >= 32767. pxx is conforming. Under the
FPC-parity ceiling's logic — we care about compiling correct code, not about
mimicking a reference implementation — a program that assumes more than the
standard promises is the program's problem.
Against that: glibc, musl, the BSDs and every Linux libc use 2147483647.
"Real C code compiles" is the actual goal of the C frontend, and 32767 is a
value no modern program is written against. It also costs precision: a program
building a double from rand()/RAND_MAX gets 15 bits instead of 31.
The options
- Leave it. Conforming; busybox awk is one file; pxx does not chase implementations.
- Raise RAND_MAX to 2147483647 and widen
rand()to return 31 bits (still the standard's own generator, just not discarding the high half). Unblocks awk and matches every libc a C program was written against. Changes the valuesrand()returns, sotest/crand_props.cneeds re-reading — it asserts properties, not values, so it should survive, but that must be checked rather than assumed. - Raise the macro only, leaving
rand()at 15 bits. Rejected outright — that is the one combination that is a genuine defect: code scaling byRAND_MAXwould silently lose 16 bits of range.
Option 2 is the recommendation, but it is a behaviour change to a shipped library and the user's call.