mirror of
git://git.code.sf.net/p/sbcl/sbcl
synced 2026-09-10 07:26:40 -04:00
Some checks failed
Linux qemu / ppc64le (push) Failing after 1s
Linux arm / build (push) Has been cancelled
CL-host / ecl (push) Has been cancelled
CL-host / clisp (push) Has been cancelled
CL-host / ccl (push) Has been cancelled
CL-host / cmucl (push) Has been cancelled
CL-host / sbcl (push) Has been cancelled
Linux arm64 / build (--with-sb-thread) (push) Has been cancelled
Linux / build (x86, --with-sb-thread, ) (push) Has been cancelled
Linux / build (x86, --without-sb-thread, ) (push) Has been cancelled
Linux / build (x86, --without-sb-unicode, ) (push) Has been cancelled
Linux / build (x86-64, --with-mark-region-gc) (push) Has been cancelled
Linux / build (x86-64, --with-sb-fasteval --without-sb-eval, fasteval) (push) Has been cancelled
Linux / build (x86-64, --with-sb-thread, ) (push) Has been cancelled
Linux / build (x86-64, --with-sb-thread, sse4) (push) Has been cancelled
Linux / build (x86-64, --without-sb-thread, ) (push) Has been cancelled
Linux / build (x86-64, --without-sb-unicode, ) (push) Has been cancelled
Mac / build (--without-sb-thread, x86-64) (push) Has been cancelled
Mac / build (arm64, --with-mark-region-gc) (push) Has been cancelled
Mac / build (arm64, --with-sb-thread) (push) Has been cancelled
Mac / build (x86-64, --with-mark-region-gc) (push) Has been cancelled
Mac / build (x86-64, --with-sb-thread) (push) Has been cancelled
Windows / build (push) Has been cancelled
CL-host / compare-xc-host-fasls (ccl, false) (push) Has been cancelled
CL-host / compare-xc-host-fasls (clisp, false) (push) Has been cancelled
CL-host / compare-xc-host-fasls (cmucl, false) (push) Has been cancelled
CL-host / compare-xc-host-fasls (self, false) (push) Has been cancelled
THere's no special being bound there anymore.
194 lines
7.4 KiB
Common Lisp
194 lines
7.4 KiB
Common Lisp
;;;; Testing the behavior of foreign calls trying to unwind the stack. Uses win32-stack-unwind.c.
|
|
|
|
;;;; This software is part of the SBCL system. See the README file for
|
|
;;;; more information.
|
|
;;;;
|
|
;;;; While most of SBCL is derived from the CMU CL system, the test
|
|
;;;; files (like this one) were written from scratch after the fork
|
|
;;;; from CMU CL.
|
|
;;;;
|
|
;;;; This software is in the public domain and is provided with
|
|
;;;; absolutely no warranty. See the COPYING and CREDITS files for
|
|
;;;; more information.
|
|
|
|
#-win32 (invoke-restart 'run-tests::skip-file) ;; This is extremely win32-specific.
|
|
#-x86 (invoke-restart 'run-tests::skip-file) ;; And our AMD64 backend does not aim to support it.
|
|
|
|
(use-package :sb-alien)
|
|
|
|
;;; XXX XXX this should change to use run-compiler.sh, now that we have it
|
|
(defun run-compiler ()
|
|
(let ((proc (run-program "gcc" '("win32-stack-unwind.c" "-shared"
|
|
"-o" "win32-stack-unwind.dll")
|
|
:search t)))
|
|
(unless (zerop (process-exit-code proc))
|
|
(error "Bad exit code: ~S"
|
|
(process-exit-code proc)))))
|
|
|
|
(run-compiler)
|
|
|
|
(load-shared-object (truename "win32-stack-unwind.dll"))
|
|
|
|
(defun establish-return-frame (callback)
|
|
"Establish an SEH frame for use as a target with PERFORM-TEST-UNWIND and invoke CALLBACK via FUNCALL"
|
|
(with-alien-callable ((test void ()
|
|
(funcall callback)))
|
|
(alien-funcall (extern-alien "establish_return_frame"
|
|
(function void (* (function void))))
|
|
(alien-sap test)))
|
|
(values))
|
|
|
|
(defun perform-test-unwind ()
|
|
"Perform an RtlUnwind to the surrounding ESTABLISH-RETURN-FRAME frame."
|
|
(alien-funcall (extern-alien "perform_test_unwind" (function void))))
|
|
|
|
|
|
;;; An attempt to detect and clean up latent fatalities in the
|
|
;;; post-test environent.
|
|
|
|
(defmacro with-test-environment (args &body body)
|
|
(declare (ignore args))
|
|
(let ((old-bsp (gensym))
|
|
(old-cuwp (gensym))
|
|
(old-ccb (gensym))
|
|
(old-asp (gensym)))
|
|
`(let ((*standard-input* *standard-input*))
|
|
(let ((,old-bsp (+ sb-vm::*binding-stack-pointer* 2))
|
|
(,old-cuwp sb-vm::*current-unwind-protect-block*)
|
|
(,old-ccb sb-vm:*current-catch-block*)
|
|
(,old-asp sb-vm::*alien-stack-pointer*))
|
|
(handler-case
|
|
(let ((result (progn ,@body))
|
|
extra-results)
|
|
(when (not (eql ,old-bsp sb-vm::*binding-stack-pointer*))
|
|
#+(or)
|
|
(format t "~A ~A~%" ,old-bsp sb-vm::*binding-stack-pointer*)
|
|
(push :bsp-fail extra-results))
|
|
(when (not (eql ,old-cuwp sb-vm::*current-unwind-protect-block*))
|
|
(push :cuwp-fail extra-results))
|
|
(when (not (eql ,old-ccb sb-vm:*current-catch-block*))
|
|
(push :ccb-fail extra-results))
|
|
(when (not (eql ,old-asp sb-vm::*alien-stack-pointer*))
|
|
(push :asp-fail extra-results))
|
|
(setf sb-vm::*current-unwind-protect-block* ,old-cuwp)
|
|
(setf sb-vm:*current-catch-block* ,old-ccb)
|
|
(setf sb-vm::*alien-stack-pointer* ,old-asp)
|
|
(list* result extra-results))
|
|
(error ()
|
|
:error))))))
|
|
|
|
|
|
;;; Test cases.
|
|
|
|
(with-test (:name #1=:base-case)
|
|
;; Tests that the unwind test machinery works.
|
|
(let ((result
|
|
(with-test-environment ()
|
|
(establish-return-frame (lambda () (perform-test-unwind)))
|
|
:success)))
|
|
(format t "~S result: ~S~%" #1# result)
|
|
(assert (eql :success (car result)))))
|
|
|
|
(with-test (:name #1=:special-binding)
|
|
;; Tests that special bindings are undone properly during
|
|
;; unwind.
|
|
(let ((result
|
|
(with-test-environment ()
|
|
(let ((foo :success))
|
|
(declare (special foo))
|
|
(establish-return-frame (lambda ()
|
|
(let ((foo nil))
|
|
(declare (special foo))
|
|
(perform-test-unwind))))
|
|
foo))))
|
|
(format t "~S result: ~S~%" #1# result)
|
|
(assert (eql :success (car result)))))
|
|
|
|
(with-test (:name #1=:unwind-protect)
|
|
;; Tests that unwind-protect forms are run during unwind.
|
|
(let ((result
|
|
(with-test-environment ()
|
|
(let (result)
|
|
(establish-return-frame (lambda ()
|
|
(unwind-protect
|
|
(perform-test-unwind)
|
|
(setf result :success))))
|
|
result))))
|
|
(format t "~S result: ~S~%" #1# result)
|
|
(assert (eql :success (car result)))))
|
|
|
|
(with-test (:name #1=:unwind-protect-nlx)
|
|
;; Tests that unwind-protect forms that are run during unwind
|
|
;; can do a non-local exit to abort the unwind.
|
|
(let ((result
|
|
(with-test-environment ()
|
|
(let (result)
|
|
(establish-return-frame (lambda ()
|
|
(block nil
|
|
(unwind-protect
|
|
(perform-test-unwind)
|
|
(return)))
|
|
(setf result :success)))
|
|
result))))
|
|
(format t "~S result: ~S~%" #1# result)
|
|
(assert (eql :success (car result)))))
|
|
|
|
(with-test (:name #1=:no-unwind)
|
|
;; Basic smoke test of establish-return-frame.
|
|
(let ((result
|
|
(with-test-environment ()
|
|
(establish-return-frame (lambda ()))
|
|
:success)))
|
|
(format t "~S result: ~S~%" #1# result)
|
|
(assert (eql :success (car result)))))
|
|
|
|
(with-test (:name #1=:no-unwind-error)
|
|
;; Tests that EXCEPTION_BREAKPOINT is caught and handled
|
|
;; correctly within callbacks.
|
|
(let ((result
|
|
(with-test-environment ()
|
|
(establish-return-frame (lambda ()
|
|
(handler-case
|
|
(some-undefined-function)
|
|
(undefined-function ()))))
|
|
:success)))
|
|
(format t "~S result: ~S~%" #1# result)
|
|
(assert (eql :success (car result)))))
|
|
|
|
(with-test (:name #1=:unwind-foreign-frame)
|
|
;; Tests that unwinding a foreign SEH frame isn't completely
|
|
;; broken.
|
|
(let ((result
|
|
(with-test-environment ()
|
|
(block nil
|
|
(establish-return-frame (lambda () (return :success)))))))
|
|
(format t "~S result: ~S~%" #1# result)
|
|
(assert (eql :success (car result)))))
|
|
|
|
(with-test (:name #1=:unwind-protect-unwind-foreign-frame)
|
|
;; Tests that an unwind-protect block is allowed to unwind
|
|
;; past the original unwind target.
|
|
(let ((result
|
|
(with-test-environment ()
|
|
(block nil
|
|
(establish-return-frame (lambda ()
|
|
(unwind-protect
|
|
(perform-test-unwind)
|
|
(return :success))))))))
|
|
(format t "~S result: ~S~%" #1# result)
|
|
(assert (eql :success (car result)))))
|
|
|
|
(with-test (:name #1=:unwind-error)
|
|
;; Another test for unwinding an SEH frame.
|
|
(let ((result
|
|
(with-test-environment ()
|
|
(handler-case
|
|
(establish-return-frame (lambda ()
|
|
(error "Foo!")))
|
|
(error ()
|
|
:success)))))
|
|
(format t "~S result: ~S~%" #1# result)
|
|
(assert (eql :success (car result)))))
|
|
|
|
;;;; success!
|