Clisp “Program stack overflow. RESET” on a (cadr).

2019-09-13 15:40发布

问题:

This question already has an answer here:

  • Unusual stack overflow when inserting nodes in binary tree 1 answer

I'm (still) porting code from Franz Lisp to Common LISP. Now I seem to have pushed the interpreter into a strange corner where it blows up.

[11]> (setq fff (cadr contextstack))    
*** - Program stack overflow. RESET

Now how can that cause a stack overflow? Where's the recursion?

I can take the length OK:

[12]> (length contextstack)
79

describe works. This is just the beginning of long "describe" output.

[13]> (describe (cadr contextstack))

(# . #1=#) is a cons.

 #<FUNCTION POPPATTERN (NODE) (DECLARE (SYSTEM::IN-DEFUN POPPATTERN)) (BLOCK POPPATTERN (MAPONE # #) (XEPATTERN NODE #))> is an interpreted
 function.
 Argument list: (NODE)

 #1=# is a structure of type ENODE.
 Slots:
   EROOT           =
  #1=#S(ENODE :EROOT #1# :EQCLASS #1# :ESUCCESSORS ALLTRUE! :ESLENGTH NIL :EPREDECESSORS NIL :ECONGRUENT NIL :EDEMON NIL :EMERGEDEMON NIL
        :EPATTERN

;;; much more

But almost anything else applied to contextstack blows up with the stack overflow message.

The structure ENODE contains links to other ENODE items, and there is circularity which could make some code loop. But cadr? How is that even possible?

The original code used "hunks", a MacLISP feature from the 1970s. I converted it to use Common LISP structs, and may have broken something.

This is all running interpretive; I haven't compiled anything. Safety level is the default. I tried adding (proclaim '(optimize (safety 3))) to force more checking, but it didn't change anything.

If you want to reproduce this, download the code in

https://github.com/John-Nagle/pasv/tree/master/src/CPC4

start "clisp", do (load 'setup), and then start looking at contextstack. Whatever is breaking is happening early, as the program is initializing.

回答1:

How you got the error

Chances are, the error is in printing, not cadr. You can verify it by doing

(progn (cadr contextstack) nil)

which should work just fine.

If it still blows up, you should check if cadr raises an exception (and then the error message would contain a circular object and blow up):

(and (consp contextstack)
     (consp (cdr contextstack)))

How to avoid the error

CLISP FAQ says:

You will always get a stack overflow when you try to print a circular object (LIST, STRUCTURE-OBJECT, VECTOR etc) and *PRINT-CIRCLE* is NIL. Just set *PRINT-CIRCLE* to T.

Note that this is not CLISP-specific, you should get the same error with any ANSI Common Lisp when *print-circle* is nil.

In your specific case, look closely at the output of (describe (cadr contextstack)):

(# . #1=#) is a cons.

This #= notation is used by the printer to avoid stack overflows when printing circular objects.

PS. You now owe me 10 zorkmids :-)