+;; unconditional, in case either previous left it enabled
+(disable-debugger)
+\f
+;;;; test some limitations of MAKE-LISP-OBJ
+
+;;; Older GENCGC systems had a bug in the pointer validation used by
+;;; MAKE-LISP-OBJ that made SIMPLE-FUN objects always fail to
+;;; validate.
+(with-test (:name (:make-lisp-obj :simple-funs))
+ (sb-sys:without-gcing
+ (assert (eq #'identity
+ (sb-kernel:make-lisp-obj
+ (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)))
+ #+nil
+ (format *error-output* "Looking for: ~A~%" text)
+ (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)))))
+
+(defgeneric gf-dispatch-test/gf (x y)
+ (:method (x y)
+ (+ x y)))
+(defun gf-dispatch-test/f (z)
+ (gf-dispatch-test/gf z))
+
+(with-test (:name :gf-dispatch-backtrace)
+ ;; Fill the cache
+ (gf-dispatch-test/gf 1 1)
+ ;; Wrong argument count
+ (assert (verify-backtrace (lambda () (gf-dispatch-test/f 42))
+ '(((sb-pcl::gf-dispatch gf-dispatch-test/gf) 42)))))
+
+(with-test (:name (:xep-arglist-clean-up :bug-1192929))
+ (assert
+ (block nil
+ (handler-bind ((error (lambda (e)
+ (declare (ignore e))
+ (return (< (length (car (sb-debug:backtrace-as-list 1))) 10)))))
+ (funcall (compile nil `(lambda (i) (declare ((mod 65536) i)) i)) nil)))))
+
+(write-line "/debug.impure.lisp done")