Synonym-streams are always open and can't be closed twice.
Affects | Status | Importance | Assigned to | Milestone | |
---|---|---|---|---|---|
SBCL |
Fix Released
|
Undecided
|
Douglas Katzman |
Bug Description
OPEN-STREAM-P always returns T for SYNONYM-STREAMs:
--
(let ((con (make-concatena
(declare (special con))
(let ((syn (make-synonym-
(values (close syn)
=> T
=> NIL
=> T
--
It appears from a comment in src/code/
Next, SBCL makes it an error to CLOSE a SYNONYM-STREAM twice:
--
(let ((con (make-concatena
(declare (special con))
(let ((syn (make-synonym-
(values (close syn)
(close syn))))
--
This isn't compatible with the dictionary entry for CLOSE, which says it's permissible to close an already closed stream. (This is a useful property in programs that traffic in lots of streams and can't manage all of them using WITH forms.) It's also pathological that the logic by which the second CLOSE errors is that SBCL considers SYN to always be open while CON isn't, especially given that CON can be repeatedly closed without error.
In summary, none of the above code closes a component stream /prior/ to closing the composite stream; SBCL gives odd semantics to OPEN-STREAM-P and CLOSE on a SYNONYM-STREAM that allows 22.1.4 to be part of the consideration in the above cases.
So I propose that the definitions of OPEN-STREAM-P and CLOSE for SYNONYM-STREAM merely delegate to the target stream. (It turns out that changing OPEN-STREAM-P this way seems to suffice to change CLOSE, too.) Patch attached, and four test cases are below. Note that this change supplies non-error semantics to one case that has undefined consequences and that currently errors (the third test below), though I'd argue that this slight permissiveness is worth getting the above cases to work more reasonably.
Thanks in advance for any consideration.
--
;;; Tests for OPEN-STREAM-P and CLOSE on a SYNONYM-STREAM.
;; Prior 2.0.10.76, this returned T, NIL, T.
(sb-rt:deftest (open-stream-p synonym-
(let ((con (make-concatena
(declare (special con))
(let ((syn (make-synonym-
(values (close syn)
t
nil
nil)
;; Prior 2.0.10.76, this errored on the second CLOSE.
(sb-rt:deftest (close synonym-stream twice)
(let ((con (make-concatena
(declare (special con))
(let ((syn (make-synonym-
(values (close syn)
(close syn))))
t
t)
;; This form has undefined consequences. Prior to 2.0.10.76, the
;; second CLOSE errored because CON was closed prior to trying to
;; close SYN. After, treats SYN as closed, and so the second CLOSE has
;; no effect.
(sb-rt:deftest (close)
(let ((con (make-concatena
(declare (special con))
(let ((syn (make-synonym-
(values (close con) ; has undefined consequences
(close syn))))
t
t)
;; SYNONYM-STREAMs will always have the unique property that the nature
;; and status of the stream can change because the value of the synonym
;; variable changes. So if a SYNONYM-STREAM can go from EOF to
;; not-EOF, or from a binary stream to a character stream,
;; why not closed to open?
;; Prior to 2.0.10.76 this returned T, NIL, T, T T.
(sb-rt:deftest (close-then-frob synonym-stream)
(let ((con1 (make-concatena
(con2 (make-concatena
(declare (special con1 con2))
(let ((syn (make-synonym-
(apply #'values
(close syn)
(progn (setq con1 con2)
t
nil
nil
t
t)
--
Bug reporting metadata:
$ uname -a
Darwin m5.local 19.6.0 Darwin Kernel Version 19.6.0: Mon Aug 31 22:12:52 PDT 2020; root:xnu-
$ sbcl --version
SBCL 2.0.0
$ sbcl --no-userinit --no-sysinit --non-interactive --eval '(format t "~{~S~%~}" *features*)'
This is SBCL 2.0.0, an implementation of ANSI Common Lisp.
More information about SBCL is available at <http://
SBCL is free software, provided as is, with absolutely no warranty.
It is mostly in the public domain; some portions are provided under
BSD-style licenses. See the CREDITS and COPYING files in the
distribution for more information.
:X86-64
:64-BIT
:ALIEN-CALLBACKS
:ANSI-CL
:AVX2
:BSD
:C-STACK-
:CALL-SYMBOL
:COMMON-LISP
:COMPACT-
:COMPARE-
:CYCLE-COUNTER
:DARWIN
:FP-AND-
:GENCGC
:IEEE-FLOATING-
:IMMOBILE-CODE
:IMMOBILE-SPACE
:INODE64
:INTEGER-EQL-VOP
:LINKAGE-TABLE
:LITTLE-ENDIAN
:MACH-EXCEPTION
:MACH-O
:OS-PROVIDES-
:OS-PROVIDES-DLADDR
:OS-PROVIDES-DLOPEN
:OS-PROVIDES-PUTWC
:OS-PROVIDES-
:PACKAGE-
:SB-CORE-
:SB-DOC
:SB-EVAL
:SB-LDB
:SB-PACKAGE-LOCKS
:SB-SIMD-PACK
:SB-SIMD-PACK-256
:SB-SOURCE-
:SB-THREAD
:SB-UNICODE
:SBCL
:STACK-
:STACK-
:STACK-
:STACK-
:STACK-
:UNDEFINED-
:UNIX
:UNWIND-
Changed in sbcl: | |
status: | New → Confirmed |
Changed in sbcl: | |
status: | Fix Committed → Fix Released |
Should CLOSE actually close the underlying stream?
As it says "The effect of close on a constructed stream is to close the argument stream only. There is no effect on the constituents of composite streams."