enlarge() in picosat.c rebases every stored Lit*/Rnk* by the byte distance
the arrays moved during realloc, holding that distance in a long. On LLP64
(Windows x64) long is 32 bits while pointers are 64, so a move of more than
2GB truncates and every rebased pointer is left wild.
The bug does not normally reproduce on Linux for two independent reasons, and you have to remove both to see it:
- LP64 has a wide enough
long. Simulate LLP64 by making only the delta variablesint32_t, leaving pointers 64-bit. This is faithful: on LLP64 both the delta variable and thefix_*parameters are 32-bit, so truncating once at the assignment and sign-extending into the (64-bit) parameters gives the same arithmetic. - glibc's
reallockeeps blocks close together, so the >2GB move never happens. Force it by routing picosat's three allocation primitives (new/delete/resize, all of which carry explicit sizes) through anmmapallocator that places each block 4GB past the previous one.
With both removed, the failure is deterministic: 6/6 crash with the
truncating delta, 6/6 survive with ptrdiff_t. Same allocator, same
workload, same compiler — the delta type is the only variable.
int32_t delta: PICOTRUNC max_var=0 real=38654705664 as32=0
PICOTRUNC max_var=11164 real=24133421236224 as32=0
Segmentation fault (signal 11)
ptrdiff_t delta: same two truncations detected
solve result = 10 (SAT), SURVIVED
The max_var=0 truncation is harmless — it happens during picosat_adjust on
an empty solver, where the fix-up loops have nothing to iterate. The fatal one
is on a populated solver.
tar xzf picosat-965.tar.gz
cp -r picosat-965 far_trunc && (cd far_trunc && patch -p1 < ../exp_trunc.diff)
cp -r picosat-965 far_fixed && (cd far_fixed && patch -p1 < ../exp_trunc.diff \
&& sed -i 's/int32_t rnks_delta, lits_delta;/ptrdiff_t rnks_delta, lits_delta;/' picosat.c)
# build each as a shared lib, then:
gcc -O2 -Ipicosat-965 driver.c -o driver_trunc far_trunc/libpicosat.so -Wl,-rpath,far_trunc
gcc -O2 -Ipicosat-965 driver.c -o driver_fixed far_fixed/libpicosat.so -Wl,-rpath,far_fixed
./driver_trunc 11164 # segfaults
./driver_fixed 11164 # survivesNOTE: exp_trunc.diff is a diagnostic scaffold, not the proposed
fix. The proposed fix is only long -> ptrdiff_t at the two delta
declarations and the nine fix_* signatures.