fix source information for functions from EVAL
[sbcl.git] / tests / debug.impure.lisp
index 9d8c34b..b902b74 100644 (file)
 
 ;;; The debugger doesn't have any native knowledge of the interpreter
 (when (eq sb-ext:*evaluator-mode* :interpret)
-  (sb-ext:quit :unix-status 104))
+  (sb-ext:exit :code 104))
 
 \f
 ;;;; Check that we get debug arglists right.
 
+(defvar *p* (namestring *load-truename*))
+
 ;;; FIXME: This should use some get-argslist like functionality that
 ;;; we actually export.
 ;;;
 
 (defvar *undefined-function-frame*
   ;; bug 353
-  '(#+(or x86 x86-64) "bogus stack frame"
-    #-(or x86 x86-64) "undefined function"))
+  '("undefined function"))
 
 ;;; Test for "undefined function" (undefined_tramp) working properly.
 ;;; Try it with and without tail call elimination, since they can have
          (funcall fun)))
 
   (with-test (:name (:undefined-function :bug-346)
-              :fails-on '(or :alpha :ppc :sparc :mips
+                    ;; Failures on ALPHA, SPARC, MIPS, and probably
+                    ;; HPPA are due to not having a full and valid
+                    ;; stack frame for the undefined function frame.
+                    ;; See PPC undefined_tramp for details.
+              :fails-on '(or :alpha :sparc :mips
                           (and :x86-64 :freebsd)))
     (assert (verify-backtrace
              (lambda () (test #'optimized))
              (list *undefined-function-frame*
-                   (list '(flet test) #'optimized)))))
+                   (list `(flet test :in ,*p*) #'optimized)))))
 
   ;; bug 353: This test fails at least most of the time for x86/linux
   ;; ca. 0.8.20.16. -- WHN
-  (with-test (:name (:undefined-function :bug-353)
-              ;; This used to have fewer :fails-on features pre-0.9.16.38,
-              ;; but it turns out that the bug was just being masked by
-              ;; the presence of the IR1 stepper instrumentation (and
-              ;; is thus again failing now that the instrumentation is
-              ;; no more).
-              :fails-on '(or :alpha :mips :ppc))
+  (with-test (:name (:undefined-function :bug-353))
     (assert (verify-backtrace
              (lambda () (test #'not-optimized))
              (list *undefined-function-frame*
-                   (list '(flet not-optimized))
-                   (list '(flet test) #'not-optimized))))))
+                   (list `(flet not-optimized :in ,*p*))
+                   (list `(flet test :in ,*p*) #'not-optimized))))))
 
 (with-test (:name :backtrace-interrupted-condition-wait
             :skipped-on '(not :sb-thread)
                   ;; :TIMEOUT NIL to the frame we expect. If we leave it out,
                   ;; the backtrace is fine -- but the test fails. I can only
                   ;; boggle right now.
-            :fails-on :darwin)
+            :fails-on '(or (and :x86 :linux) :darwin))
   (let ((m (sb-thread:make-mutex))
         (q (sb-thread:make-waitqueue)))
     (assert (verify-backtrace
               :fails-on :alpha)  ; bug 346
     (assert (verify-backtrace (lambda () (test #'optimized))
                               (list '(/ 42 &rest)
-                                    (list '(flet test) #'optimized)))))
+                                    (list `(flet test :in ,*p*) #'optimized)))))
   (with-test (:name (:divide-by-zero :bug-356)
               :fails-on :alpha)  ; bug 356
     (assert (verify-backtrace (lambda () (test #'not-optimized))
                               (list '(/ 42 &rest)
-                                    '((flet not-optimized))
-                                    (list '(flet test) #'not-optimized))))))
+                                    `((flet not-optimized :in ,*p*))
+                                    (list `(flet test :in ,*p*) #'not-optimized))))))
 
 (with-test (:name (:throw :no-such-tag)
             :fails-on '(or
       (throw 'no-such-tag t))
     (assert (verify-backtrace #'throw-test '((throw-test))))))
 
+(defun bug-308926 (x)
+  (let ((v "foo"))
+    (flet ((bar (z)
+             (oops v z)
+             (oops z v)))
+      (bar x)
+      (bar v))))
+
+(with-test (:name :bug-308926)
+  (assert (verify-backtrace (lambda () (bug-308926 13))
+                            '(((flet bar :in bug-308926) 13)
+                              (bug-308926 &rest t)))))
+
 ;;; test entry point handling in backtraces
 
 (defun oops ()
   (error "oops"))
 
+(with-test (:name :xep-too-many-arguments)
+  (assert (verify-backtrace (lambda () (oops 1 2 3 4 5 6))
+                            '((oops ? ? ? ? ? ?)))))
+
 (defmacro defbt (n ll &body body)
-  `(progn
-     ;; normal debug info
-     (defun ,(intern (format nil "BT.~A.1" n)) ,ll
-       ,@body)
-     ;; no arguments saved
-     (defun ,(intern (format nil "BT.~A.2" n)) ,ll
-       (declare (optimize (debug 1) (speed 3)))
-       ,@body)
-     ;; no lambda-list saved
-     (defun ,(intern (format nil "BT.~A.3" n)) ,ll
-       (declare (optimize (debug 0)))
-       ,@body)))
+  ;; WTF is this? This is a way to make these tests not depend so much on the
+  ;; details of LOAD/EVAL. Around 1.0.57 we changed %SIMPLE-EVAL to be
+  ;; slightly smarter, which meant that things which used to have xeps
+  ;; suddently had tl-xeps, etc. This takes care of that.
+  `(funcall
+    (compile nil
+             '(lambda ()
+               (progn
+                 ;; normal debug info
+                 (defun ,(intern (format nil "BT.~A.1" n)) ,ll
+                   ,@body)
+                 ;; no arguments saved
+                 (defun ,(intern (format nil "BT.~A.2" n)) ,ll
+                   (declare (optimize (debug 1) (speed 3)))
+                   ,@body)
+                 ;; no lambda-list saved
+                 (defun ,(intern (format nil "BT.~A.3" n)) ,ll
+                   (declare (optimize (debug 0)))
+                   ,@body))))))
 
 (defbt 1 (&key key)
   (list key))
 (defvar *compile-nil-non-tc* (compile nil '(lambda (y) (cons (funcall *compile-nil-error* y) nil))))
 (with-test (:name (:compile nil))
   (assert (verify-backtrace (lambda () (funcall *compile-nil-non-tc* 13))
-                            '(((lambda (x)) 13)
-                              ((lambda (y)) 13)))))
+                            `(((lambda (x) :in ,*p*) 13)
+                              ((lambda (y) :in ,*p*) 13)))))
 
 (with-test (:name :clos-slot-typecheckfun-named)
   (assert
     (assert
      (verify-backtrace (lambda ()
                          (funcall (make-fun 0) 10 11 0))
-                       '((sb-kernel:two-arg-/ 10/11 0)
+                       `((sb-kernel:two-arg-/ 10/11 0)
                          (/ 10 11 0)
-                         ((lambda (&rest rest)) 10 11 0))))
+                         ((lambda (&rest rest) :in ,*p*) 10 11 0))))
     (assert
      (verify-backtrace (lambda ()
                          (funcall (make-fun 1) 10 11 0))
-                       '((sb-kernel:two-arg-/ 10/11 0)
+                       `((sb-kernel:two-arg-/ 10/11 0)
                          (/ 10 11 0)
-                         ((lambda (a &rest rest)) 10 11 0))))
+                         ((lambda (a &rest rest) :in ,*p*) 10 11 0))))
     (assert
      (verify-backtrace (lambda ()
                          (funcall (make-fun 2) 10 11 0))
-                       '((sb-kernel:two-arg-/ 10/11 0)
+                       `((sb-kernel:two-arg-/ 10/11 0)
                          (/ 10 11 0)
-                         ((lambda (a b &rest rest)) 10 11 0))))))
+                         ((lambda (a b &rest rest) :in ,*p*) 10 11 0))))))
 
 ;;;; test TRACE
 
       (declare (notinline dx-arg-backtrace))
       (assert (member-if (lambda (frame)
                            (and (consp frame)
-                                (equal '(flet dx-arg-backtrace) (car frame))
+                                (consp (car frame))
+                                (equal '(flet dx-arg-backtrace :in) (butlast (car frame)))
                                 (notany #'sb-debug::stack-allocated-p (cdr frame))))
                          (dx-arg-backtrace dx-arg))))))
 
                  (sb-kernel:get-lisp-obj-address
                   #'identity))))))
 
+;;; Older CHENEYGC systems didn't perform any real pointer validity
+;;; checks beyond "is this pointer to somewhere in heap space".
+(with-test (:name (make-lisp-obj :pointer-validation))
+  ;; Fun and games: We need to test MAKE-LISP-OBJ with a known-bogus
+  ;; address, but we also need the GC to not pitch a fit if it sees an
+  ;; object with said bogus address.  Thus, construct our known-bogus
+  ;; object within an area of unboxed storage (a vector) in static
+  ;; space.  We'll make it a simple object, (CONS 0 0), which has an
+  ;; in-memory representation of two consecutive zero words.  We
+  ;; allocate a three-word vector so that we can guarantee a
+  ;; double-word aligned double-word of zeros no matter what happens
+  ;; with the vector-data-offset (currently double-word aligned).
+  (let* ((memory (sb-int:make-static-vector 3 :element-type `(unsigned-byte ,sb-vm:n-word-bits)
+                                            :initial-element 0))
+         (vector-data-address (sb-sys:sap-int (sb-kernel::vector-sap memory)))
+         (object-base-address (logandc2 (+ vector-data-address sb-vm:lowtag-mask) sb-vm:lowtag-mask))
+         (object-tagged-address (+ object-base-address sb-vm:list-pointer-lowtag)))
+    (multiple-value-bind (object valid-p)
+        (sb-kernel:make-lisp-obj object-tagged-address nil)
+      (declare (ignore object))
+      (assert (not valid-p)))))
+
+(defun test-debugger (control form &rest targets)
+  (let ((out (make-string-output-stream))
+        (oops t))
+    (unwind-protect
+         (progn
+           (with-simple-restart (debugger-test-done! "Debugger Test Done!")
+             (let* ((*debug-io* (make-two-way-stream
+                                 (make-string-input-stream control)
+                                 (make-broadcast-stream out #+nil *standard-output*)))
+                    ;; Initial announcement goes to *ERROR-OUTPUT*
+                    (*error-output* *debug-io*)
+                    (*invoke-debugger-hook* nil))
+               (handler-bind ((error #'invoke-debugger))
+                 (eval form))))
+           (setf oops nil))
+      (when oops
+        (error "Uncontrolled unwind from debugger test.")))
+    ;; For sanity's sake this is outside the *debug-io* rebinding -- otherwise
+    ;; it could swallow our asserts!
+    (with-input-from-string (s (get-output-stream-string out))
+      (loop for line = (read-line s nil)
+            while line
+            do (assert targets)
+               #+nil
+               (format *error-output* "Got: ~A~%" line)
+               (let ((match (pop targets)))
+                 (if (eq '* match)
+                     ;; Whatever, till the next line matches.
+                     (let ((text (pop targets)))
+                       (unless (search text line)
+                         (push text targets)
+                         (push match targets)))
+                     (unless (search match line)
+                       (format *error-output* "~&Wanted: ~S~%   Got: ~S~%" match line)
+                       (setf oops t))))))
+    ;; Check that we saw everything we wanted
+    (when targets
+      (error "Missed: ~S" targets))
+    (assert (not oops))))
+
+(with-test (:name (:debugger :source 1))
+  (test-debugger
+   "d
+    source 0
+    debugger-test-done!"
+   `(progn
+      (defun this-will-break (x)
+               (declare (optimize debug))
+               (let* ((y (- x x))
+                      (z (/ x y)))
+                 (+ x z)))
+      (this-will-break 1))
+   '*
+   "debugger invoked"
+   '*
+   "DIVISION-BY-ZERO"
+   "operands (1 0)"
+   '*
+   "INTEGER-/-INTEGER"
+   "(THIS-WILL-BREAK 1)"
+   "1]"
+   "(/ X Y)"
+   "1]"))
+
+(with-test (:name (:debugger :source 2))
+  (test-debugger
+   "d
+    source 0
+    debugger-test-done!"
+   `(locally (declare (optimize (speed 0) (safety 3) (debug 3)))
+      (let ((f #'(lambda (x cont)
+                   (print x (make-broadcast-stream))
+                   (if (zerop x)
+                       (error "foo")
+                       (funcall cont (1- x) cont)))))
+        (funcall f 10 f)))
+   '*
+   "debugger"
+   '*
+   "foo"
+   '*
+   "source: (ERROR \"foo\")"
+   '*
+   "(LAMBDA (X CONT)"
+   '*
+   "(FUNCALL CONT (1- X) CONT)"
+   "1]"))
+
+(with-test (:name (disassemble :high-debug-eval))
+  (eval `(defun this-will-be-disassembled (x)
+           (declare (optimize debug))
+           (+ x x)))
+  (let* ((oopses (make-string-output-stream))
+         (disassembly
+           (let ((*error-output* oopses))
+             (with-output-to-string (*standard-output*)
+               (disassemble 'this-will-be-disassembled)))))
+    (with-input-from-string (s disassembly)
+      (assert (search "; disassembly for THIS-WILL-BE-DISASSEMBLED"
+                      (read-line s))))
+    (let ((problems (get-output-stream-string oopses)))
+      (unless (zerop (length problems))
+        (error problems)))))
+
+(defun this-too-will-be-disasssembled (x)
+  (declare (optimize debug))
+  (+ x x))
+
+(with-test (:name (disassemble :high-debug-load))
+  (let* ((oopses (make-string-output-stream))
+         (disassembly
+           (let ((*error-output* oopses))
+             (with-output-to-string (*standard-output*)
+               (disassemble 'this-too-will-be-disasssembled)))))
+    (with-input-from-string (s disassembly)
+      (assert (equal "; disassembly for THIS-TOO-WILL-BE-DISASSSEMBLED"
+                     (read-line s))))
+    (let ((problems (get-output-stream-string oopses)))
+      (unless (zerop (length problems))
+        (error problems)))))
+
 (write-line "/debug.impure.lisp done")