1 ;;;; This file is for testing backtraces, using test machinery which
2 ;;;; might have side effects (e.g. executing DEFUN).
4 ;;;; This software is part of the SBCL system. See the README file for
7 ;;;; While most of SBCL is derived from the CMU CL system, the test
8 ;;;; files (like this one) were written from scratch after the fork
11 ;;;; This software is in the public domain and is provided with
12 ;;;; absolutely no warranty. See the COPYING and CREDITS files for
13 ;;;; more information.
15 (cl:in-package
:cl-user
)
17 ;;; The following objects should be EQUALP to the respective markers
18 ;;; produced by the backtrace machinery.
20 (defvar *unused-argument
*
21 (sb-debug::make-unprintable-object
"unused argument"))
23 (defvar *unavailable-argument
*
24 (sb-debug::make-unprintable-object
"unavailable argument"))
26 (defvar *unavailable-more
*
27 (sb-debug::make-unprintable-object
"more unavailable arguments"))
29 (defvar *unavailable-lambda-list
*
30 (sb-debug::make-unprintable-object
"unavailable lambda list"))
32 ;;; TEST-FUNCTION is called and has to signal an error at which point
33 ;;; the backtrace will be captured.
35 ;;; If DETAILS is true, the returned backtrace description is of the
38 ;;; (((NAME1 . ARGS1) INFO1)
39 ;;; ((NAME2 . ARGS2) INFO2)
42 ;;; Otherwise it is of the form
48 (defun call-with-backtrace (cont test-function
&key details
)
49 (flet ((capture-it (condition)
51 (sb-debug::map-backtrace
53 (multiple-value-bind (name args info
)
54 (sb-debug::frame-call frame
)
56 (list (cons name args
) info
)
59 (funcall cont
(nreverse backtrace
) condition
))))
60 (handler-bind ((error #'capture-it
))
61 (funcall test-function
))))
63 ;;; Check the backtrace FRAMES against the list of frame
64 ;;; specifications EXPECTED signaling an error if they do not match.
66 ;;; If DETAILS is true, EXPECTED is a list with elements of the form
68 ;;; ((FUNCTION ARGS) INFO)
70 ;;; Otherwise elements are of the form
74 ;;; ARGS is a list of expected argument values, but can also contain
75 ;;; the following symbols
77 ;;; &REST The corresponding frame in FRAMES can contain an arbitrary
78 ;;; number of arguments starting at the corresponding
81 ;;; ? The corresponding frame in FRAMES can have an arbitrary
82 ;;; argument at the corresponding position.
83 (defun check-backtrace (frames expected
&key details
)
84 (labels ((args-equal (want actual
)
85 (cond ((eq want
*unavailable-lambda-list
*)
87 ((eq '&rest
(car want
))
91 ((or (eq '?
(car want
)) (equal (car want
) (car actual
)))
92 (args-equal (cdr want
) (cdr actual
)))
93 ((typep (car want
) 'sb-impl
::unprintable-object
)
94 (equalp (car want
) (car actual
)))
97 (fail (datum &rest arguments
)
98 (return-from check-backtrace
99 (values nil
(apply #'sb-kernel
:coerce-to-condition
100 datum
'simple-error
'error arguments
)))))
101 (mapc (lambda (frame spec
)
106 (and (args-equal (car spec
)
108 (equal (cdr spec
) (cdr frame
))))
110 (and (equal (car spec
) (car frame
))
111 (args-equal (cdr spec
) (cdr frame
)))))
112 (fail "~@<Unexpected frame during ~
113 ~:[non-detailed~:;detailed~] check: wanted ~S, got ~
115 details spec frame
)))
119 ;;; Check for backtraces generally being correct. Ensure that the
120 ;;; actual backtrace finishes (doesn't signal any errors on its own),
121 ;;; and that it contains the frames we expect, doesn't contain any
122 ;;; "bogus stack frame"s, and contains the appropriate toplevel call
123 ;;; and hasn't been cut off anywhere.
125 ;;; See CHECK-BACKTRACE for an explanation of the structure
127 (defun verify-backtrace (test-function expected-frames
&key details
)
128 (labels ((find-frame (function-name frames
)
129 (member function-name frames
130 :key
(if details
#'caar
#'car
)
132 (fail (datum &rest arguments
)
133 (return-from verify-backtrace
134 (values nil
(apply #'sb-kernel
:coerce-to-condition
135 datum
'simple-error
'error arguments
)))))
137 (lambda (backtrace condition
)
138 (declare (ignore condition
))
139 (let* ((test-function-name (if details
140 (caaar expected-frames
)
141 (caar expected-frames
)))
142 (frames (or (find-frame test-function-name backtrace
)
143 (fail "~@<~S (expected name ~S) not found in ~
144 backtrace:~@:_~S~@:>"
145 test-function test-function-name backtrace
))))
146 ;; Check that we have all the frames we wanted.
147 (multiple-value-bind (successp condition
)
148 (check-backtrace frames expected-frames
:details details
)
149 (unless successp
(fail condition
)))
150 ;; Make sure the backtrace isn't stunted in any way.
151 ;; (Depends on running in the main thread.) FIXME: On Windows
152 ;; we get two extra foreign frames below regular frames.
153 (unless (find-frame 'sb-impl
::toplevel-init frames
)
154 (fail "~@<Backtrace stunted:~@:_~S~@:>" backtrace
)))
155 (return-from verify-backtrace t
))
156 test-function
:details details
)))
158 (defun assert-backtrace (test-function expected-frames
&key details
)
159 (multiple-value-bind (successp condition
)
160 (verify-backtrace test-function expected-frames
:details details
)
161 (or successp
(error condition
))))
163 (defvar *p
* (namestring *load-truename
*))
165 (defvar *undefined-function-frame
*
166 '("undefined function"))
171 ;;; Test for "undefined function" (undefined_tramp) working properly.
172 ;;; Try it with and without tail call elimination, since they can have
173 ;;; different effects. (Specifically, if undefined_tramp is incorrect
174 ;;; a stunted stack can result from the tail call variant.)
176 (declare (optimize (speed 2) (debug 1))) ; tail call elimination
177 (declare (muffle-conditions style-warning
))
178 (#:undefined-function
42))
180 (declare (optimize (speed 1) (debug 3))) ; no tail call elimination
181 (declare (muffle-conditions style-warning
))
182 (#:undefined-function
42))
184 (declare (optimize (speed 1) (debug 3))) ; no tail call elimination
187 (with-test (:name
(:backtrace
:undefined-function
:bug-346
)
188 :skipped-on
:interpreter
189 ;; Failures on SPARC, and probably HPPA are due to
190 ;; not having a full and valid stack frame for the
191 ;; undefined function frame. See PPC
192 ;; undefined_tramp for details.
193 :fails-on
'(or :sparc
))
195 (lambda () (test #'optimized
))
196 (list (append *undefined-function-frame
* '(42))
197 (list `(flet test
:in
,*p
*) #'optimized
))))
199 ;; bug 353: This test fails at least most of the time for x86/linux
200 ;; ca. 0.8.20.16. -- WHN
201 (with-test (:name
(:backtrace
:undefined-function
:bug-353
)
202 :skipped-on
:interpreter
)
204 (lambda () (test #'not-optimized
))
205 (list (append *undefined-function-frame
* '(42))
206 (list `(flet not-optimized
:in
,*p
*))
207 (list `(flet test
:in
,*p
*) #'not-optimized
)))))
209 (with-test (:name
(:backtrace
:interrupted-condition-wait
)
210 :skipped-on
'(not :sb-thread
))
211 (let ((m (sb-thread:make-mutex
))
212 (q (sb-thread:make-waitqueue
)))
215 (sb-thread:with-mutex
(m)
216 (handler-bind ((timeout (lambda (condition)
217 (declare (ignore condition
))
220 (sb-thread:condition-wait q m
)))))
221 `((sb-thread:condition-wait
,q
,m
:timeout nil
)))))
223 ;;; Division by zero was a common error on PPC. It depended on the
224 ;;; return function either being before INTEGER-/-INTEGER in memory,
225 ;;; or more than MOST-POSITIVE-FIXNUM bytes ahead. It also depends on
226 ;;; INTEGER-/-INTEGER calling SIGNED-TRUNCATE. I believe Raymond Toy
227 ;;; says that the Sparc backend (at least for CMUCL) inlines this, so
228 ;;; if SBCL does the same this test is probably not good for the
231 ;;; Disabling tail call elimination on this will probably ensure that
232 ;;; the return value (to the flet or the enclosing top level form) is
233 ;;; more than MOST-POSITIVE-FIXNUM with the current spaces on OS X.
234 ;;; Enabling it might catch other problems, so do it anyway.
236 (declare (optimize (speed 2) (debug 1))) ; tail call elimination
237 (declare (muffle-conditions style-warning
))
240 (declare (optimize (speed 1) (debug 3))) ; no tail call elimination
241 (declare (muffle-conditions style-warning
))
244 (declare (optimize (speed 1) (debug 3))) ; no tail call elimination
247 (with-test (:name
(:backtrace
:divide-by-zero
:bug-346
)
248 :skipped-on
:interpreter
)
249 (assert-backtrace (lambda () (test #'optimized
))
251 ((flet test
:in
,*p
*) ,#'optimized
))))
253 (with-test (:name
(:backtrace
:divide-by-zero
:bug-356
)
254 :skipped-on
:interpreter
)
255 (assert-backtrace (lambda () (test #'not-optimized
))
257 ((flet not-optimized
:in
,*p
*))
258 ((flet test
:in
,*p
*) ,#'not-optimized
)))))
261 (throw 'no-such-tag t
))
262 (with-test (:name
(:backtrace
:throw
:no-such-tag
)
263 :fails-on
'(and :sparc
:linux
))
264 (assert-backtrace #'throw-test
'((throw-test))))
266 (funcall (checked-compile
268 (defun bug-308926 (x)
275 :allow-style-warnings t
))
276 (with-test (:name
(:backtrace
:bug-308926
) :skipped-on
:interpreter
)
277 (assert-backtrace (lambda () (bug-308926 13))
278 '(((flet bar
:in bug-308926
) 13)
279 (bug-308926 &rest t
))))
281 ;;; Test backtrace through assembly routines
283 (macrolet ((test (predicate fun
285 (find-symbol (format nil
"TWO-ARG-~A" fun
)
287 (let ((test-name (make-symbol (format nil
"TEST-~A" fun
))))
288 `(flet ((,test-name
(x y
)
289 ;; make sure it's not in tail position
291 (with-test (:name
(:backtrace
:bug-800343
,fun
)
292 :skipped-on
:interpreter
)
295 (eval `(funcall ,#',test-name
42 t
)))
299 `((,(find-symbol (format nil
"GENERIC-~A" fun
) "SB-VM"))))
300 ((flet ,(string test-name
) :in
,*p
*) 42 t
)))))))
301 (test-predicates (&rest functions
)
302 `(progn ,@(mapcar (lambda (function)
303 `(test t
,@(sb-int:ensure-list function
)))
305 (test-functions (&rest functions
)
306 `(progn ,@(mapcar (lambda (function)
307 `(test nil
,@(sb-int:ensure-list function
)))
309 (test-predicates = < >)
310 (test-functions + -
* /
312 (logand sb-kernel
:two-arg-and
)
313 (logior sb-kernel
:two-arg-ior
)
314 (logxor sb-kernel
:two-arg-xor
)))
316 ;;; test entry point handling in backtraces
318 (with-test (:name
(:backtrace
:xep-too-many-arguments
)
319 :skipped-on
:interpreter
)
320 ;; CHECKED-COMPILE avoids STYLE-WARNING noise.
321 (assert-backtrace (checked-compile '(lambda () (oops 1 2 3 4 5 6))
322 :allow-style-warnings t
)
323 '((oops ? ? ? ? ? ?
))))
325 (defmacro defbt
(n ll
&body body
)
326 ;; WTF is this? This is a way to make these tests not depend so much on the
327 ;; details of LOAD/EVAL. Around 1.0.57 we changed %SIMPLE-EVAL to be
328 ;; slightly smarter, which meant that things which used to have xeps
329 ;; suddently had tl-xeps, etc. This takes care of that.
335 (defun ,(intern (format nil
"BT.~A.1" n
)) ,ll
337 ;; no arguments saved
338 (defun ,(intern (format nil
"BT.~A.2" n
)) ,ll
339 (declare (optimize (debug 1) (speed 3)))
341 ;; no lambda-list saved
342 (defun ,(intern (format nil
"BT.~A.3" n
)) ,ll
343 (declare (optimize (debug 0)))
345 :allow-style-warnings t
)))
353 (defbt 3 (&key
(key (oops)))
356 ;;; ERROR instead of OOPS so that tail call elimination doesn't happen
357 (defbt 4 (&optional opt
)
358 (list (error "error")))
360 (defbt 5 (&optional
(opt (oops)))
363 (defbt 6 (&optional
(opt nil opt-p
))
364 (declare (ignore opt
))
365 (list (error "error ~A" opt-p
))) ; use OPT-P
367 (defbt 7 (&key
(key nil key-p
))
368 (declare (ignore key
))
369 (list (error "error ~A" key-p
))) ; use KEY-P
372 (error "XEPs in backtraces: ~S" x
))
374 (with-test (:name
(:backtrace
:bug-354
))
375 (assert (not (verify-backtrace (lambda () (bug-354 354))
377 (((bug-354 &rest
) (:tl
:external
)) 354)))))
378 (assert-backtrace (lambda () (bug-354 354)) '((bug-354 354))))
380 ;;; FIXME: This test really should be broken into smaller pieces
381 (with-test (:name
(:backtrace
:tl-xep
))
382 (assert-backtrace #'namestring
'(((namestring) (:external
))) :details t
)
383 (assert-backtrace #'namestring
'((namestring))))
385 (with-test (:name
(:backtrace
:more-processor
))
386 ;; CHECKED-COMPILE avoids STYLE-WARNING noise.
387 (assert-backtrace (checked-compile '(lambda () (bt.1.1 :key
))
388 :allow-style-warnings t
)
389 '(((bt.1.1 :key
) (:more
)))
391 (assert-backtrace (checked-compile '(lambda () (bt.1.2 :key
))
392 :allow-style-warnings t
)
393 '(((bt.1.2 ?
) (:more
)))
395 (assert-backtrace (lambda () (bt.1.3 :key
))
396 `(((bt.1.3 ,*unavailable-more
*) (:more
)))
398 (assert-backtrace (checked-compile '(lambda () (bt.1.1 :key
))
399 :allow-style-warnings t
)
401 (assert-backtrace (checked-compile '(lambda () (bt.1.2 :key
))
402 :allow-style-warnings t
)
404 (assert-backtrace (lambda () (bt.1.3 :key
))
407 (with-test (:name
(:backtrace
:xep
))
408 (assert-backtrace #'bt
.2.1 '(((bt.2.1) (:external
))) :details t
)
409 (assert-backtrace #'bt
.2.2 '(((bt.2.2) (:external
))) :details t
)
410 (assert-backtrace #'bt
.2.3 `(((bt.2.3) (:external
))) :details t
)
411 (assert-backtrace #'bt
.2.1 '((bt.2.1)))
412 (assert-backtrace #'bt
.2.2 '((bt.2.2)))
413 (assert-backtrace #'bt
.2.3 `((bt.2.3))))
415 ;;; This test is somewhat deceptively named. Due to confusion in debug
416 ;;; naming these functions used to have sb-c::varargs-entry debug
417 ;;; names for their main lambda.
418 (with-test (:name
(:backtrace
:varargs-entry
))
419 (assert-backtrace #'bt
.3.1 '((bt.3.1 :key nil
)))
420 (assert-backtrace #'bt
.3.2 '((bt.3.2 :key ?
)))
421 (assert-backtrace #'bt
.3.3 `((bt.3.3 :key
,*unavailable-argument
*)))
422 (assert-backtrace #'bt
.3.1 '((bt.3.1 :key nil
)))
423 (assert-backtrace #'bt
.3.2 '((bt.3.2 :key ?
)))
424 (assert-backtrace #'bt
.3.3 `((bt.3.3 :key
,*unavailable-argument
*))))
426 ;;; This test is somewhat deceptively named. Due to confusion in debug naming
427 ;;; these functions used to have sb-c::hairy-args-processor debug names for
428 ;;; their main lambda.
429 (with-test (:name
(:backtrace
:hairy-args-processor
))
430 (assert-backtrace #'bt
.4.1 '((bt.4.1 ?
)))
431 (assert-backtrace #'bt
.4.2 '((bt.4.2 ?
)))
432 (assert-backtrace #'bt
.4.3 `((bt.4.3 ,*unused-argument
*)))
433 (assert-backtrace #'bt
.4.1 '((bt.4.1 ?
)))
434 (assert-backtrace #'bt
.4.2 '((bt.4.2 ?
)))
435 (assert-backtrace #'bt
.4.3 `((bt.4.3 ,*unused-argument
*))))
437 (with-test (:name
(:backtrace
:optional-processor
))
438 (assert-backtrace #'bt
.5.1 '(((bt.5.1) (:optional
))) :details t
)
439 (assert-backtrace #'bt
.5.2 '(((bt.5.2) (:optional
))) :details t
)
440 (assert-backtrace #'bt
.5.3 `(((bt.5.3) (:optional
)))
442 (assert-backtrace #'bt
.5.1 '((bt.5.1)))
443 (assert-backtrace #'bt
.5.2 '((bt.5.2)))
444 (assert-backtrace #'bt
.5.3 `((bt.5.3))))
446 (with-test (:name
(:backtrace
:unused-optional-with-supplied-p
:bug-1498644
))
447 (assert-backtrace (lambda () (bt.6.1 :opt
))
448 `(((bt.6.1 ,*unused-argument
*) ()))
450 (assert-backtrace (lambda () (bt.6.2 :opt
))
451 `(((bt.6.2 ,*unused-argument
*) ()))
453 (assert-backtrace (lambda () (bt.6.3 :opt
))
454 `(((bt.6.3 ,*unused-argument
*) ()))
456 (assert-backtrace (lambda () (bt.6.1 :opt
))
457 `((bt.6.1 ,*unused-argument
*)))
458 (assert-backtrace (lambda () (bt.6.2 :opt
))
459 `((bt.6.2 ,*unused-argument
*)))
460 (assert-backtrace (lambda () (bt.6.3 :opt
))
461 `((bt.6.3 ,*unused-argument
*))))
463 (with-test (:name
(:backtrace
:unused-key-with-supplied-p
))
464 (assert-backtrace (lambda () (bt.7.1 :key
:value
))
465 `(((bt.7.1 :key
,*unused-argument
*) ()))
467 (assert-backtrace (lambda () (bt.7.2 :key
:value
))
468 `(((bt.7.2 :key
,*unused-argument
*) ()))
470 (assert-backtrace (lambda () (bt.7.3 :key
:value
))
471 `(((bt.7.3 :key
,*unused-argument
*) ()))
473 (assert-backtrace (lambda () (bt.7.1 :key
:value
))
474 `((bt.7.1 :key
,*unused-argument
*)))
475 (assert-backtrace (lambda () (bt.7.2 :key
:value
))
476 `((bt.7.2 :key
,*unused-argument
*)))
477 (assert-backtrace (lambda () (bt.7.3 :key
:value
))
478 `((bt.7.3 :key
,*unused-argument
*))))
480 (defvar *compile-nil-error
*
481 (checked-compile '(lambda (x)
482 (cons (when x
(error "oops")) nil
))))
483 (defvar *compile-nil-non-tc
*
484 (checked-compile '(lambda (y)
485 (cons (funcall *compile-nil-error
* y
) nil
))))
486 (with-test (:name
(:backtrace compile nil
))
487 (assert-backtrace (lambda () (funcall *compile-nil-non-tc
* 13))
488 `(((lambda (x) :in
,*p
*) 13)
489 ((lambda (y) :in
,*p
*) 13))))
491 (with-test (:name
(:backtrace
:clos-slot-typecheckfun-named
))
495 (locally (declare (optimize safety
))
496 (defclass clos-typecheck-test
()
497 ((slot :type fixnum
)))
498 (setf (slot-value (make-instance 'clos-typecheck-test
) 'slot
) t
))))
499 '(((sb-pcl::slot-typecheck fixnum
) t
))))
501 (with-test (:name
(:backtrace
:clos-emf-named
))
506 (defgeneric clos-emf-named-test
(x)
507 (:method
((x symbol
)) x
)
508 (:method
:before
(x) (assert x
)))
509 (clos-emf-named-test nil
)))
510 :allow-style-warnings t
)
511 '(((sb-pcl::emf clos-emf-named-test
) ? ? nil
))))
513 (with-test (:name
(:backtrace
:bug-310173
))
515 (let* ((names '(a b
))
516 (req (loop repeat n collect
(pop names
))))
518 `(lambda (,@req
&rest rest
)
519 (let ((* *)) ; no tail-call
520 (apply '/ ,@req rest
)))))))
521 (assert-backtrace (lambda ()
522 (funcall (make-fun 0) 10 11 0))
523 `((sb-kernel:two-arg-
/ 10/11 0)
525 ((lambda (&rest rest
) :in
,*p
*) 10 11 0)))
526 (assert-backtrace (lambda ()
527 (funcall (make-fun 1) 10 11 0))
528 `((sb-kernel:two-arg-
/ 10/11 0)
530 ((lambda (a &rest rest
) :in
,*p
*) 10 11 0)))
531 (assert-backtrace (lambda ()
532 (funcall (make-fun 2) 10 11 0))
533 `((sb-kernel:two-arg-
/ 10/11 0)
535 ((lambda (a b
&rest rest
) :in
,*p
*) 10 11 0)))))
537 (defgeneric gf-dispatch-test
/gf
(x y
)
540 (defun gf-dispatch-test/f
(z)
541 (declare (muffle-conditions style-warning
))
542 (gf-dispatch-test/gf z
))
543 (with-test (:name
(:backtrace
:gf-dispatch
))
545 (gf-dispatch-test/gf
1 1)
546 ;; Wrong argument count
547 (assert-backtrace (lambda () (gf-dispatch-test/f
42))
548 '(((sb-pcl::gf-dispatch gf-dispatch-test
/gf
) 42))))
550 (with-test (:name
(:backtrace
:local-tail-call
))
552 (lambda () (funcall (compile nil
`(sb-int:named-lambda test
()
555 (declare (notinline tail
))
559 (defun fact (n) (if (zerop n
) (error "nope") (* n
(fact (1- n
)))))
562 (with-test (:name
(:backtrace
:interpreted-factorial
)
563 :skipped-on
'(not :interpreter
))
567 (sb-interpreter::2-arg-
* &rest
)
569 (sb-interpreter::2-arg-
* &rest
)
571 (sb-interpreter::2-arg-
* &rest
)
573 (sb-interpreter::2-arg-
* &rest
)
575 (sb-interpreter::2-arg-
* &rest
)
578 (with-test (:name
:deleted-args
)
579 (let ((fun (checked-compile `(lambda (&rest ignore
)
580 (declare (ignore ignore
))
582 (assert (typep (block nil
583 (handler-bind ((error
586 (sb-debug:list-backtrace
))))))
590 (defun mega-string-replace-fail (x)
591 (let ((string (make-string 10000 :initial-element
#\z
))
592 (stream (make-string-output-stream)))
595 ((condition (lambda (c)
597 (sb-debug:print-backtrace
:stream stream
)
600 (get-output-stream-string stream
)))
602 (with-test (:name
:long-string-abbreviation
)
603 (let ((backtrace (mega-string-replace-fail '(#\-
1))))
604 (assert (search (concatenate 'string
606 (make-string 49 :initial-element
#\z
)