GNU bug report logs -
#79762
Guile may run stale code if source changes too quickly
Previous Next
To reply to this bug, email your comments to 79762 AT debbugs.gnu.org.
Toggle the display of automated, internal messages from the tracker.
Report forwarded
to
bug-guile <at> gnu.org:
bug#79762; Package
guile.
(Mon, 03 Nov 2025 22:02:01 GMT)
Full text and
rfc822 format available.
Acknowledgement sent
to
Rob Browning <rlb <at> defaultvalue.org>:
New bug report received and forwarded. Copy sent to
bug-guile <at> gnu.org.
(Mon, 03 Nov 2025 22:02:02 GMT)
Full text and
rfc822 format available.
Message #5 received at submit <at> debbugs.gnu.org (full text, mbox):
[Message part 1 (text/plain, inline)]
In the past I'd noticed that guile appeared to be running stale code,
and I finally got a chance to track it down with help from Dale Smith.
The cause is that filesystems have finite (and sometimes quite coarse)
timestamp "granularity", and guile currently treats equal timestamps
between a .scm file and .go file as meaning that the .go file is up to
date, i.e. represents the compilation of the code in the .scm
file. Right now that is not always true, and can produce undesiarable
results:
For example, if you do this:
echo '(display "something bad\n")' > test.scm
guile test.scm
echo '(display "the (broken) fix)' > test.scm
guile test.scm
The final guile invocation may actually succeed while printing
"something bad" if the test.go generated by the first guile invocation
ends up with the same timestamp as the one with the fix. It's not even
relevant that the fix is actually itself broken (invalid syntax) because
guile never attempts to compile it --- it just runs the "bad" test.go.
To fix this, we can change compiled_is_fresh in load.c to require the
.go to be strictly newer than the corresponding .scm, i.e. change the <=
to < here:
if (source_mtime.tv_sec < compiled_mtime.tv_sec
|| (source_mtime.tv_sec == compiled_mtime.tv_sec
&& source_mtime.tv_nsec <= compiled_mtime.tv_nsec))
compiled_is_newer = 1;
...
and in more-recent? in boot-9.scm, change >= to > here:
(and (= (stat:mtime stat1) (stat:mtime stat2))
(>= (stat:mtimensec stat1)
(stat:mtimensec stat2)))))
This script demonstrates the problem for the latter case:
[test-stale-load (text/x-sh, inline)]
#!/bin/bash
set -ueo pipefail
guile="${GUILE:-guile}"
top="$(pwd)"
tmpdir=''
on-exit() { cd "$top"; if test "$tmpdir"; then rm -rf "$tmpdir"; fi; }
trap on-exit EXIT
tmpdir="$(mktemp -d show-stale-load-XXXXXXX)"
cd "$tmpdir"
mkdir cache
export XDG_CACHE_HOME="$(pwd)/cache"
while true; do
echo '(display "game over\n")' > foo.scm
"$guile" foo.scm > /dev/null
# (Compilation of) this broken fix should be rejected, but rarely
# it's not because foo.scm here ends up with the same timestamp as
# the foo.go compiled above.
echo '(display "fixed)' > foo.scm
if "$guile" foo.scm | tee foo.log; then
echo 'broken fix did not provoke an error'
fi
if grep -q 'game over' foo.log; then
# stat foo.scm "$(find -name foo.scm.go)"
echo '=== ran bad code even after fix was in place ==='
exit 2
fi
done
[Message part 3 (text/plain, inline)]
Thanks to Dale Smith for finding the root causes.
--
Rob Browning
rlb @defaultvalue.org and @debian.org
GPG as of 2011-07-10 E6A9 DA3C C9FD 1FF8 C676 D2C4 C0F0 39E9 ED1B 597A
GPG as of 2002-11-03 14DD 432F AE39 534D B592 F9A0 25C8 D377 8C7E 73A4
This bug report was last modified 1 day ago.
Previous Next
GNU bug tracking system
Copyright (C) 1999 Darren O. Benham,
1997,2003 nCipher Corporation Ltd,
1994-97 Ian Jackson.