FIND-RESTART, when given a RESTART, omits to check if the restart is still active according to its test-function and condition-restarts associations
Affects | Status | Importance | Assigned to | Milestone | |
---|---|---|---|---|---|
SBCL |
Fix Released
|
Undecided
|
Unassigned |
Bug Description
What I do:
(let ((activep t))
(restart-bind ((dynamically-
(let ((actual-restart
(values
;; Inactive because of condition-restarts associations.
(let ((required-
;; Inactive because of test-function.
(progn
(setf activep nil)
What happens:
Values returned:
#<RESTART DYNAMICALLY-
#<RESTART DYNAMICALLY-
What I expected to happen:
Values returned:
NIL
NIL
Analysis:
From CLHS FIND-RESTART:
"If identifier is a currently active restart, then it is returned. Otherwise, nil is returned."
I'm pretty sure a restart is not considered "active" if its test-function returns false.
I'm less sure about condition-restarts associations, but I think the same behavior (returning NIL) should apply.
The only way to test if a RESTART that you have in your hands is still valid is to call FIND-RESTART on it, since there's no portable way to query condition-restarts associations or call a RESTART's test-function directly. It might be possible to test the restart for validity by trying to FIND-RESTART its RESTART-NAME, but this is inefficient, unidiomatic, error-prone (this restart might have been shadowed by another restart of the same name since FIND-RESTART was called the first time), and convoluted compared to just using the restart itself.
Note that INVOKE-RESTART has the same type of problem (calling the restart-function when given an actual restart as argument while still in its dynamic extent yet being inactive because of condition-restarts associations or test-function returning false), but in SBCL INVOKE-RESTART indirectly invokes FIND-RESTART so this is really the same problem...
From CLHS INVOKE-RESTART:
"If restart is not valid, an error of type control-error is signaled."
SBCL version: 1.0.42
uname -a: Linux dynamorph 2.6.32-30-generic #59-Ubuntu SMP Tue Mar 1 21:30:21 UTC 2011 i686 GNU/Linux
*features*:
(:SWANK :QUICKLISP :SB-BSD-
:SBCL :SB-DOC :SB-TEST :SB-LDB :SB-PACKAGE-LOCKS :SB-UNICODE :SB-EVAL
:SB-SOURCE-
:LARGEFILE :GENCGC :STACK-
:COMPARE-
:STACK-
:STACK-
:CYCLE-COUNTER :INLINE-CONSTANTS :MEMORY-
:OS-PROVIDES-
Changed in sbcl: | |
status: | New → Fix Committed |
Changed in sbcl: | |
status: | Fix Committed → Fix Released |
Other implementations seem to support the interpretation in the report (see results below).
See https:/ /bugs.launchpad .net/sbcl/ +bug/769615 for a patch which adds MAP-RESTARTS and also changes the behavior of FIND-RESTART as requested here.
restart.lisp: active- restart
(constantly 'irrelevant)
:test- function (lambda (condition)
(declare (ignore condition))
activep) ))
(find- restart 'dynamically- active- restart) )) condition (make-condition 'condition))
(wrong- condition (make-condition 'condition)))
(with- condition- restarts required-condition (list actual-restart)
(let ((activep t))
(restart-bind ((dynamically-
(let ((actual-restart
;; Inactive because of condition-restarts associations.
(let ((required-
(print (find-restart actual-restart wrong-condition))))
;; Inactive because of test-function.
(setf activep nil)
(print (find-restart actual-restart)))))
ECL f584e5ad048d360 e955f6512402eee )
(Embeddable Common-Lisp) 12.12.1
(git:e725846659
$ ~/opt/ecl/bin/ecl -load restart.lisp
;;; Loading "/tmp/restart.lisp"
NIL
NIL
CLISP
GNU CLISP 2.49 (2010-07-07) (built on rothera.buildd [10.211.37.14])
$ clisp restart.lisp
NIL
NIL
CCL
Clozure Common Lisp Version 1.8-r15286M (LinuxX8632)!
$ ~/opt/ccl/lx86cl -l restart.lisp
NIL
NIL