mirror of
https://github.com/tinygo-org/tinygo.git
synced 2026-08-15 16:33:40 +00:00
runtime: add Windows vectored exception handler for recoverable panics
Register a vectored exception handler at startup so Windows hardware exceptions can be translated into Go panics. Access violations become nil pointer panics, and integer divide-by-zero exceptions become divide by zero panics, allowing defer/recover to handle them like ordinary runtime panics.
This commit is contained in:
@@ -485,6 +485,8 @@ func defaultTarget(options *Options) (*TargetSpec, error) {
|
|||||||
"--no-insert-timestamp",
|
"--no-insert-timestamp",
|
||||||
"--no-dynamicbase",
|
"--no-dynamicbase",
|
||||||
)
|
)
|
||||||
|
spec.ExtraFiles = append(spec.ExtraFiles,
|
||||||
|
"src/runtime/runtime_windows.c")
|
||||||
case "wasm", "wasip1", "wasip2":
|
case "wasm", "wasip1", "wasip2":
|
||||||
return nil, fmt.Errorf("GOOS=%s but GOARCH is unset. Please set GOARCH to wasm", options.GOOS)
|
return nil, fmt.Errorf("GOOS=%s but GOARCH is unset. Please set GOARCH to wasm", options.GOOS)
|
||||||
default:
|
default:
|
||||||
|
|||||||
@@ -0,0 +1,29 @@
|
|||||||
|
//go:build none
|
||||||
|
|
||||||
|
// This file is included on Windows (despite the //go:build line above).
|
||||||
|
|
||||||
|
#include <windows.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
void tinygo_sigpanic_windows(int32_t exception_code);
|
||||||
|
|
||||||
|
static LONG WINAPI tinygo_exception_handler(EXCEPTION_POINTERS *info) {
|
||||||
|
DWORD code = info->ExceptionRecord->ExceptionCode;
|
||||||
|
switch (code) {
|
||||||
|
case EXCEPTION_ACCESS_VIOLATION:
|
||||||
|
case EXCEPTION_IN_PAGE_ERROR:
|
||||||
|
case EXCEPTION_INT_DIVIDE_BY_ZERO:
|
||||||
|
case EXCEPTION_INT_OVERFLOW:
|
||||||
|
tinygo_sigpanic_windows((int32_t)code);
|
||||||
|
// If runtimePanic triggers longjmp, we never reach here.
|
||||||
|
// If it doesn't (no defer frame), it will abort and we also
|
||||||
|
// never reach here.
|
||||||
|
return EXCEPTION_CONTINUE_SEARCH;
|
||||||
|
default:
|
||||||
|
return EXCEPTION_CONTINUE_SEARCH;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void tinygo_init_exception_handler(void) {
|
||||||
|
AddVectoredExceptionHandler(1, tinygo_exception_handler);
|
||||||
|
}
|
||||||
@@ -60,6 +60,10 @@ func mainCRTStartup() int {
|
|||||||
_QueryPerformanceFrequency(&performanceFrequency)
|
_QueryPerformanceFrequency(&performanceFrequency)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Register vectored exception handler so that access violations and
|
||||||
|
// divide-by-zero exceptions can be recovered with defer/recover.
|
||||||
|
tinygo_init_exception_handler()
|
||||||
|
|
||||||
// Obtain the initial stack pointer right before calling the run() function.
|
// Obtain the initial stack pointer right before calling the run() function.
|
||||||
// The run function has been moved to a separate (non-inlined) function so
|
// The run function has been moved to a separate (non-inlined) function so
|
||||||
// that the correct stack pointer is read.
|
// that the correct stack pointer is read.
|
||||||
@@ -294,3 +298,27 @@ func hardwareRand() (n uint64, ok bool) {
|
|||||||
//
|
//
|
||||||
//export SystemFunction036
|
//export SystemFunction036
|
||||||
func _RtlGenRandom(buf unsafe.Pointer, len int) bool
|
func _RtlGenRandom(buf unsafe.Pointer, len int) bool
|
||||||
|
|
||||||
|
const (
|
||||||
|
_EXCEPTION_ACCESS_VIOLATION = 0xC0000005
|
||||||
|
_EXCEPTION_IN_PAGE_ERROR = 0xC0000006
|
||||||
|
_EXCEPTION_INT_DIVIDE_BY_ZERO = 0xC0000094
|
||||||
|
_EXCEPTION_INT_OVERFLOW = 0xC0000095
|
||||||
|
)
|
||||||
|
|
||||||
|
//export tinygo_init_exception_handler
|
||||||
|
func tinygo_init_exception_handler()
|
||||||
|
|
||||||
|
//export tinygo_sigpanic_windows
|
||||||
|
func tinygo_sigpanic_windows(exceptionCode int32) {
|
||||||
|
switch uint32(exceptionCode) {
|
||||||
|
case _EXCEPTION_ACCESS_VIOLATION, _EXCEPTION_IN_PAGE_ERROR:
|
||||||
|
runtimePanic("nil pointer dereference")
|
||||||
|
case _EXCEPTION_INT_DIVIDE_BY_ZERO:
|
||||||
|
runtimePanic("divide by zero")
|
||||||
|
case _EXCEPTION_INT_OVERFLOW:
|
||||||
|
runtimePanic("integer overflow")
|
||||||
|
default:
|
||||||
|
runtimePanic("unknown exception")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user