*PRINT-CIRCLE* crosstalk between streams
Affects | Status | Importance | Assigned to | Milestone | |
---|---|---|---|---|---|
SBCL |
Confirmed
|
Medium
|
Unassigned |
Bug Description
In sbcl-0.8.10.48 it's possible for *PRINT-CIRCLE* references to be
mixed between streams when output operations are intermingled closely
enough (as by doing output on S2 from within (PRINT-OBJECT X S1) in the
test case below), so that e.g. the references #2# appears on a stream
with no preceding #2= on that stream to define it (because the #2= was
sent to another stream).
(cl:in-package :cl-user)
(defstruct foo index)
(defparameter *foo* (make-foo :index 4))
(defstruct bar)
(defparameter *bar* (make-bar))
(defparameter *tangle* (list *foo* *bar* *foo*))
(defmethod print-object ((foo foo) stream)
(let ((index (foo-index foo)))
(format *trace-output*
"~&-$- emitting FOO ~D, ambient *BAR*=~S~%"
index *bar*)
(format stream "[FOO ~D]" index))
foo)
(let ((tsos (make-string-
(ssos (make-string-
(let ((*print-circle* t)
(prin1 *tangle* *standard-output*))
(let ((string (get-output-
(unless (string= string "(#1=[FOO 4] #S(BAR) #1#)")
;; In sbcl-0.8.10.48 STRING was "(#1=[FOO 4] #2# #1#)".:-(
(error "oops: ~S" string)))))
It might be straightforward to fix this by turning the
*CIRCULARITY-
per-stream slots, but (1) it would probably be sort of messy faking
up the special variable binding semantics using UNWIND-PROTECT and
(2) it might be sort of a pain to test that no other bugs had been
introduced.
Changed in sbcl: | |
importance: | Undecided → Medium |
status: | New → Confirmed |
Since today there is multi-threading, the *CIRCULARITY- HASH-TABLE* and *CIRCULARITY- COUNTER* can't be per stream slots. They need to be maintained per <thread,stream> combination.
It is debatable if this is a sufficient key, given that "22.4.19 *print-circle*" says:
"If a user-defined print-object method prints to a stream other than the one that was supplied, then circularity detection starts over for that stream."
'Starts over' taken literally, it would say that any user function used as print customization which writes to a different stream than the supplied one defines a new context.
Printing to the same stream from different contexts, whether dynamically scoped or via multiple threads has then undefined consequences.