mirror of
https://github.com/tinygo-org/tinygo.git
synced 2026-08-03 02:27:48 +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-dynamicbase",
|
||||
)
|
||||
spec.ExtraFiles = append(spec.ExtraFiles,
|
||||
"src/runtime/runtime_windows.c")
|
||||
case "wasm", "wasip1", "wasip2":
|
||||
return nil, fmt.Errorf("GOOS=%s but GOARCH is unset. Please set GOARCH to wasm", options.GOOS)
|
||||
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)
|
||||
}
|
||||
|
||||
// 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.
|
||||
// The run function has been moved to a separate (non-inlined) function so
|
||||
// that the correct stack pointer is read.
|
||||
@@ -294,3 +298,27 @@ func hardwareRand() (n uint64, ok bool) {
|
||||
//
|
||||
//export SystemFunction036
|
||||
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