Subject: compiler disrespects referential integrity

From: Zefram <[email-masked]>
Date: Sun, 5 Jan 2014 23:13:47 +0000

The guile-2.0.9 compiler doesn't preserve the distinctness of mutable
objects that are referenced in code via the read-eval (#.) facility.
(I'm not mutating the code itself, only quoted objects.)  The interpreter,
and for comparison guile-1.8, do preserve object identity, allowing
read-eval to be used to incorporate direct object references into code.
Test case:

$ cat t9
(cond-expand
  (guile-2 (defmacro compile-time f `(eval-when (compile eval) ,@f)))
  (else (defmacro compile-time f `(begin ,@f))))
(compile-time (fluid-set! read-eval? #t))
(compile-time (define aaa (cons 1 2)))
(set-car! '#.aaa 5)
(write '#.aaa)
(newline)
(write '(1 . 2))
(newline)
$ guile-1.8 t9
(5 . 2)
(1 . 2)
$ guile-2.0 --no-auto-compile t9
(5 . 2)
(1 . 2)
$ guile-2.0 t9
;;; note: auto-compilation is enabled, set GUILE_AUTO_COMPILE=0
;;;       or pass the --no-auto-compile argument to disable.
;;; compiling /home/zefram/usr/guile/t9
;;; compiled /home/zefram/.cache/guile/ccache/2.0-LE-8-2.0/home/zefram/usr/guile/t9.go
(5 . 2)
(5 . 2)
$ guile-2.0 t9
(5 . 2)
(5 . 2)

In the test case, the explicitly-constructed pair aaa is conflated with
the pair literal (1 . 2), and so the runtime modification of aaa (which
is correctly mutable) affects the literal.

This issue seems closely related to the problem described at
<http://debbugs.gnu.org/cgi/bugreport.cgi?bug=11198>, wherein the compiler
is entirely unable to handle code incorporating references to some kinds
of object.  In that case the failure mode is a compile-time error, so
the problem can be worked around.  The failure mode with pairs, silent
misbehaviour, is a more serious problem.  Between them, these problems
break most of the interesting uses for read-eval, albeit only when using
the compiler.

Debian incarnation of this bug report:
http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=734157

-zefram