使用 lambda 和“reduce”捕获标签时出现奇怪的非 lisp 错误
Weird non-lisp errors with capturing labels with a lambda and `reduce`
我在为 Windows 使用 Allegro Common Lisp v9.0 开发应用程序时偶然发现了一个非常奇怪的错误 (?)。我没有得到常规的 lisp 错误,而是得到了封装在 lisp 条件中的系统错误。我设法创建了一个简单的测试用例来重现错误(这很愚蠢):
(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))
我每次尝试此测试用例时都会收到堆栈溢出错误。
在我的原始代码中,我遇到了很多错误,主要是分段错误,一次是 'can not take car
of <..> because it is not listp',一次是 Allegro 崩溃。
当 运行 在 CLisp 中使用相同的代码片段(或我的原始代码)时,一切运行正常,REPL 给出了答案。
我的问题:我是不是做错了什么或违法了,还是Allegro CL有bug?如果是这样,我们能否确定该错误是什么以及如何处理它?
一些实验似乎表明 reduce
和双标签对于重现错误至关重要;将 reduce
替换为 funcall
或者如果只有一个标签则不会出现错误。
这是一个编译器错误。请联系 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,
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,
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],[=10=] ; 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,
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,
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],[=10=] ; 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,
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
在第二个闭包模板的 49 和 52 处,您可以看到它正在使用 2 个参数 sys::funcall-tramp
12.
sys::funcall-tramp
是我认为可能执行或以其他方式允许尾调用的内部。
根据 57 处的 ecx
,因为 ecx
似乎用于检查是否调用了内部 sys::trap-wnaerr
;我想 wna
代表 wrong nnumber of arguments.
我在为 Windows 使用 Allegro Common Lisp v9.0 开发应用程序时偶然发现了一个非常奇怪的错误 (?)。我没有得到常规的 lisp 错误,而是得到了封装在 lisp 条件中的系统错误。我设法创建了一个简单的测试用例来重现错误(这很愚蠢):
(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))
我每次尝试此测试用例时都会收到堆栈溢出错误。
在我的原始代码中,我遇到了很多错误,主要是分段错误,一次是 'can not take car
of <..> because it is not listp',一次是 Allegro 崩溃。
当 运行 在 CLisp 中使用相同的代码片段(或我的原始代码)时,一切运行正常,REPL 给出了答案。
我的问题:我是不是做错了什么或违法了,还是Allegro CL有bug?如果是这样,我们能否确定该错误是什么以及如何处理它?
一些实验似乎表明 reduce
和双标签对于重现错误至关重要;将 reduce
替换为 funcall
或者如果只有一个标签则不会出现错误。
这是一个编译器错误。请联系 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,
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,
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],[=10=] ; 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,
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,
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],[=10=] ; 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,
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
在第二个闭包模板的 49 和 52 处,您可以看到它正在使用 2 个参数 sys::funcall-tramp
12.
sys::funcall-tramp
是我认为可能执行或以其他方式允许尾调用的内部。根据 57 处的
ecx
,因为ecx
似乎用于检查是否调用了内部sys::trap-wnaerr
;我想wna
代表 wrong nnumber of arguments.