1 ;;;; This file is for testing debugging functionality, using
2 ;;;; test machinery which might have side effects (e.g.
5 ;;;; This software is part of the SBCL system. See the README file for
8 ;;;; While most of SBCL is derived from the CMU CL system, the test
9 ;;;; files (like this one) were written from scratch after the fork
12 ;;;; This software is in the public domain and is provided with
13 ;;;; absolutely no warranty. See the COPYING and CREDITS files for
14 ;;;; more information.
16 (cl:in-package
:cl-user
)
18 ;;; The debugger doesn't have any native knowledge of the interpreter
19 (when (eq sb-ext
:*evaluator-mode
* :interpret
)
20 (invoke-restart 'run-tests
::skip-file
))
23 (with-test (:name
:legal-bpt-lra-object
)
24 (sb-int:binding
* ((code (sb-kernel:fun-code-header
#'read
))
25 (sap (sb-sys:sap
+ (sb-kernel:code-instructions code
) 13)) ; random
26 ((bpt-sap bpt-code-obj
) (sb-di::make-bpt-lra sap
)))
27 (declare (ignore bpt-sap
))
28 ;; This was causing heap corruption
29 (assert (zerop (sb-kernel:code-jump-table-words bpt-code-obj
)))))
32 ;;;; Check that we get debug arglists right.
34 (defun zoop (zeep &key beep
)
35 (declare (ignore zeep beep
) (special blurp
))
37 (assert (equal (sb-kernel:%fun-lambda-list
#'zoop
) '(zeep &key beep
)))
39 ;;; Check some predefined functions too.
41 ;;; (We don't know exactly what the arguments are, e.g. the first
42 ;;; argument of PRINT might be SB-IMPL::OBJECT or SB-KERNEL::OBJ or
43 ;;; whatever. But we do know the general structure that a correct
44 ;;; answer should have, so we can safely do a lot of checks.)
45 (with-test (:name
:predefined-functions-1
)
46 (destructuring-bind (object-sym andoptional-sym stream-sym
)
47 (sb-kernel:%fun-lambda-list
#'print
)
48 (assert (symbolp object-sym
))
49 (assert (eql andoptional-sym
'&optional
))
50 (assert (symbolp stream-sym
))))
52 (with-test (:name
:predefined-functions-2
)
53 (destructuring-bind (dest-sym control-sym andrest-sym format-args-sym
)
54 (sb-kernel:%fun-lambda-list
#'format
)
55 (assert (symbolp dest-sym
))
56 (assert (symbolp control-sym
))
57 (assert (eql andrest-sym
'&rest
))
58 (assert (symbolp format-args-sym
))))
62 (defmacro with-traced-function
((name &rest options
) &body body
)
63 `(with-output-to-string (*trace-output
*)
66 (trace ,name
,@options
)
68 (ignore-errors (untrace ,name
)))))
70 (defun call-collecting-traces (fn trace-arguments
)
72 (flet ((collect (depth what when frame values
)
73 (declare (ignore frame
))
74 (flet ((ensure-readable (x)
76 (function (sb-impl::%fun-name x
))
77 (sb-debug::unprintable-object
78 (sb-debug::unprintable-object-string x
))
81 (ensure-readable what
)
83 (mapcar #'ensure-readable values
))
86 (let ((sb-debug:*trace-report-default
* #'collect
))
87 (eval `(trace ,@trace-arguments
))
89 (ignore-errors (untrace))
90 (assert (null (trace)))))
93 (defmacro collecting-traces
((&rest trace-arguments
) &body body
)
94 `(call-collecting-traces (lambda () ,@body
) ',trace-arguments
))
96 (defun trace-this (&optional arg
)
97 (declare (ignore arg
))
100 (defun mv-trace-this (&optional arg
)
102 (2 (values 'ok
"hi"))
103 (3 (values 'ok
"hi" :foo
))
104 (4 (values 'ok
"hi" :foo
:bar
))))
106 (defun trace-fact (n)
109 (* n
(trace-fact (1- n
)))))
111 (with-test (:name
(trace :simple
))
112 (let ((output (with-traced-function (trace-this)
113 (assert (eq 'ok
(trace-this))))))
114 (assert (search "TRACE-THIS" output
))
115 (assert (search "returned OK" output
))))
117 (with-test (:name
(trace :print-readably
))
118 (let ((output (with-traced-function (trace-this)
119 (let ((*print-readably
* t
))
120 (assert (eq 'ok
(trace-this (sb-int:make-unprintable-object
"foo"))))))))
121 (assert (search "TRACE-THIS" output
))
122 (assert (search "foo" output
))
123 (assert (search "returned OK" output
))))
125 ;;; The following should not work:
127 ;;; (DEFMACRO M (&REST r) (format t "M invoked: ~S~%" r))
128 ;;; (ENCAPSULATE 'M 'foo (lambda (f &rest r) (format t "encapsulation: ~S ~S~%" f r)))
130 ;;; If (ENCAPSULATE) were permitted, M's guard trampoline would be replaced by the
131 ;;; encapsulation which is not meaningful. Most uses of the macro M will NOT invoke
132 ;;; the encapsulation since we don't store macro functions in the symbol-function location.
133 ;;; Only a consumer of M being accidentally compiled first and resolving M to an
134 ;;; fdefinition would see the encapulation. That should just be an error.
135 (with-test (:name
:no-macro-encapsulation
)
136 (assert-error (sb-int:encapsulate
'cond
'tryme
137 (lambda (f &rest stuff
)
138 (declare (ignore f stuff
))))))
140 (defparameter *breakpoint-tracing-expectations
*
141 '(:fails-on
(or :arm
:arm64
)
142 :broken-on
(or :freebsd
:ppc
:ppc64
)))
145 (with-test (:name
(trace :encapsulate nil
)
146 .
#.
*breakpoint-tracing-expectations
*)
147 (let ((output (with-traced-function (trace-this :encapsulate nil
)
148 (assert (eq 'ok
(trace-this))))))
149 (assert (search "TRACE-THIS" output
))
150 (assert (search "returned OK" output
))))
152 (with-test (:name
:breakpoint-trace-multival .
#.
*breakpoint-tracing-expectations
*)
153 (let ((output (with-traced-function (mv-trace-this :encapsulate nil
)
154 (assert (equal (multiple-value-list (mv-trace-this 2))
156 (assert (search "MV-TRACE-THIS" output
))
157 (assert (search "returned OK" output
)))
158 (let ((output (with-traced-function (mv-trace-this :encapsulate nil
)
159 (assert (equal (multiple-value-list (mv-trace-this 3))
161 (assert (search "MV-TRACE-THIS" output
))
162 (assert (search "returned OK" output
)))
163 (let ((output (with-traced-function (mv-trace-this :encapsulate nil
)
164 (assert (equal (multiple-value-list (mv-trace-this 4))
165 '(ok "hi" :foo
:bar
))))))
166 (assert (search "MV-TRACE-THIS" output
))
167 (assert (search "returned OK" output
))))
169 (with-test (:name
(trace :encapsulate nil
:recursive
)
170 .
#.
*breakpoint-tracing-expectations
*)
171 (let ((output (with-traced-function (trace-fact :encapsulate nil
)
172 (assert (= 120 (trace-fact 5))))))
173 (assert (search "TRACE-FACT" output
))
174 (assert (search "returned 1" output
))
175 (assert (search "returned 120" output
))))
177 (defun trace-and-fmakunbound-this (x)
180 (with-test (:name
(trace fmakunbound
:bug-667657
))
181 (trace trace-and-fmakunbound-this
)
182 (fmakunbound 'trace-and-fmakunbound-this
)
183 ;; FIXME: this generates a pointless warning that we can't untrace a formerly
184 ;; traced function. Function redefinition knows to untrace/re-trace because of
185 ;; the setf-fdefn hook. fmakunbound can do something similar - drop the trace.
187 (assert (not (trace))))
189 (with-test (:name
(trace :report nil
:smoke
))
190 (let ((output (with-traced-function (trace-this :report nil
)
191 (assert (eq 'ok
(trace-this))))))
192 (assert (sequence:emptyp output
))))
194 (with-test (:name
(trace :report nil
:print
))
195 (let ((output (with-traced-function
196 (trace-fact :report nil
:print
(sb-debug:arg
0))
197 (assert (eq '2 (trace-fact 2))))))
198 (assert (string= output
(format nil
"2~@
202 (defvar *collected-traces
*)
203 (defun custom-trace-report (depth what when frame values
)
204 (push (list* depth what when
(sb-debug::frame-p frame
) values
)
207 (with-test (:name
(trace :custom-report
))
208 (let ((*collected-traces
* nil
))
209 (let ((output (with-traced-function (trace-fact :report custom-trace-report
)
211 (assert (zerop (length output
)))
212 (assert (equalp (reverse *collected-traces
*)
213 '((0 trace-fact
:enter t
2)
214 (1 trace-fact
:enter t
1)
215 (2 trace-fact
:enter t
0)
216 (2 trace-fact
:exit t
1)
217 (1 trace-fact
:exit t
1)
218 (0 trace-fact
:exit t
2)))))))
220 (with-test (:name
(trace :anonymous
) .
#.
*breakpoint-tracing-expectations
*)
221 (assert (equalp (call-collecting-traces
224 `(:function
,#'trace-fact
:condition
(plusp (sb-debug:arg
0))))
225 '((0 trace-fact
:enter
1)
226 (0 trace-fact
:exit
1)))))
228 (defgeneric trace-gf
(x)
229 (:method
((x float
)) (+ x
(call-next-method)))
230 (:method
:before
((x float
)) 'bf
)
231 (:method
:around
((x float
)) (call-next-method))
232 (:method
:after
((x float
)) 'af
)
233 (:method
((x number
)) (+ x
(call-next-method)))
234 (:method
:before
((x number
)) 'bn
)
235 (:method
:around
((x number
)) (call-next-method))
236 (:method
:after
((x number
)) 'an
)
237 (:method
((x (eql 21.0))) (call-next-method))
240 (with-test (:name
(trace :all-methods
))
241 (assert (equal (collecting-traces (trace-gf :methods t
)
243 '((0 trace-gf
:enter
21.0)
244 (1 (method trace-gf
:around
(float)) :enter
21.0)
245 (2 (method trace-gf
:around
(number)) :enter
21.0)
246 (3 (sb-pcl::combined-method trace-gf
) :enter
21.0)
247 (4 (method trace-gf
:before
(float)) :enter
21.0)
248 (4 (method trace-gf
:before
(float)) :exit bf
)
249 (4 (method trace-gf
:before
(number)) :enter
21.0)
250 (4 (method trace-gf
:before
(number)) :exit bn
)
251 (4 (method trace-gf
((eql 21.0))) :enter
21.0)
252 (5 (method trace-gf
(float)) :enter
21.0)
253 (6 (method trace-gf
(number)) :enter
21.0)
254 (7 (method trace-gf
(t)) :enter
21.0)
255 (7 (method trace-gf
(t)) :exit
0)
256 (6 (method trace-gf
(number)) :exit
21.0)
257 (5 (method trace-gf
(float)) :exit
42.0)
258 (4 (method trace-gf
((eql 21.0))) :exit
42.0)
259 (4 (method trace-gf
:after
(number)) :enter
21.0)
260 (4 (method trace-gf
:after
(number)) :exit an
)
261 (4 (method trace-gf
:after
(float)) :enter
21.0)
262 (4 (method trace-gf
:after
(float)) :exit af
)
263 (3 (sb-pcl::combined-method trace-gf
) :exit
42.0)
264 (2 (method trace-gf
:around
(number)) :exit
42.0)
265 (1 (method trace-gf
:around
(float)) :exit
42.0)
266 (0 trace-gf
:exit
42.0)))))
268 (with-test (:name
(trace :methods
))
269 (assert (equal (collecting-traces ((method trace-gf
:after
(float))
270 (method trace-gf
:around
(number))
271 (method trace-gf
(t)))
273 '((0 (method trace-gf
:around
(number)) :enter
42.0)
274 (1 (method trace-gf
(t)) :enter
42.0)
275 (1 (method trace-gf
(t)) :exit
0)
276 (1 (method trace-gf
:after
(float)) :enter
42.0)
277 (1 (method trace-gf
:after
(float)) :exit af
)
278 (0 (method trace-gf
:around
(number)) :exit
84.0)))))
280 (with-test (:name
(trace :methods
:encapsulate nil
)
281 .
#.
*breakpoint-tracing-expectations
*)
282 (assert (equal (collecting-traces (:encapsulate nil
283 (method trace-gf
:after
(float))
284 (method trace-gf
:around
(number))
285 (method trace-gf
(t)))
287 '((0 (sb-pcl::fast-method trace-gf
:around
(number)) :enter
42.0)
288 (1 (sb-pcl::fast-method trace-gf
(t)) :enter
"unused argument")
289 (1 (sb-pcl::fast-method trace-gf
(t)) :exit
0)
290 (1 (sb-pcl::fast-method trace-gf
:after
(float)) :enter
"unused argument")
291 (1 (sb-pcl::fast-method trace-gf
:after
(float)) :exit af
)
292 (0 (sb-pcl::fast-method trace-gf
:around
(number)) :exit
84.0)))))
294 (defparameter *expected-trace-gf-number
+t-trace
*
295 '((0 (method trace-gf
:around
(number)) :enter
42.0)
296 (1 (method trace-gf
(t)) :enter
42.0)
297 (1 (method trace-gf
(t)) :exit
0)
298 (0 (method trace-gf
:around
(number)) :exit
84.0)))
300 (with-test (:name
(trace :methods
:untrace-some
))
301 (assert (equal (collecting-traces ((method trace-gf
:after
(float))
302 (method trace-gf
:around
(number))
303 (method trace-gf
(t)))
304 (untrace (method trace-gf
:after
(float)))
306 *expected-trace-gf-number
+t-trace
*)))
308 (with-test (:name
(trace :methods
:untrace-many
))
309 (assert (equal (collecting-traces ((method trace-gf
:around
(number))
310 (method trace-gf
(t))
314 *expected-trace-gf-number
+t-trace
*)))
316 (with-test (:name
(trace :methods
:trace-more
))
317 (assert (equal (collecting-traces ((method trace-gf
(t)))
318 (eval '(trace (method trace-gf
:around
(number))))
320 *expected-trace-gf-number
+t-trace
*)))
322 (defgeneric (setf trace-gf
) (value)
323 (:method
((x float
)) (call-next-method))
324 (:method
:before
((x number
)) 'before
)
325 (:method
((x number
)) x
))
327 (with-test (:name
(trace :setf-methods
))
328 (assert (equal (collecting-traces ((method (setf trace-gf
) (float))
329 (method (setf trace-gf
) (number))
330 (method (setf trace-gf
) :before
(number)))
331 (setf (trace-gf) 42.0))
332 '((0 (method (setf trace-gf
) :before
(number)) :enter
42.0)
333 (0 (method (setf trace-gf
) :before
(number)) :exit before
)
334 (0 (method (setf trace-gf
) (float)) :enter
42.0)
335 (1 (method (setf trace-gf
) (number)) :enter
42.0)
336 (1 (method (setf trace-gf
) (number)) :exit
42.0)
337 (0 (method (setf trace-gf
) (float)) :exit
42.0)))))
339 (defun global-fact (x)
340 (declare (optimize (debug 3))) ; suppress inlining
342 (flet ((multiply (x y
)
346 (multiply x
(fact (1- x
)))))))
349 (with-test (:name
(trace :labels
) .
#.
*breakpoint-tracing-expectations
*)
350 (assert (equal (collecting-traces ((labels fact
:in global-fact
)
351 (flet multiply
:in global-fact
))
353 '((0 (labels fact
:in global-fact
) :enter
1)
354 (1 (labels fact
:in global-fact
) :enter
0)
355 (1 (labels fact
:in global-fact
) :exit
1)
356 (1 (flet multiply
:in global-fact
) :enter
1 1)
357 (1 (flet multiply
:in global-fact
) :exit
1)
358 (0 (labels fact
:in global-fact
) :exit
1)))))
360 (defgeneric gfact
(x)
361 (:method
((x number
))
362 (declare (optimize (debug 3))) ; suppress inlining
363 (flet ((fact (x) (global-fact x
)))
366 (with-test (:name
(trace :labels
:within-method
)
367 .
#.
*breakpoint-tracing-expectations
*)
368 (assert (equal (collecting-traces ((flet fact
:in
(method gfact
(number))))
370 '((0 (flet fact
:in
(method gfact
(number))) :enter
3)
371 (0 (flet fact
:in
(method gfact
(number))) :exit
6)))))
373 (with-test (:name
(trace :labels
:within-untraced-method
)
374 .
#.
*breakpoint-tracing-expectations
*)
375 (assert (equal (collecting-traces ((method gfact
(number))
376 (flet fact
:in
(method gfact
(number))))
377 (untrace (method gfact
(number)))
379 '((0 (flet fact
:in
(method gfact
(number))) :enter
3)
380 (0 (flet fact
:in
(method gfact
(number))) :exit
6)))))
383 (declare (optimize (debug 3)))
384 (flet ((body () 'original-foo
))
387 (defun call-with-trace-foo-redefined (fn)
388 (let ((original (fdefinition 'trace-foo
)))
389 ;; the local function will be named (FLET BODY) instead of (FLET
390 ;; BODY :IN TRACE-FOO) unless we use EVAL here.
391 (eval '(defun trace-foo ()
392 (declare (optimize (debug 3)))
393 (flet ((body () 'redefined-foo
))
397 (setf (fdefinition 'trace-foo
) original
))))
399 (with-test (:name
(trace :labels
:redefined
)
400 .
#.
*breakpoint-tracing-expectations
*)
401 (assert (equal (collecting-traces ((flet body
:in trace-foo
))
403 (call-with-trace-foo-redefined 'trace-foo
))
404 '((0 (flet body
:in trace-foo
) :enter
)
405 (0 (flet body
:in trace-foo
) :exit original-foo
)
406 (0 (flet body
:in trace-foo
) :enter
)
407 (0 (flet body
:in trace-foo
) :exit redefined-foo
)))))
409 (defmethod trace-foo-gf ()
410 (declare (optimize (debug 3)))
411 (flet ((body () 'original-foo
))
414 (defun call-with-trace-foo-gf-redefined (fn)
415 ;; using ADD-METHOD and REMOVE-METHOD yields outdated DEBUG-FUN
416 ;; info, so work around that using EVAL.
417 (eval '(defmethod trace-foo-gf ()
418 (declare (optimize (debug 3)))
419 (flet ((body () 'redefined-foo
))
423 (eval '(defmethod trace-foo-gf ()
424 (declare (optimize (debug 3)))
425 (flet ((body () 'original-foo
))
428 (with-test (:name
(trace :labels
:redefined-method
)
429 .
#.
*breakpoint-tracing-expectations
*)
430 (assert (equal (collecting-traces ((flet body
:in
(method trace-foo-gf
())))
432 (call-with-trace-foo-gf-redefined 'trace-foo-gf
))
433 '((0 (flet body
:in
(method trace-foo-gf
())) :enter
)
434 (0 (flet body
:in
(method trace-foo-gf
())) :exit original-foo
)
435 (0 (flet body
:in
(method trace-foo-gf
())) :enter
)
436 (0 (flet body
:in
(method trace-foo-gf
())) :exit redefined-foo
)))))
438 (defun fn-with-cmac (x) x
)
440 (define-compiler-macro fn-with-cmac
(x)
441 (declare (ignore x
) (optimize (debug 3))) ; suppress flet inlining
445 (with-test (:name
(trace :compiler-macro
)
446 .
#.
*breakpoint-tracing-expectations
*)
447 (assert (equal (collecting-traces ((compiler-macro fn-with-cmac
))
448 (compile nil
'(lambda () (fn-with-cmac 0))))
449 '((0 (compiler-macro fn-with-cmac
) :enter
(fn-with-cmac 0) "unused argument")
450 (0 (compiler-macro fn-with-cmac
) :exit
42)))))
452 (with-test (:name
(trace :flet
:within-compiler-macro
)
453 .
#.
*breakpoint-tracing-expectations
*)
454 (assert (equal (collecting-traces ((flet body
:in
(compiler-macro fn-with-cmac
)))
455 (compile nil
'(lambda () (fn-with-cmac 0))))
456 '((0 (flet body
:in
(compiler-macro fn-with-cmac
)) :enter
)
457 (0 (flet body
:in
(compiler-macro fn-with-cmac
)) :exit
42)))))
459 (defun call-with-compiler-macro-redefined (fn)
460 (eval `(define-compiler-macro fn-with-cmac
(x)
461 (declare (ignore x
) (optimize (debug 3)))
462 (flet ((body () ''redefined
))
466 (eval `(define-compiler-macro fn-with-cmac
(x)
467 (declare (ignore x
) (optimize (debug 3)))
472 (with-test (:name
(trace :compiler-macro
:redefined
)
473 .
#.
*breakpoint-tracing-expectations
*)
474 (assert (equal (collecting-traces ((compiler-macro fn-with-cmac
)
475 (flet body
:in
(compiler-macro fn-with-cmac
)))
476 (compile nil
'(lambda () (fn-with-cmac 0)))
477 (call-with-compiler-macro-redefined
478 (lambda () (compile nil
'(lambda () (fn-with-cmac 0))))))
479 '((0 (compiler-macro fn-with-cmac
) :enter
(fn-with-cmac 0) "unused argument")
480 (1 (flet body
:in
(compiler-macro fn-with-cmac
)) :enter
)
481 (1 (flet body
:in
(compiler-macro fn-with-cmac
)) :exit
42)
482 (0 (compiler-macro fn-with-cmac
) :exit
42)
483 (0 (compiler-macro fn-with-cmac
) :enter
(fn-with-cmac 0) "unused argument")
484 (1 (flet body
:in
(compiler-macro fn-with-cmac
)) :enter
)
485 (1 (flet body
:in
(compiler-macro fn-with-cmac
)) :exit
'redefined
)
486 (0 (compiler-macro fn-with-cmac
) :exit
'redefined
)))))
492 (catch 'foo
(throw-foo)))
494 (with-test (:name
(trace :non-local-exit
))
495 (assert (equal (collecting-traces (throw-foo)
497 '((0 throw-foo
:enter
)
498 (0 throw-foo
:non-local-exit
)))))
500 (with-test (:name
(trace :non-local-exit
:standard-report
))
501 (let ((output (with-traced-function (throw-foo)
503 (assert (search "exited non-locally" output
))))
505 (defun trace-inner-function (x)
508 (defun trace-outer-function (x)
509 (declare (optimize (debug 3))) ; avoid tail call optimization
510 (trace-inner-function x
))
512 (defun test-trace-inner-function (&key encapsulate
)
513 (assert (equal (let ((sb-debug:*trace-encapsulate-default
* encapsulate
))
514 (collecting-traces (trace-inner-function
515 :wherein trace-outer-function
)
516 (trace-outer-function 'outer-value
)
517 (trace-inner-function 'inner-value
)))
518 '((0 trace-inner-function
:enter outer-value
)
519 (0 trace-inner-function
:exit outer-value
)))))
521 (with-test (:name
(trace :wherein
:encapsulate t
))
522 (test-trace-inner-function :encapsulate t
))
524 (with-test (:name
(trace :wherein
:encapsulate nil
)
525 .
#.
*breakpoint-tracing-expectations
*)
526 (test-trace-inner-function :encapsulate nil
))
528 (defun test-trace-fact-wherein (&key encapsulate
)
529 (assert (equal (let ((sb-debug:*trace-encapsulate-default
* encapsulate
))
530 (collecting-traces (trace-fact :wherein trace-fact
)
532 '((0 trace-fact
:enter
0)
533 (0 trace-fact
:exit
1)))))
535 (with-test (:name
(trace :wherein
:recursive
:encapsulate t
))
536 (test-trace-fact-wherein :encapsulate t
))
538 (with-test (:name
(trace :wherein
:recursive
:encapsulate nil
)
539 .
#.
*breakpoint-tracing-expectations
*)
540 (test-trace-fact-wherein :encapsulate nil
))
542 (defmacro macro-fact
(x)
543 (labels ((fact (x) (if (zerop x
) 1 (* x
(fact (1- x
))))))
546 (with-test (:name
(trace :macro
)
547 .
#.
*breakpoint-tracing-expectations
*)
548 (assert (equal (collecting-traces (macro-fact)
549 (macroexpand-1 '(macro-fact 3)))
550 '((0 macro-fact
:enter
(macro-fact 3) "unused argument")
551 (0 macro-fact
:exit
6)))))
553 (with-test (:name
(trace :labels
:within-macro
)
554 .
#.
*breakpoint-tracing-expectations
*)
555 (assert (equal (collecting-traces ((labels fact
:in macro-fact
))
556 (macroexpand-1 '(macro-fact 0)))
557 '((0 (labels fact
:in macro-fact
) :enter
0)
558 (0 (labels fact
:in macro-fact
) :exit
1)))))
560 (defun call-with-macro-fact-redefined (fn)
561 (handler-bind ((sb-kernel:redefinition-with-defmacro
#'muffle-warning
))
562 (eval `(defmacro macro-fact
(x)
563 (declare (ignore x
) (optimize (debug 3)))
564 (labels ((fact () 'redefined
)) (fact))))
567 (eval `(defmacro macro-fact
(x)
568 (labels ((fact (x) (if (zerop x
) 1 (* x
(fact (1- x
))))))
572 (with-test (:name
(trace :macro
:redefined
)
573 .
#.
*breakpoint-tracing-expectations
*)
574 (assert (equal (collecting-traces (macro-fact
575 (labels fact
:in macro-fact
))
576 (macroexpand-1 '(macro-fact 0))
577 (call-with-macro-fact-redefined
578 (lambda () (macroexpand-1 '(macro-fact 0)))))
579 '((0 macro-fact
:enter
(macro-fact 0) "unused argument")
580 (1 (labels fact
:in macro-fact
) :enter
0)
581 (1 (labels fact
:in macro-fact
) :exit
1) (0 macro-fact
:exit
1)
582 (0 macro-fact
:enter
(macro-fact 0) "unused argument")
583 (1 (labels fact
:in macro-fact
) :enter
)
584 (1 (labels fact
:in macro-fact
) :exit redefined
)
585 (0 macro-fact
:exit redefined
)))))
587 (defun (cas trace-cas
) (old new x
)
588 (declare (optimize (debug 3)))
589 (flet (((cas body
) (o n
)
591 (cas (body) old new
)))
593 (with-test (:name
(trace :cas
)
594 .
#.
*breakpoint-tracing-expectations
*)
595 (assert (equal (collecting-traces ((cas trace-cas
)
596 (flet (cas body
) :in
(cas trace-cas
)))
597 (cas (trace-cas 1) 21 20))
598 '((0 (cas trace-cas
) :enter
21 20 1)
599 (1 (flet (cas body
) :in
(cas trace-cas
)) :enter
21 20)
600 (1 (flet (cas body
) :in
(cas trace-cas
)) :exit
42)
601 (0 (cas trace-cas
) :exit
42)))))
603 (defmethod (cas trace-cas-gf
) (old new x
)
604 (declare (optimize (debug 3)))
605 (flet (((cas body
) (o n
)
607 (cas (body) old new
)))
609 (with-test (:name
(trace :cas
:generic
)
610 .
#.
*breakpoint-tracing-expectations
*)
611 (assert (equal (collecting-traces ((method (cas trace-cas-gf
) (t t t
))
612 (flet (cas body
) :in
(method (cas trace-cas-gf
) (t t t
))))
613 (cas (trace-cas-gf 1) 21 20))
614 '((0 (method (cas trace-cas-gf
) (t t t
)) :enter
21 20 1)
615 (1 (flet (cas body
) :in
(method (cas trace-cas-gf
) (t t t
))) :enter
21 20)
616 (1 (flet (cas body
) :in
(method (cas trace-cas-gf
) (t t t
))) :exit
42)
617 (0 (method (cas trace-cas-gf
) (t t t
)) :exit
42)))))
619 (defun (setf trace-setf
) (value x
)
620 (declare (optimize (debug 3)))
621 (flet (((setf body
) (value)
623 (setf (body) value
)))
625 (with-test (:name
(trace :setf
)
626 .
#.
*breakpoint-tracing-expectations
*)
627 (assert (equal (collecting-traces ((setf trace-setf
)
628 (flet (setf body
) :in
(setf trace-setf
)))
629 (setf (trace-setf 11) 31))
630 '((0 (setf trace-setf
) :enter
31 11)
631 (1 (flet (setf body
) :in
(setf trace-setf
)) :enter
31)
632 (1 (flet (setf body
) :in
(setf trace-setf
)) :exit
42)
633 (0 (setf trace-setf
) :exit
42)))))
635 (with-test (:name
:bug-414
)
636 (handler-bind ((warning #'error
))
637 (with-scratch-file (output "fasl")
638 (load (compile-file "bug-414.lisp" :output-file output
639 :verbose nil
:print nil
)))
640 (with-output-to-string (s)
641 (disassemble 'bug-414
:stream s
))))
643 ;; A known function can be stored as a code constant in lieu of the
644 ;; usual mode of storing an #<fdefn> and looking up the function from it.
645 ;; One such usage occurs with TAIL-CALL-VARIABLE (e.g. via APPLY).
646 ;; Show that declaring the function locally notinline uses the #<fdefn>
647 ;; by first compiling a call that would have elided the #<fdefn>
649 ;; XXX: what purpose has the JUNK argument?
650 (defun test-compile-then-load (filename junk
)
651 (declare (notinline compile-file load
))
652 (with-scratch-file (output "fasl")
653 (apply 'load
(apply 'compile-file filename
:output-file output junk
)
655 (compile 'test-compile-then-load
)
656 (with-test (:name
:traceable-known-fun
)
657 (let ((s (make-string-output-stream)))
658 (trace compile-file load
)
659 (let ((*trace-output
* s
))
660 (test-compile-then-load "bug-414.lisp" nil
))
662 (assert (>= (count #\Newline
(get-output-stream-string s
)) 4))))
664 (with-test (:name
:bug-310175
)
665 ;; KLUDGE: Not all DX-enabled platforms DX CONS, and the compiler
666 ;; transforms two-arg-LIST* (and one-arg-LIST) to CONS. Therefore,
667 ;; use two-arg-LIST, which should get through to VOP LIST, and thus
668 ;; stack-allocate on a predictable set of machines.
669 (let ((dx-arg (list t t
)))
670 (declare (dynamic-extent dx-arg
))
671 (flet ((dx-arg-backtrace (x)
672 (declare (optimize (debug 2)))
673 (prog1 (sb-debug:list-backtrace
:count
10)
674 (assert (sb-debug::stack-allocated-p x
)))))
675 (declare (notinline dx-arg-backtrace
))
676 (assert (member-if (lambda (frame)
679 (equal '(flet dx-arg-backtrace
:in
) (butlast (car frame
)))
680 (notany #'sb-debug
::stack-allocated-p
(cdr frame
))))
681 (dx-arg-backtrace dx-arg
))))))
683 (with-test (:name
:bug-795245
)
691 (sb-debug:print-backtrace
:count
100
692 :stream
(make-broadcast-stream))
694 (throw 'done
:error
))
696 (throw 'done
:ok
))))))
697 (apply '/= nil
1 2 nil
))))))
699 ;;;; test infinite error protection
701 (defmacro nest-errors
(n-levels error-form
)
703 `(handler-bind ((error (lambda (condition)
704 (declare (ignore condition
))
706 (nest-errors ,(1- n-levels
) ,error-form
))
709 (defun erroring-debugger-hook (condition old-debugger-hook
)
710 (let ((*debugger-hook
* old-debugger-hook
))
711 (format t
"recursive condition: ~A~%" condition
) (force-output)
712 (error "recursive condition: ~A" condition
)))
714 (defun test-infinite-error-protection ()
715 ;; after 50 successful throws to SB-IMPL::TOPLEVEL-CATCHER sbcl used
716 ;; to halt, it produces so much garbage that's hard to suppress that
717 ;; it is tested only once
718 (write-line "--HARMLESS BUT ALARMING BACKTRACE COMING UP--")
719 (let ((*debugger-hook
* #'erroring-debugger-hook
))
721 (let ((error-counter 0)
722 (*terminal-io
* (make-broadcast-stream)))
726 (catch 'sb-impl
::toplevel-catcher
727 (nest-errors 20 (error "infinite error ~s"
728 (incf error-counter
)))
730 (write-line "--END OF H-B-A-B--"))
732 ;;; *debugger-hook* is now cleared after trying to enter the debugger
733 ;;; *once in ERROR-ERROR, breaking these tests.
734 (with-test (:name
:infinite-error-protection
737 (test-infinite-error-protection))
739 (with-test (:name
(:infinite-error-protection
:thread
)
740 :skipped-on
(or :sbcl
(not :sb-thread
)))
742 (let ((thread (sb-thread:make-thread
#'test-infinite-error-protection
)))
743 (loop while
(sb-thread:thread-alive-p thread
))))
745 ;; unconditional, in case either previous left it enabled
748 ;;;; test some limitations of MAKE-LISP-OBJ
750 ;;; Older GENCGC systems had a bug in the pointer validation used by
751 ;;; MAKE-LISP-OBJ that made SIMPLE-FUN objects always fail to
753 (with-test (:name
(:make-lisp-obj
:simple-funs
))
754 (sb-sys:without-gcing
755 (assert (eq #'identity
756 (sb-kernel:make-lisp-obj
757 (sb-kernel:get-lisp-obj-address
760 ;;; Older CHENEYGC systems didn't perform any real pointer validity
761 ;;; checks beyond "is this pointer to somewhere in heap space".
762 (with-test (:name
(:make-lisp-obj
:pointer-validation
))
763 ;; Fun and games: We need to test MAKE-LISP-OBJ with a known-bogus
764 ;; address, but we also need the GC to not pitch a fit if it sees an
765 ;; object with said bogus address. Thus, construct our known-bogus
766 ;; object within an area of unboxed storage (a vector) in static
767 ;; space. We'll make it a simple object, (CONS 0 0), which has an
768 ;; in-memory representation of two consecutive zero words. We
769 ;; allocate a three-word vector so that we can guarantee a
770 ;; double-word aligned double-word of zeros no matter what happens
771 ;; with the vector-data-offset (currently double-word aligned).
772 (let* ((memory (sb-int:make-static-vector
3 :element-type
`(unsigned-byte ,sb-vm
:n-word-bits
)
774 (vector-data-address (sb-sys:sap-int
(sb-kernel::vector-sap memory
)))
775 (object-base-address (logandc2 (+ vector-data-address sb-vm
:lowtag-mask
) sb-vm
:lowtag-mask
))
776 (object-tagged-address (+ object-base-address sb-vm
:list-pointer-lowtag
)))
777 (multiple-value-bind (object valid-p
)
778 (sb-kernel:make-lisp-obj object-tagged-address nil
)
779 (declare (ignore object
))
780 (assert (not valid-p
)))))
782 (defun test-debugger (control form
&rest targets
)
783 (let ((out (make-string-output-stream))
787 (with-simple-restart (debugger-test-done! "Debugger Test Done!")
788 (let* ((*debug-io
* (make-two-way-stream
789 (make-string-input-stream control
)
790 (make-broadcast-stream out
#+nil
*standard-output
*)))
791 ;; Initial announcement goes to *ERROR-OUTPUT*
792 (*error-output
* *debug-io
*)
793 (*invoke-debugger-hook
* nil
))
794 (handler-bind ((error #'invoke-debugger
))
798 (error "Uncontrolled unwind from debugger test.")))
799 ;; For sanity's sake this is outside the *debug-io* rebinding -- otherwise
800 ;; it could swallow our asserts!
801 (with-input-from-string (s (get-output-stream-string out
))
802 (loop for line
= (read-line s nil
)
804 do
(assert targets nil
"Line = ~a" line
)
806 (format *error-output
* "Got: ~A~%" line
)
807 (let ((match (pop targets
)))
809 ;; Whatever, till the next line matches.
810 (let ((text (pop targets
)))
812 (format *error-output
* "Looking for: ~A~%" text
)
813 (unless (search text line
)
815 (push match targets
)))
816 (unless (search match line
)
817 (format *error-output
* "~&Wanted: ~S~% Got: ~S~%" match line
)
819 ;; Check that we saw everything we wanted
821 (error "Missed: ~S" targets
))
822 (assert (not oops
))))
824 (with-test (:name
(:debugger
:source
1))
830 (defun this-will-break (x)
831 (declare (optimize debug
))
840 "Operation was (/ 1 0)"
843 "(THIS-WILL-BREAK 1)"
848 (with-test (:name
(:debugger
:source
2))
853 `(locally (declare (optimize (speed 0) (safety 3) (debug 3)))
854 (let ((f #'(lambda (x cont
)
855 (print x
(make-broadcast-stream))
858 (funcall cont
(1- x
) cont
)))))
865 "source: (ERROR \"~%foo\")"
869 "(FUNCALL CONT (1- X) CONT)"
872 (with-test (:name
(:debugger
:bogus-debug-fun
:source
) :skipped-on
:ppc
)
883 (with-test (:name
(disassemble :high-debug-eval
))
884 (eval `(defun this-will-be-disassembled (x)
885 (declare (optimize debug
))
887 (let* ((oopses (make-string-output-stream))
889 (let ((*error-output
* oopses
))
890 (with-output-to-string (*standard-output
*)
891 (disassemble 'this-will-be-disassembled
)))))
892 (with-input-from-string (s disassembly
)
893 (assert (search "; disassembly for THIS-WILL-BE-DISASSEMBLED"
895 (let ((problems (get-output-stream-string oopses
)))
896 (unless (zerop (length problems
))
899 (defun this-too-will-be-disasssembled (x)
900 (declare (optimize debug
))
903 (with-test (:name
(disassemble :high-debug-load
))
904 (let* ((oopses (make-string-output-stream))
906 (let ((*error-output
* oopses
))
907 (with-output-to-string (*standard-output
*)
908 (disassemble 'this-too-will-be-disasssembled
)))))
909 (with-input-from-string (s disassembly
)
910 (assert (equal "; disassembly for THIS-TOO-WILL-BE-DISASSSEMBLED"
912 (let ((problems (get-output-stream-string oopses
)))
913 (unless (zerop (length problems
))
916 (with-test (:name
(:xep-arglist-clean-up
:bug-1192929
))
919 (handler-bind ((error (lambda (e)
921 (return (< (length (car (sb-debug:list-backtrace
:count
1)))
923 (funcall (compile nil
`(lambda (i) (declare ((mod 65536) i
)) i
)) nil
)))))
927 (defun print-backtrace-to-string/debug-print-variable-alist
(x)
929 (with-output-to-string (stream)
930 (let ((*debug-print-variable-alist
* '((*print-length
* .
5)
931 (*print-level
* .
3))))
932 (sb-debug:print-backtrace
:stream stream
:count
5)))
933 x
)) ; Force use of X to prevent flushing
935 (with-test (:name
(:print-frame-call
:respect
*debug-print-variable-alist
*
936 *print-length
* :bug-1261646
))
937 (let* ((printed (print-backtrace-to-string/debug-print-variable-alist
938 (make-array 200 :initial-element
0)))
939 (call "(PRINT-BACKTRACE-TO-STRING/DEBUG-PRINT-VARIABLE-ALIST ")
940 (position (+ (search call printed
) (length call
))))
941 (assert (eql position
(search "#(0 0 0 0 0 ...)" printed
:start2 position
)))))
943 (with-test (:name
(:print-frame-call
:respect
*debug-print-variable-alist
*
944 *print-level
* :bug-1261646
))
945 (let* ((printed (print-backtrace-to-string/debug-print-variable-alist
947 (call "(PRINT-BACKTRACE-TO-STRING/DEBUG-PRINT-VARIABLE-ALIST ")
948 (position (+ (search call printed
) (length call
))))
949 (assert (eql position
(search "((#))" printed
:start2 position
)))))
955 (with-test (:name
:trace-debug-arg
)
956 (trace foo
:print-after
(setf *x
* (sb-debug:arg
0)))
960 (trace foo
:print
(setf *x
* (sb-debug:arg
0)))
964 (trace foo
:condition
(eql (setf *x
* (sb-debug:arg
0)) 0))
968 (trace foo
:condition-after
(setf *x
* (sb-debug:arg
0)))
972 (trace foo
:break
(and (setf *x
* (sb-debug:arg
0)) nil
))
976 (trace foo
:break-all
(and (setf *x
* (sb-debug:arg
0)) nil
))
979 (trace foo
:break-after
(and (setf *x
* (sb-debug:arg
0)) nil
))
982 (defun frobbleize (arg) (declare (ignore arg
)) (sb-debug:list-backtrace
) 'win
)
983 (defmethod low-debug-method ((self t
))
984 (declare (optimize (debug 0)))
985 (frobbleize 'me
) ; make this not a tail call, so it remains on stack
987 (with-test (:name
:clean-fast-method-frame-lossage
)
988 (low-debug-method 42)) ; no need to assert. it either crashes or doesn't
990 (defun return-65535 ()
993 (with-test (:name
:indirect-closure-values
)
996 (handler-bind ((error (lambda (c)
998 (sb-debug:map-backtrace
1000 (let ((sb-debug::*current-frame
* frame
)
1001 (name (sb-debug::frame-call frame
)))
1002 (when (or (eq name
'test
)
1004 (or (eql (search '(labels f1
) name
) 0)
1005 (eql (search '(labels f2
) name
) 0))))
1007 (assert (eql (var 'a
) 2))))))
1011 `(sb-int:named-lambda test
()
1012 (declare (optimize debug
))
1021 (assert (= count
3))))
1023 (with-test (:name
:indirect-closure-values
.2)
1026 (handler-bind ((error (lambda (c)
1027 (declare (ignore c
))
1028 (sb-debug:map-backtrace
1030 (let ((sb-debug::*current-frame
* frame
)
1031 (name (sb-debug::frame-call frame
)))
1032 (when (or (eq name
'test
)
1034 (or (eql (search '(labels f1
) name
) 0)
1035 (eql (search '(labels f2
) name
) 0))))
1037 (assert (eql (var 'a
) 65535))))))
1041 `(sb-int:named-lambda test
()
1042 (declare (optimize debug
))
1043 (let ((a (return-65535)))
1044 (declare ((unsigned-byte 16) a
))
1052 (assert (= count
3))))
1054 (with-test (:name
:indirect-closure-values.crash
)
1056 (handler-bind ((error (lambda (c)
1057 (declare (ignore c
))
1058 (sb-debug:map-backtrace
1060 (let ((name (sb-debug::frame-call frame
))
1061 (location (sb-debug::frame-code-location frame
))
1062 (d-fun (sb-debug::frame-debug-fun frame
)))
1063 (when (eq name
'test
)
1064 (assert (sb-debug::debug-var-info-available d-fun
))
1065 (dolist (v (sb-debug::ambiguous-debug-vars d-fun
""))
1066 (assert (not (sb-debug::var-valid-in-frame-p v location frame
))))
1070 `(sb-int:named-lambda test
()
1071 (declare (optimize debug safety
))
1078 (with-test (:name
:non-tail-self-call-bad-variables
)
1081 (handler-bind ((error (lambda (c)
1082 (declare (ignore c
))
1083 (sb-debug:map-backtrace
1085 (let ((sb-debug::*current-frame
* frame
))
1086 (multiple-value-bind (name args
)
1087 (sb-debug::frame-call frame
)
1088 (when (eq name
'test
)
1089 (assert (or (null args
)
1090 (equal args
'(nil))))
1094 (compile nil
`(sb-int:named-lambda test
(&optional x
)
1095 (declare (optimize sb-c
::recognize-self-calls
))
1096 (signal 'error
:format-control
"~a" :format-arguments
(list x
))
1099 (assert (= count
1))))
1101 (with-test (:name
:local-tail-call-variables
)
1104 (handler-bind ((error (lambda (c)
1105 (declare (ignore c
))
1106 (sb-debug:map-backtrace
1108 (let ((sb-debug::*current-frame
* frame
))
1109 (multiple-value-bind (name args
)
1110 (sb-debug::frame-call frame
)
1111 (when (eq name
'test
)
1112 (assert (equal args
'(error)))
1116 (compile nil
`(sb-int:named-lambda test
(x)
1118 ;; If :local-tail-call fails, this will fail
1119 ;; too, because there's no jump between
1120 ;; SIGNAL and the call to TAIL and it will
1121 ;; show (flet tail) in the backtrace.
1123 (declare (notinline tail
))
1126 (assert (= count
1))))
1128 (with-test (:name
:variables-surrounding-inlined-code
)
1131 (handler-bind ((error (lambda (c)
1132 (declare (ignore c
))
1133 (sb-debug:map-backtrace
1135 (let ((sb-debug::*current-frame
* frame
))
1136 (multiple-value-bind (name)
1137 (sb-debug::frame-call frame
)
1138 (when (eq name
'test
)
1139 (assert (equal (sb-debug:var
'l
) '(1 2 3)))
1143 (compile nil
`(sb-int:named-lambda test
(a i
)
1144 (declare (optimize (debug 3)))
1145 (let ((l (list 1 2 3)))
1149 (assert (= count
1))))
1151 (with-test (:name
:variables-surrounding-inlined-code
.2)
1154 (handler-bind ((error (lambda (c)
1155 (declare (ignore c
))
1156 (sb-debug:map-backtrace
1158 (let ((sb-debug::*current-frame
* frame
))
1159 (multiple-value-bind (name)
1160 (sb-debug::frame-call frame
)
1161 (when (eq name
'test
)
1162 (assert (equal (sb-debug:var
'l
) '(1 2 3)))
1166 (compile nil
`(sb-int:named-lambda test
(c)
1167 (declare (optimize (debug 3)))
1168 (let ((l (list 1 2 3)))
1169 (map 'list
#'signal c
)
1172 (assert (= count
1))))
1174 (with-test (:name
:properly-tagged-p-internal
)
1175 ;; Pick a code component that has a ton of restarts.
1176 (let* ((code (sb-kernel:fun-code-header
#'sb-impl
::update-package-with-variance
))
1177 (n (sb-kernel:code-n-entries code
)))
1178 (sb-sys:with-pinned-objects
(code)
1179 (let* ((base (logandc2 (sb-kernel:get-lisp-obj-address code
)
1181 (limit (+ base
(sb-ext:primitive-object-size code
))))
1182 (flet ((properly-tagged-p (ptr)
1183 (eql (alien-funcall (extern-alien "properly_tagged_p_internal"
1184 (function int unsigned unsigned
))
1187 ;; For architectures that don't use LRAs, there are exactly 'n-entries'
1188 ;; properly tagged interior pointers. For those which do use LRAs,
1189 ;; there are at least that many, because we allow pointing to LRAs,
1190 ;; but they aren't enumerable so we don't know the actual count.
1191 (assert (#+(or x86 x86-64 arm64
) =
1192 #-
(or x86 x86-64 arm64
) >
1193 (loop for ptr from
(+ base
(* 2 sb-vm
:n-word-bytes
))
1194 below limit count
(properly-tagged-p ptr
))
1196 ;; Verify that the binary search algorithm for simple-fun-index works.
1198 (loop for ptr from base below limit
1200 (let ((index (alien-funcall
1201 (extern-alien "simple_fun_index"
1202 (function int unsigned unsigned
))
1204 (unless (eql index -
1)
1205 (let ((tagged-fun (logior ptr sb-vm
:fun-pointer-lowtag
)))
1206 (assert (properly-tagged-p tagged-fun
))
1209 (format t
"~x -> ~d (~a)~%"
1210 ptr index
(sb-kernel:make-lisp-obj tagged-fun
))))))
1211 (assert (= count n
))))))))
1213 (with-test (:name
:repeatable-fasl
)
1214 (with-scratch-file (output1 "fasl")
1215 (compile-file "bug-414.lisp" ; compile this file, why not
1216 ::output-file output1
:verbose nil
:print nil
)
1217 (with-scratch-file (output2 "fasl")
1218 (compile-file "bug-414.lisp" ; compile this file, why not
1219 ::output-file output2
:verbose nil
:print nil
)
1220 (with-open-file (fasl1 output1
:element-type
'(unsigned-byte 8))
1221 (with-open-file (fasl2 output2
:element-type
'(unsigned-byte 8))
1222 (assert (= (file-length fasl1
) (file-length fasl2
)))
1223 (loop repeat
(file-length fasl1
)
1224 do
(assert (= (read-byte fasl1
) (read-byte fasl2
)))))))))
1227 (defun ll-unknown (x y
) (declare (optimize (debug 0))) (+ x y
))
1228 (compile 'll-unknown
)
1229 (with-test (:name
:unknown-lambda-list
)
1230 (assert (eq (sb-kernel:%fun-lambda-list
#'ll-unknown
) :unknown
)))
1232 ;;;; SB-DEBUG:*STACK-TOP-HINT* management
1234 (defun buggy-handler (c)
1235 (declare (ignore c
))
1236 ;; signal a nondescript condition to avoid triggering WITH-TEST's error
1238 (error 'simple-condition
:format-control
"buggy handler"))
1240 (defun signal-and-handle-with-buggy-handler ()
1241 (handler-bind ((program-error #'buggy-handler
))
1242 (signal 'program-error
)))
1244 (defun call-getting-stack-top-on-invoke-debugger (fn)
1246 (let ((*invoke-debugger-hook
*
1247 (lambda (condition hook
)
1248 (declare (ignore condition hook
))
1249 (let ((top (sb-debug::resolve-stack-top-hint
)))
1250 (return (caar (sb-debug:list-backtrace
:from top
)))))))
1253 (defun ds-bind-when (x)
1255 (sb-c::ds-bind-error
'(foo) 2 3 '((:macro baz . deftype
))))
1256 (print "something to prevent tco"))
1258 (with-test (:name
(:stack-top-hint
:arg-count-error
))
1259 (assert (eq 'ds-bind-when
1261 (handler-bind ((error
1263 (declare (ignore c
))
1264 (let ((top (sb-debug::resolve-stack-top-hint
)))
1265 (return (caar (sb-debug:list-backtrace
:from top
)))))))
1266 (ds-bind-when t
))))))
1268 ;; If an error occurs within a signal handler, we want to see the handling
1269 ;; frames in the backtrace.
1270 (with-test (:name
(:stack-top-hint
:signal
))
1271 (assert (eq 'buggy-handler
1272 (call-getting-stack-top-on-invoke-debugger
1273 #'signal-and-handle-with-buggy-handler
))))
1275 ;; When breaking on signals, we don't need to see the SIGNAL frame or other
1276 ;; frames above that.
1277 (with-test (:name
(:stack-top-hint
:signal
:break-on-signals
))
1278 (assert (eq 'signal-and-handle-with-buggy-handler
1279 (let ((*break-on-signals
* t
))
1280 (call-getting-stack-top-on-invoke-debugger
1281 #'signal-and-handle-with-buggy-handler
)))))