I stumbled across a very weird bug (?) while I was developing an application in Allegro Common Lisp, v9.0 for Windows. I do not get the regular lisp errors, instead I get system errors encapsulated in a lisp condition. I managed to create a simple test-case to reproduce the error (it's very silly):
(defun lambda-producer ()
(labels ((producer-label (x y)
(if (> x y) (- x y) (- y x)))
(producer-label2 (x y)
(max (producer-label x 2) (producer-label y 3))))
(lambda (x)
(reduce (lambda (a b) (producer-label2 a b)) x))))
;; Get errors when calling:
(funcall (lambda-producer) (list 2 1 5 12))
I get a Stack overflow error for this test case every time I try it.
In my original code I got a plethora of errors, mostly segmentation faults, once a 'can not take car
of <..> because it is not listp' and once Allegro crashed.
When running the same snippet (or my original code) in CLisp, everything runs fine and the REPL gives an answer.
My question: Am I doing something wrong or illegal here, or is there a bug in Allegro CL? If so, can we determine what that bug is and what to do about it?
Some experimentation seems to indicate that the reduce
and double labels are essential in reproducing the error; replacing reduce
with a funcall
or if there is only one label does not give an error.
This is a compiler bug. Please contact Franz.
CG-USER(8): (disassemble (lambda-producer))
;; disassembly of #<Closure Template Function (:INTERNAL LAMBDA-PRODUCER 0)>
;; formals: X
;; closure vectors:
;; 0: #<Closure (LABELS LAMBDA-PRODUCER PRODUCER-LABEL2) @ #xdfdda7a>
;; 1: #<Function (LABELS LAMBDA-PRODUCER PRODUCER-LABEL)>
;; constant vector:
0: #<Closure Template Function (:INTERNAL (:INTERNAL LAMBDA-PRODUCER 0) 0)>
1: REDUCE
;; code start: #x21869018:
0: 55 pushl ebp
1: 89 e5 movl ebp,esp
3: 83 ec 38 subl esp,$56
6: 89 75 fc movl [ebp-4],esi
9: 89 5d e4 movl [ebp-28],ebx
12: 39 63 1a cmpl [ebx+26],esp
15: 76 03 jbe 20
17: ff 57 43 call *[edi+67] ; SYS::TRAP-STACK-OVFL
20: 83 f9 01 cmpl ecx,$1
23: 74 03 jz 28
25: ff 57 8b call *[edi-117] ; SYS::TRAP-WNAERR
28: 8b 5d 00 movl ebx,[ebp+0]
31: 8b 5b ec movl ebx,[ebx-20]
34: 8b 5b fa movl ebx,[ebx-6]
37: 80 7f cb 00 cmpb [edi-53],$0 ; SYS::C_INTERRUPT-PENDING
41: 74 03 jz 46
43: ff 57 87 call *[edi-121] ; SYS::TRAP-SIGNAL-HIT
46: 8b 56 12 movl edx,[esi+18] ; #<Closure Template Function (:INTERNAL (:INTERNAL LAMBDA-PRODUCER 0) 0)>
49: ff b7 43 fe pushl [edi-445] ; SYS::CLOSURE-HEADER
ff ff
55: 8f 45 d0 popl [ebp-48]
58: ff b7 47 fe pushl [edi-441] ; SYS::CLOSURE-ADDRESS
ff ff
64: 8f 45 d4 popl [ebp-44]
67: 89 55 d8 movl [ebp-40],edx
70: 89 5d dc movl [ebp-36],ebx
73: 8d 5d e2 leal ebx,[ebp-30]
76: 89 c2 movl edx,eax
78: 89 d8 movl eax,ebx
80: 8b 5e 16 movl ebx,[esi+22] ; REDUCE
83: ff 57 27 call *[edi+39] ; SYS::TRAMP-TWO
86: 89 7d f0 movl [ebp-16],edi
89: c9 leave
90: 8b 75 fc movl esi,[ebp-4]
93: c3 ret
;; disassembly of #<Closure Template Function (:INTERNAL (:INTERNAL LAMBDA-PRODUCER 0) 0)>
;; formals: A B
;; code start: #x2186ccc0:
0: 55 pushl ebp
1: 89 e5 movl ebp,esp
3: 83 ec 30 subl esp,$48
6: 89 75 fc movl [ebp-4],esi
9: 89 5d e4 movl [ebp-28],ebx
12: 39 63 1a cmpl [ebx+26],esp
15: 76 03 jbe 20
17: ff 57 43 call *[edi+67] ; SYS::TRAP-STACK-OVFL
20: 83 f9 02 cmpl ecx,$2
23: 74 03 jz 28
25: ff 57 8b call *[edi-117] ; SYS::TRAP-WNAERR
28: 8b 5d 00 movl ebx,[ebp+0]
31: 8b 5b ec movl ebx,[ebx-20]
34: 8b 5b fa movl ebx,[ebx-6]
37: 80 7f cb 00 cmpb [edi-53],$0 ; SYS::C_INTERRUPT-PENDING
41: 74 03 jz 46
43: ff 57 87 call *[edi-121] ; SYS::TRAP-SIGNAL-HIT
46: ff 73 f6 pushl [ebx-10]
49: 8f 45 dc popl [ebp-36] ; EXCL::|local-0|
52: 8b 75 dc movl esi,[ebp-36] ; EXCL::|local-0|
55: 89 fb movl ebx,edi
57: b9 02 00 00 movl ecx,$2
00
62: ff 57 23 call *[edi+35] ; SYS::FUNCALL-TRAMP
65: 89 7d f0 movl [ebp-16],edi
68: c9 leave
69: 8b 75 fc movl esi,[ebp-4]
72: c3 ret
73: 90 nop
At 49 and 52 of the second closure template, you can see that it's feeding itself to sys::funcall-tramp
1 with 2 arguments2.
sys::funcall-tramp
is an internal that I think might perform or otherwise allow tail calls.
According to ecx
at 57, since ecx
is what seems to be used to check if the internal sys::trap-wnaerr
is called; I suppose wna
stands for wrong number of arguments.