set-pprint-dispatch on nonexistent type causes maximum error depth excession

Bug #1429520 reported by James Kalenius
6
This bug affects 1 person
Affects Status Importance Assigned to Milestone
SBCL
Fix Released
Undecided
Unassigned

Bug Description

(set-pprint-dispatch 'foo 'bar)

Help! 11 nested errors. SB-KERNEL:*MAXIMUM-ERROR-DEPTH* exceeded.
Backtrace for: #<SB-THREAD:THREAD "repl-thread" RUNNING {10045000B3}>
Help! 11 nested errors. SB-KERNEL:*MAXIMUM-ERROR-DEPTH* exceeded.
Backtrace for: #<SB-THREAD:THREAD "repl-thread" RUNNING {10045000B3}>
Help! 11 nested errors. SB-KERNEL:*MAXIMUM-ERROR-DEPTH* exceeded.
Backtrace for: #<SB-THREAD:THREAD "repl-thread" RUNNING {10045000B3}>
Help! 11 nested errors. SB-KERNEL:*MAXIMUM-ERROR-DEPTH* exceeded.
Backtrace for: #<SB-THREAD:THREAD "Swank Sentinel" RUNNING {100352A1D3}>

This does not happen outside of SLIME, probably because of SLIME's printer settings.

What seems to be happening is that set-pprint-dispatch computes a function to run typep, and actually calling that function causes an error; so pretty printing anything at all after set-pprint-dispatch puts you in a pit of recursive errors. This results in difficult behavior like my capture attempts breaking just as badly (ignore-errors, handler-bind, binding *debugger-hook*, that sort of thing). |3b| deduced that if you just set *print-pretty* to NIL before the bad set-pprint-dispatch you get no error, but later pprinting of anything causes recursive death.

In any case, more desirable behavior would be pprint just giving a warning that a given type tester errored and continuing on its way. Probably debatable.

In 1.2.6 and 1.2.8 (says axion).

uname -a
Linux Syadavaktavyah 3.18.6-1-ARCH #1 SMP PREEMPT Sat Feb 7 08:44:05 CET 2015 x86_64 GNU/Linux

*features*
(:SWANK :QUICKLISP :SB-BSD-SOCKETS-ADDRINFO :ASDF-PACKAGE-SYSTEM :ASDF3.1
 :ASDF3 :ASDF2 :ASDF :OS-UNIX :NON-BASE-CHARS-EXIST-P :ASDF-UNICODE
 :ALIEN-CALLBACKS :ANSI-CL :ASH-RIGHT-VOPS :C-STACK-IS-CONTROL-STACK
 :COMMON-LISP :COMPARE-AND-SWAP-VOPS :COMPLEX-FLOAT-VOPS :CYCLE-COUNTER :ELF
 :FLOAT-EQL-VOPS :GENCGC :IEEE-FLOATING-POINT :INLINE-CONSTANTS
 :INTERLEAVED-RAW-SLOTS :LINKAGE-TABLE :LINUX :LITTLE-ENDIAN
 :MEMORY-BARRIER-VOPS :MULTIPLY-HIGH-VOPS :OS-PROVIDES-BLKSIZE-T
 :OS-PROVIDES-DLADDR :OS-PROVIDES-DLOPEN :OS-PROVIDES-GETPROTOBY-R
 :OS-PROVIDES-POLL :OS-PROVIDES-PUTWC :OS-PROVIDES-SUSECONDS-T
 :PACKAGE-LOCAL-NICKNAMES :RAW-INSTANCE-INIT-VOPS :SB-CORE-COMPRESSION :SB-DOC
 :SB-EVAL :SB-FUTEX :SB-LDB :SB-PACKAGE-LOCKS :SB-SIMD-PACK
 :SB-SOURCE-LOCATIONS :SB-TEST :SB-THREAD :SB-UNICODE :SBCL
 :STACK-ALLOCATABLE-CLOSURES :STACK-ALLOCATABLE-FIXED-OBJECTS
 :STACK-ALLOCATABLE-LISTS :STACK-ALLOCATABLE-VECTORS
 :STACK-GROWS-DOWNWARD-NOT-UPWARD :SYMBOL-INFO-VOPS :UNIX
 :UNWIND-TO-FRAME-AND-CALL-VOP :X86-64)

Revision history for this message
Attila Lendvai (attila-lendvai) wrote :
Download full text (97.2 KiB)

FTR, i have an old github pull request and/or patch here on lp that attempts to print a backtrace in such cases (https://github.com/sbcl/sbcl/pull/3), and in general try to provide more information for debugging, because i had many headaches with such errors. this is what it prints into the inferior lisp buffer (looks like it's multiple threads printing in parallel):

Help! 11 nested errors. SB-KERNEL:*MAXIMUM-ERROR-DEPTH* exceeded.
Help! 11 nested errors. SB-KERNEL:*MAXIMUM-ERROR-DEPTH* exceeded.
Backtrace for:
#<Backtrace for: #<SB-THREADSB-THREAD:THREAD:THREAD "repl-thread"S ank SenRUNNINGtinel"1007840033}>RUNNING
100A3E21B3}>
0: ((LAMBDA NIL :IN SB-DEBUG::FUNCALL-WITH-DEBUG-IO-SYNTAX))
0: ((LAMBDA NIL :IN SB-DEBUG::FUNCALL-WITH-DEBUG-IO-SYNTAX))1: (SB-IMPL::CALL-WITH-SANE-IO-SYNTAX #<CLOSURE (LAMBDA NIL :IN SB-DEBUG::FUNCALL-WITH-DEBUG-IO-SYNTAX) {1008EA2FEB}>)
1: (SB-IMPL::CALL-WITH-SANE-IO-SY2: (SB-IMPL::%WITH-STANDARD-IO-SYNTAX #<CLOSURE (LAMBDA NIL :IN SB-DEBUG::FUNCALL-WITH-DEBUG-IO-SYNTAX) {1008EA2FBB}>)
2: (SB-IMPL::%WITH-STANDARD-IO-SYNTAX #<CLOSURE (LAMBDA NIL :IN SB-DEBUG::FUNCALL-WITH-DEBUG-IO-SYNTAX) {1008E42F3B}>)
3: (PRINT-BACKTRACE :STREAM #<SYNONYM-STREAM :SYMBOL SB-SYS:*TTY* {1008EA2D83}> :START 0 :FROM :DEBUGGER-FRAME :COUNT NIL :PRINT-THREAD T :PRINT-FRAME-SOURCE NIL :METHOD-FRAME-STYLE NIL :EMERGENCY-BEST-EFFORT T)
3: (PRINT-BACKTRACE :STREAM #<SYNONYM-STREAM :SYMBOL SB-SYS:*TTY* {1008E42D03}> :START 0 :FROM :DEBUGGER-FRAME :COUNT NIL :PRINT-THREAD T :PRINT-FRAME-SOURCE NIL :METHOD-FRAME-STYLE NIL :EMERGENCY-BEST-EFFORT T)
4: ((FLET SB-IMPL::TRY-TO-INVOKE-DEBUGGER :IN SB-IMPL::ERROR-ERROR))
4: ((FLET SB-IMPL::TRY-TO-INVOKE-DEBUGGER :IN SB-IMPL::ERROR-ERROR))
5: ((LAMBDA NIL :IN SB-IMPL::ERROR-ERROR))
5: ((LAMBDA NIL :IN SB-IMPL::ERROR-ERROR))
6: (SB-IMPL::%WITH-STANDARD-IO-SYNTAX #<CLOSURE (LAMBDA NIL :IN SB-IMPL::ERROR-ERROR) {1008EA1B2B}>)
6: (SB-IMPL::%WITH-STANDARD-IO-SYNTAX #<CLOSURE (LAMBDA NIL :IN SB-IMPL::ERROR-ERROR) {1008E41B2B}>)
7: (SB-IMPL::ERROR-ERROR "Help! " 11 " nested errors. " "SB-KERNEL:*MAXIMUM-ERROR-DEPTH* exceeded.")
7: (SB-IMPL::ERROR-ERROR "Help! " 11 " nested errors. " "SB-KERNEL:*MAXIMUM-ERROR-DEPTH* exceeded.")8: (SB-IMPL::INFINITE-ERROR-PROTECTOR)
8: (SB-IMPL::INFINITE-ERROR-PROTECTOR)
9: (ERROR #<SB-SYS:DEADLINE-TIMEOUT {1008EA1AA3}>)
9: (ERROR #<SB-SYS:DEADLINE-TIMEOUT {1008E41AA3}>)
10: (SB-SYS:SIGNAL-DEADLINE)
10: (SB-SYS:SIGNAL-DEADLINE)
11: ((FLET #:CLEANUP-FUN-563 :IN SB-THREAD:CONDITION-WAIT)) [cleanup]
11: ((FLET #:CLEANUP-FUN-563 :IN SB-THREAD:CONDITION-WAIT)) [cleanup]
12: ((FLET #:WITHOUT-INTERRUPTS-BODY-558 :IN SB-THREAD:CONDITION-WAIT))

13: (SB-THREAD:CONDITION-WAIT #<SB-THREAD:WAITQUEUE {1007848E53}> #<SB-THREAD:MUTEX owner: #<SB-THREAD:THREAD "repl-thread" RUNNING {1007840033}> {1007848E23}> :TIMEOUT NIL)13: (SB-THREAD:CONDITION-WAIT #<SB-THREAD:WAITQUEUE {100A3DF563}> #<SB-THREAD:MUTEX owner: #<SB-THREAD:THREAD "Swank Sentinel" RUNNING {100A3E21B3}> {100A3DF533}> :TIMEOUT NIL)
14: ((FLET #:FORM-FUN-2872 :IN SWANK/SBCL::CONDITION-TIMED-WAIT))14: ((FLET #:FORM-FUN-2872 :IN SWANK/SBCL::CONDITION-TIMED-WAIT))
15: (SWANK/SBCL::CONDITIO15: (SWANK/SBCL::CONDITION-TIMED-WAIT #<...

Revision history for this message
Douglas Katzman (dougk) wrote :

It should be at least a warning, if not an error, when the type can't be parsed at the time of call to set-pprint-dispatch.

If it's "only" a warning, we could do something extremely clever by having dispatch entries marked as 'disabled' so that they allow installation but silently do nothing. Subsequent changes to the type system (via defstruct, defclass, deftype) can trigger re-evaluation of the type constraints on pprint dispatch entries.

But really I think we should just refuse to install the dispatch entry, because while it is not undefined per se, it is pretty clear that it will lead to prohibited behavior: TYPEP says "The consequences are undefined if the type-specifier is not a type specifier."
And the behavior of the pprint-dispatch is more-or-less to invoke TYPEP although it doesn't say that in those words.

Revision history for this message
Christophe Rhodes (csr21-cantab) wrote : Re: [Bug 1429520] Re: set-pprint-dispatch on nonexistent type causes maximum error depth excession

Douglas Katzman <email address hidden> writes:

> But really I think we should just refuse to install the dispatch
> entry, because while it is not undefined per se, it is pretty clear
> that it will lead to prohibited behavior: TYPEP says "The consequences
> are undefined if the type-specifier is not a type specifier." And the
> behavior of the pprint-dispatch is more-or-less to invoke TYPEP
> although it doesn't say that in those words.

I could live with that, but we still need to handle errors from running
TYPEP, because of the possibility of users handing us (SATISFIES ...)
types where the predicate signals an error.

Christophe

Revision history for this message
Christophe Rhodes (csr21-cantab) wrote :

Douglas Katzman <email address hidden> writes:

> But really I think we should just refuse to install the dispatch
> entry, because while it is not undefined per se, it is pretty clear
> that it will lead to prohibited behavior: TYPEP says "The consequences
> are undefined if the type-specifier is not a type specifier." And the
> behavior of the pprint-dispatch is more-or-less to invoke TYPEP
> although it doesn't say that in those words.

I think we still need to handle errors from within pprint-dispatch,
though, because users can install dispatch entries using (SATISFIES ...)
types where the predicate can (inadvisedly) signal an error.

Christophe

Revision history for this message
Douglas Katzman (dougk) wrote :

Afaict, we do handle errors sanely. There is a default sane pprint-dispatch table that the debugger uses.
This is only a problem in Slime.

* (defun bork (x) x (error "Oh oh"))
BORK
* (set-pprint-dispatch '(satisfies bork) (lambda (stream obj) (format stream "[~A]" (type-of obj))))
debugger invoked on a SIMPLE-ERROR in thread
#<THREAD "main thread" RUNNING {1002D8E9F3}>:
  Oh oh

Type HELP for debugger help, or (SB-EXT:EXIT) to exit from SBCL.

restarts (invokable by number or by possibly-abbreviated name):
  0: [ABORT] Exit debugger, returning to top level.

(BORK #<unavailable argument>)
0] *print-pretty*
T
0] (make-hash-table)
#<HASH-TABLE :TEST EQL :COUNT 0 {1002E69283}>
0] (make-array 4)
(make-array 4)
#(0 0 0 0)

Revision history for this message
Attila Lendvai (attila-lendvai) wrote :

i've looked into hardening slime some more to deal with this, but it's dubious whether it's worth it.

basically pretty much everything printing-related gets broken after that set-pprint-dispatch call. slime already tries to deal with nested errors while debugging, but not all code-paths are sealed, and its debugger is using formatted printing all around.

Revision history for this message
Alastair Bridgewater (alastair-bridgewater) wrote :
Download full text (3.6 KiB)

Dare I suggest that a suitably-nested error in the SLIME debugger might
invoke WITH-STANDARD-IO-SYNTAX or similar?

On Mon, Mar 9, 2015 at 10:02 AM, Attila Lendvai <email address hidden>
wrote:

> i've looked into hardening slime some more to deal with this, but it's
> dubious whether it's worth it.
>
> basically pretty much everything printing-related gets broken after that
> set-pprint-dispatch call. slime already tries to deal with nested errors
> while debugging, but not all code-paths are sealed, and its debugger is
> using formatted printing all around.
>
> --
> You received this bug notification because you are subscribed to SBCL.
> https://bugs.launchpad.net/bugs/1429520
>
> Title:
> set-pprint-dispatch on nonexistent type causes maximum error depth
> excession
>
> Status in Steel Bank Common Lisp:
> New
>
> Bug description:
> (set-pprint-dispatch 'foo 'bar)
>
> Help! 11 nested errors. SB-KERNEL:*MAXIMUM-ERROR-DEPTH* exceeded.
> Backtrace for: #<SB-THREAD:THREAD "repl-thread" RUNNING {10045000B3}>
> Help! 11 nested errors. SB-KERNEL:*MAXIMUM-ERROR-DEPTH* exceeded.
> Backtrace for: #<SB-THREAD:THREAD "repl-thread" RUNNING {10045000B3}>
> Help! 11 nested errors. SB-KERNEL:*MAXIMUM-ERROR-DEPTH* exceeded.
> Backtrace for: #<SB-THREAD:THREAD "repl-thread" RUNNING {10045000B3}>
> Help! 11 nested errors. SB-KERNEL:*MAXIMUM-ERROR-DEPTH* exceeded.
> Backtrace for: #<SB-THREAD:THREAD "Swank Sentinel" RUNNING {100352A1D3}>
>
> This does not happen outside of SLIME, probably because of SLIME's
> printer settings.
>
> What seems to be happening is that set-pprint-dispatch computes a
> function to run typep, and actually calling that function causes an
> error; so pretty printing anything at all after set-pprint-dispatch
> puts you in a pit of recursive errors. This results in difficult
> behavior like my capture attempts breaking just as badly (ignore-
> errors, handler-bind, binding *debugger-hook*, that sort of thing).
> |3b| deduced that if you just set *print-pretty* to NIL before the bad
> set-pprint-dispatch you get no error, but later pprinting of anything
> causes recursive death.
>
> In any case, more desirable behavior would be pprint just giving a
> warning that a given type tester errored and continuing on its way.
> Probably debatable.
>
> In 1.2.6 and 1.2.8 (says axion).
>
> uname -a
> Linux Syadavaktavyah 3.18.6-1-ARCH #1 SMP PREEMPT Sat Feb 7 08:44:05 CET
> 2015 x86_64 GNU/Linux
>
> *features*
> (:SWANK :QUICKLISP :SB-BSD-SOCKETS-ADDRINFO :ASDF-PACKAGE-SYSTEM :ASDF3.1
> :ASDF3 :ASDF2 :ASDF :OS-UNIX :NON-BASE-CHARS-EXIST-P :ASDF-UNICODE
> :ALIEN-CALLBACKS :ANSI-CL :ASH-RIGHT-VOPS :C-STACK-IS-CONTROL-STACK
> :COMMON-LISP :COMPARE-AND-SWAP-VOPS :COMPLEX-FLOAT-VOPS :CYCLE-COUNTER
> :ELF
> :FLOAT-EQL-VOPS :GENCGC :IEEE-FLOATING-POINT :INLINE-CONSTANTS
> :INTERLEAVED-RAW-SLOTS :LINKAGE-TABLE :LINUX :LITTLE-ENDIAN
> :MEMORY-BARRIER-VOPS :MULTIPLY-HIGH-VOPS :OS-PROVIDES-BLKSIZE-T
> :OS-PROVIDES-DLADDR :OS-PROVIDES-DLOPEN :OS-PROVIDES-GETPROTOBY-R
> :OS-PROVIDES-POLL :OS-PROVIDES-PUTWC :OS-PROVIDES-SUSECONDS-T
> :PACKAGE-LOCAL-NICKNAMES :RAW-INSTANC...

Read more...

Revision history for this message
Attila Lendvai (attila-lendvai) wrote :

FTR, i created an issue for slime and linked to a commit that alleviates the immediate problem.

details are availabe here: https://github.com/slime/slime/issues/236

Revision history for this message
Douglas Katzman (dougk) wrote :

I implemented deferred compilation for unknown types -
http://sourceforge.net/p/sbcl/sbcl/ci/172a24e19c02ab4ed4cc46cddd0eb8f85a6cf19f/

Changed in sbcl:
status: New → Fix Committed
Stas Boukarev (stassats)
Changed in sbcl:
status: Fix Committed → Fix Released
To post a comment you must log in.
This report contains Public information  
Everyone can see this information.

Other bug subscribers

Remote bug watches

Bug watches keep track of this bug in other bug trackers.