mirror of
https://github.com/golang/go
synced 2024-11-19 06:04:39 -07:00
undo CL 145150043 / 8b3d26697b8d
That was complete failure - builders are broken, but original cl worked fine on my system. I will need access to builders to test this change properly. ««« original CL description runtime: handle all windows exception Fixes #8006. LGTM=rsc R=golang-codereviews, rsc CC=golang-codereviews https://golang.org/cl/145150043 »»» TBR=rsc R=golang-codereviews CC=golang-codereviews https://golang.org/cl/154180043
This commit is contained in:
parent
17a108ba07
commit
64736accdb
@ -59,9 +59,6 @@ const (
|
||||
|
||||
INFINITE = C.INFINITE
|
||||
WAIT_TIMEOUT = C.WAIT_TIMEOUT
|
||||
|
||||
EXCEPTION_CONTINUE_EXECUTION = C.EXCEPTION_CONTINUE_EXECUTION
|
||||
EXCEPTION_CONTINUE_SEARCH = C.EXCEPTION_CONTINUE_SEARCH
|
||||
)
|
||||
|
||||
type SystemInfo C.SYSTEM_INFO
|
||||
|
@ -32,9 +32,6 @@ enum {
|
||||
|
||||
INFINITE = 0xffffffff,
|
||||
WAIT_TIMEOUT = 0x102,
|
||||
|
||||
EXCEPTION_CONTINUE_EXECUTION = -0x1,
|
||||
EXCEPTION_CONTINUE_SEARCH = 0x0,
|
||||
};
|
||||
|
||||
typedef struct SystemInfo SystemInfo;
|
||||
|
@ -32,9 +32,6 @@ enum {
|
||||
|
||||
INFINITE = 0xffffffff,
|
||||
WAIT_TIMEOUT = 0x102,
|
||||
|
||||
EXCEPTION_CONTINUE_EXECUTION = -0x1,
|
||||
EXCEPTION_CONTINUE_SEARCH = 0x0,
|
||||
};
|
||||
|
||||
typedef struct SystemInfo SystemInfo;
|
||||
|
@ -34,7 +34,6 @@
|
||||
#pragma dynimport runtime·SetEvent SetEvent "kernel32.dll"
|
||||
#pragma dynimport runtime·SetProcessPriorityBoost SetProcessPriorityBoost "kernel32.dll"
|
||||
#pragma dynimport runtime·SetThreadPriority SetThreadPriority "kernel32.dll"
|
||||
#pragma dynimport runtime·SetUnhandledExceptionFilter SetUnhandledExceptionFilter "kernel32.dll"
|
||||
#pragma dynimport runtime·SetWaitableTimer SetWaitableTimer "kernel32.dll"
|
||||
#pragma dynimport runtime·Sleep Sleep "kernel32.dll"
|
||||
#pragma dynimport runtime·SuspendThread SuspendThread "kernel32.dll"
|
||||
@ -66,7 +65,6 @@ extern void *runtime·SetConsoleCtrlHandler;
|
||||
extern void *runtime·SetEvent;
|
||||
extern void *runtime·SetProcessPriorityBoost;
|
||||
extern void *runtime·SetThreadPriority;
|
||||
extern void *runtime·SetUnhandledExceptionFilter;
|
||||
extern void *runtime·SetWaitableTimer;
|
||||
extern void *runtime·Sleep;
|
||||
extern void *runtime·SuspendThread;
|
||||
@ -79,9 +77,7 @@ void *runtime·GetQueuedCompletionStatusEx;
|
||||
|
||||
extern uintptr runtime·externalthreadhandlerp;
|
||||
void runtime·externalthreadhandler(void);
|
||||
void runtime·exceptiontramp(void);
|
||||
void runtime·firstcontinuetramp(void);
|
||||
void runtime·lastcontinuetramp(void);
|
||||
void runtime·sigtramp(void);
|
||||
|
||||
#pragma textflag NOSPLIT
|
||||
uintptr
|
||||
@ -110,28 +106,12 @@ void
|
||||
runtime·osinit(void)
|
||||
{
|
||||
void *kernel32;
|
||||
void *addVectoredContinueHandler = nil;
|
||||
|
||||
kernel32 = runtime·stdcall1(runtime·LoadLibraryA, (uintptr)"kernel32.dll");
|
||||
|
||||
runtime·externalthreadhandlerp = (uintptr)runtime·externalthreadhandler;
|
||||
|
||||
runtime·stdcall2(runtime·AddVectoredExceptionHandler, 1, (uintptr)runtime·exceptiontramp);
|
||||
if(kernel32 != nil)
|
||||
addVectoredContinueHandler = runtime·stdcall2(runtime·GetProcAddress, (uintptr)kernel32, (uintptr)"AddVectoredContinueHandler");
|
||||
if(addVectoredContinueHandler == nil)
|
||||
// use SetUnhandledExceptionFilter if VectoredContinueHandler is unavailable.
|
||||
// note: SetUnhandledExceptionFilter handler won't be called, if debugging.
|
||||
runtime·stdcall1(runtime·SetUnhandledExceptionFilter, (uintptr)runtime·lastcontinuetramp);
|
||||
else {
|
||||
runtime·stdcall2(addVectoredContinueHandler, 1, (uintptr)runtime·firstcontinuetramp);
|
||||
runtime·stdcall2(addVectoredContinueHandler, 0, (uintptr)runtime·lastcontinuetramp);
|
||||
}
|
||||
|
||||
runtime·stdcall2(runtime·AddVectoredExceptionHandler, 1, (uintptr)runtime·sigtramp);
|
||||
runtime·stdcall2(runtime·SetConsoleCtrlHandler, (uintptr)runtime·ctrlhandler, 1);
|
||||
|
||||
runtime·stdcall1(runtime·timeBeginPeriod, 1);
|
||||
|
||||
runtime·ncpu = getproccount();
|
||||
|
||||
// Windows dynamic priority boosting assumes that a process has different types
|
||||
@ -140,6 +120,7 @@ runtime·osinit(void)
|
||||
// In such context dynamic priority boosting does nothing but harm, so we turn it off.
|
||||
runtime·stdcall2(runtime·SetProcessPriorityBoost, -1, 1);
|
||||
|
||||
kernel32 = runtime·stdcall1(runtime·LoadLibraryA, (uintptr)"kernel32.dll");
|
||||
if(kernel32 != nil) {
|
||||
runtime·GetQueuedCompletionStatusEx = runtime·stdcall2(runtime·GetProcAddress, (uintptr)kernel32, (uintptr)"GetQueuedCompletionStatusEx");
|
||||
}
|
||||
@ -494,14 +475,10 @@ runtime·issigpanic(uint32 code)
|
||||
void
|
||||
runtime·initsig(void)
|
||||
{
|
||||
// following line keeps these functions alive at link stage
|
||||
// following line keeps sigtramp alive at link stage
|
||||
// if there's a better way please write it here
|
||||
void *e = runtime·exceptiontramp;
|
||||
void *f = runtime·firstcontinuetramp;
|
||||
void *l = runtime·lastcontinuetramp;
|
||||
USED(e);
|
||||
USED(f);
|
||||
USED(l);
|
||||
void *p = runtime·sigtramp;
|
||||
USED(p);
|
||||
}
|
||||
|
||||
uint32
|
||||
|
@ -24,63 +24,45 @@ runtime·dumpregs(Context *r)
|
||||
runtime·printf("gs %x\n", r->SegGs);
|
||||
}
|
||||
|
||||
bool
|
||||
runtime·isgoexception(ExceptionRecord *info, Context *r)
|
||||
// Called by sigtramp from Windows VEH handler.
|
||||
// Return value signals whether the exception has been handled (-1)
|
||||
// or should be made available to other handlers in the chain (0).
|
||||
uint32
|
||||
runtime·sighandler(ExceptionRecord *info, Context *r, G *gp)
|
||||
{
|
||||
bool crash;
|
||||
uintptr *sp;
|
||||
extern byte runtime·text[], runtime·etext[];
|
||||
|
||||
// Only handle exception if executing instructions in Go binary
|
||||
// (not Windows library code).
|
||||
if(r->Eip < (uint32)runtime·text || (uint32)runtime·etext < r->Eip)
|
||||
return false;
|
||||
return 0;
|
||||
|
||||
if(!runtime·issigpanic(info->ExceptionCode))
|
||||
return false;
|
||||
if(gp != nil && runtime·issigpanic(info->ExceptionCode)) {
|
||||
// Make it look like a call to the signal func.
|
||||
// Have to pass arguments out of band since
|
||||
// augmenting the stack frame would break
|
||||
// the unwinding code.
|
||||
gp->sig = info->ExceptionCode;
|
||||
gp->sigcode0 = info->ExceptionInformation[0];
|
||||
gp->sigcode1 = info->ExceptionInformation[1];
|
||||
gp->sigpc = r->Eip;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Called by sigtramp from Windows VEH handler.
|
||||
// Return value signals whether the exception has been handled (EXCEPTION_CONTINUE_EXECUTION)
|
||||
// or should be made available to other handlers in the chain (EXCEPTION_CONTINUE_SEARCH).
|
||||
uint32
|
||||
runtime·exceptionhandler(ExceptionRecord *info, Context *r, G *gp)
|
||||
{
|
||||
uintptr *sp;
|
||||
|
||||
if(!runtime·isgoexception(info, r))
|
||||
return EXCEPTION_CONTINUE_SEARCH;
|
||||
|
||||
// Make it look like a call to the signal func.
|
||||
// Have to pass arguments out of band since
|
||||
// augmenting the stack frame would break
|
||||
// the unwinding code.
|
||||
gp->sig = info->ExceptionCode;
|
||||
gp->sigcode0 = info->ExceptionInformation[0];
|
||||
gp->sigcode1 = info->ExceptionInformation[1];
|
||||
gp->sigpc = r->Eip;
|
||||
|
||||
// Only push runtime·sigpanic if r->eip != 0.
|
||||
// If r->eip == 0, probably panicked because of a
|
||||
// call to a nil func. Not pushing that onto sp will
|
||||
// make the trace look like a call to runtime·sigpanic instead.
|
||||
// (Otherwise the trace will end at runtime·sigpanic and we
|
||||
// won't get to see who faulted.)
|
||||
if(r->Eip != 0) {
|
||||
sp = (uintptr*)r->Esp;
|
||||
*--sp = r->Eip;
|
||||
r->Esp = (uintptr)sp;
|
||||
// Only push runtime·sigpanic if r->eip != 0.
|
||||
// If r->eip == 0, probably panicked because of a
|
||||
// call to a nil func. Not pushing that onto sp will
|
||||
// make the trace look like a call to runtime·sigpanic instead.
|
||||
// (Otherwise the trace will end at runtime·sigpanic and we
|
||||
// won't get to see who faulted.)
|
||||
if(r->Eip != 0) {
|
||||
sp = (uintptr*)r->Esp;
|
||||
*--sp = r->Eip;
|
||||
r->Esp = (uintptr)sp;
|
||||
}
|
||||
r->Eip = (uintptr)runtime·sigpanic;
|
||||
return -1;
|
||||
}
|
||||
r->Eip = (uintptr)runtime·sigpanic;
|
||||
return EXCEPTION_CONTINUE_EXECUTION;
|
||||
}
|
||||
|
||||
// lastcontinuehandler is reached, because runtime cannot handle
|
||||
// current exception. lastcontinuehandler will print crash info and exit.
|
||||
uint32
|
||||
runtime·lastcontinuehandler(ExceptionRecord *info, Context *r, G *gp)
|
||||
{
|
||||
bool crash;
|
||||
|
||||
if(runtime·panicking) // traceback already printed
|
||||
runtime·exit(2);
|
||||
@ -106,7 +88,7 @@ runtime·lastcontinuehandler(ExceptionRecord *info, Context *r, G *gp)
|
||||
runtime·crash();
|
||||
|
||||
runtime·exit(2);
|
||||
return 0; // not reached
|
||||
return -1; // not reached
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -32,76 +32,45 @@ runtime·dumpregs(Context *r)
|
||||
runtime·printf("gs %X\n", (uint64)r->SegGs);
|
||||
}
|
||||
|
||||
bool
|
||||
runtime·isgoexception(ExceptionRecord *info, Context *r)
|
||||
// Called by sigtramp from Windows VEH handler.
|
||||
// Return value signals whether the exception has been handled (-1)
|
||||
// or should be made available to other handlers in the chain (0).
|
||||
uint32
|
||||
runtime·sighandler(ExceptionRecord *info, Context *r, G *gp)
|
||||
{
|
||||
bool crash;
|
||||
uintptr *sp;
|
||||
extern byte runtime·text[], runtime·etext[];
|
||||
|
||||
// Only handle exception if executing instructions in Go binary
|
||||
// (not Windows library code).
|
||||
if(r->Rip < (uint64)runtime·text || (uint64)runtime·etext < r->Rip)
|
||||
return false;
|
||||
return 0;
|
||||
|
||||
if(!runtime·issigpanic(info->ExceptionCode))
|
||||
return false;
|
||||
if(gp != nil && runtime·issigpanic(info->ExceptionCode)) {
|
||||
// Make it look like a call to the signal func.
|
||||
// Have to pass arguments out of band since
|
||||
// augmenting the stack frame would break
|
||||
// the unwinding code.
|
||||
gp->sig = info->ExceptionCode;
|
||||
gp->sigcode0 = info->ExceptionInformation[0];
|
||||
gp->sigcode1 = info->ExceptionInformation[1];
|
||||
gp->sigpc = r->Rip;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Called by sigtramp from Windows VEH handler.
|
||||
// Return value signals whether the exception has been handled (EXCEPTION_CONTINUE_EXECUTION)
|
||||
// or should be made available to other handlers in the chain (EXCEPTION_CONTINUE_SEARCH).
|
||||
uint32
|
||||
runtime·exceptionhandler(ExceptionRecord *info, Context *r, G *gp)
|
||||
{
|
||||
uintptr *sp;
|
||||
|
||||
if(!runtime·isgoexception(info, r))
|
||||
return EXCEPTION_CONTINUE_SEARCH;
|
||||
|
||||
// Make it look like a call to the signal func.
|
||||
// Have to pass arguments out of band since
|
||||
// augmenting the stack frame would break
|
||||
// the unwinding code.
|
||||
gp->sig = info->ExceptionCode;
|
||||
gp->sigcode0 = info->ExceptionInformation[0];
|
||||
gp->sigcode1 = info->ExceptionInformation[1];
|
||||
gp->sigpc = r->Rip;
|
||||
|
||||
// Only push runtime·sigpanic if r->rip != 0.
|
||||
// If r->rip == 0, probably panicked because of a
|
||||
// call to a nil func. Not pushing that onto sp will
|
||||
// make the trace look like a call to runtime·sigpanic instead.
|
||||
// (Otherwise the trace will end at runtime·sigpanic and we
|
||||
// won't get to see who faulted.)
|
||||
if(r->Rip != 0) {
|
||||
sp = (uintptr*)r->Rsp;
|
||||
*--sp = r->Rip;
|
||||
r->Rsp = (uintptr)sp;
|
||||
// Only push runtime·sigpanic if r->rip != 0.
|
||||
// If r->rip == 0, probably panicked because of a
|
||||
// call to a nil func. Not pushing that onto sp will
|
||||
// make the trace look like a call to runtime·sigpanic instead.
|
||||
// (Otherwise the trace will end at runtime·sigpanic and we
|
||||
// won't get to see who faulted.)
|
||||
if(r->Rip != 0) {
|
||||
sp = (uintptr*)r->Rsp;
|
||||
*--sp = r->Rip;
|
||||
r->Rsp = (uintptr)sp;
|
||||
}
|
||||
r->Rip = (uintptr)runtime·sigpanic;
|
||||
return -1;
|
||||
}
|
||||
r->Rip = (uintptr)runtime·sigpanic;
|
||||
return EXCEPTION_CONTINUE_EXECUTION;
|
||||
}
|
||||
|
||||
// It seems Windows searches ContinueHandler's list even
|
||||
// if ExceptionHandler returns EXCEPTION_CONTINUE_EXECUTION.
|
||||
// firstcontinuehandler will stop that search,
|
||||
// if exceptionhandler did the same earlier.
|
||||
uint32
|
||||
runtime·firstcontinuehandler(ExceptionRecord *info, Context *r, G *gp)
|
||||
{
|
||||
USED(gp);
|
||||
if(!runtime·isgoexception(info, r))
|
||||
return EXCEPTION_CONTINUE_SEARCH;
|
||||
return EXCEPTION_CONTINUE_EXECUTION;
|
||||
}
|
||||
|
||||
// lastcontinuehandler is reached, because runtime cannot handle
|
||||
// current exception. lastcontinuehandler will print crash info and exit.
|
||||
uint32
|
||||
runtime·lastcontinuehandler(ExceptionRecord *info, Context *r, G *gp)
|
||||
{
|
||||
bool crash;
|
||||
|
||||
if(runtime·panicking) // traceback already printed
|
||||
runtime·exit(2);
|
||||
@ -128,7 +97,7 @@ runtime·lastcontinuehandler(ExceptionRecord *info, Context *r, G *gp)
|
||||
runtime·crash();
|
||||
|
||||
runtime·exit(2);
|
||||
return 0; // not reached
|
||||
return -1; // not reached
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -73,7 +73,6 @@ TEXT runtime·setlasterror(SB),NOSPLIT,$0
|
||||
// Called by Windows as a Vectored Exception Handler (VEH).
|
||||
// First argument is pointer to struct containing
|
||||
// exception record and context pointers.
|
||||
// Handler function is stored in AX.
|
||||
// Return 0 for 'not handled', -1 for handled.
|
||||
TEXT runtime·sigtramp(SB),NOSPLIT,$0-0
|
||||
MOVL ptrs+0(FP), CX
|
||||
@ -85,8 +84,6 @@ TEXT runtime·sigtramp(SB),NOSPLIT,$0-0
|
||||
MOVL SI, 20(SP)
|
||||
MOVL DI, 24(SP)
|
||||
|
||||
MOVL AX, SI // save handler address
|
||||
|
||||
// find g
|
||||
get_tls(DX)
|
||||
CMPL DX, $0
|
||||
@ -126,10 +123,11 @@ TEXT runtime·sigtramp(SB),NOSPLIT,$0-0
|
||||
sigtramp_g0:
|
||||
MOVL 0(CX), BX // ExceptionRecord*
|
||||
MOVL 4(CX), CX // Context*
|
||||
// call sighandler(ExceptionRecord*, Context*, G*)
|
||||
MOVL BX, 0(SP)
|
||||
MOVL CX, 4(SP)
|
||||
MOVL DX, 8(SP)
|
||||
CALL SI // call handler
|
||||
CALL runtime·sighandler(SB)
|
||||
// AX is set to report result back to Windows
|
||||
MOVL 12(SP), AX
|
||||
|
||||
@ -151,18 +149,6 @@ done:
|
||||
// RET 4 (return and pop 4 bytes parameters)
|
||||
BYTE $0xC2; WORD $4
|
||||
RET // unreached; make assembler happy
|
||||
|
||||
TEXT runtime·exceptiontramp(SB),NOSPLIT,$0
|
||||
MOVL $runtime·exceptionhandler(SB), AX
|
||||
JMP runtime·sigtramp(SB)
|
||||
|
||||
TEXT runtime·firstcontinuetramp(SB),NOSPLIT,$0-0
|
||||
// is never called
|
||||
INT $3
|
||||
|
||||
TEXT runtime·lastcontinuetramp(SB),NOSPLIT,$0-0
|
||||
MOVL $runtime·lastcontinuehandler(SB), AX
|
||||
JMP runtime·sigtramp(SB)
|
||||
|
||||
TEXT runtime·ctrlhandler(SB),NOSPLIT,$0
|
||||
PUSHL $runtime·ctrlhandler1(SB)
|
||||
|
@ -99,7 +99,6 @@ TEXT runtime·setlasterror(SB),NOSPLIT,$0
|
||||
// Called by Windows as a Vectored Exception Handler (VEH).
|
||||
// First argument is pointer to struct containing
|
||||
// exception record and context pointers.
|
||||
// Handler function is stored in AX.
|
||||
// Return 0 for 'not handled', -1 for handled.
|
||||
TEXT runtime·sigtramp(SB),NOSPLIT,$0-0
|
||||
// CX: PEXCEPTION_POINTERS ExceptionInfo
|
||||
@ -117,8 +116,6 @@ TEXT runtime·sigtramp(SB),NOSPLIT,$0-0
|
||||
MOVQ R14, 32(SP)
|
||||
MOVQ R15, 88(SP)
|
||||
|
||||
MOVQ AX, R15 // save handler address
|
||||
|
||||
// find g
|
||||
get_tls(DX)
|
||||
CMPQ DX, $0
|
||||
@ -160,10 +157,11 @@ TEXT runtime·sigtramp(SB),NOSPLIT,$0-0
|
||||
sigtramp_g0:
|
||||
MOVQ 0(CX), BX // ExceptionRecord*
|
||||
MOVQ 8(CX), CX // Context*
|
||||
// call sighandler(ExceptionRecord*, Context*, G*)
|
||||
MOVQ BX, 0(SP)
|
||||
MOVQ CX, 8(SP)
|
||||
MOVQ DX, 16(SP)
|
||||
CALL R15 // call handler
|
||||
CALL runtime·sighandler(SB)
|
||||
// AX is set to report result back to Windows
|
||||
MOVL 24(SP), AX
|
||||
|
||||
@ -189,18 +187,6 @@ done:
|
||||
|
||||
RET
|
||||
|
||||
TEXT runtime·exceptiontramp(SB),NOSPLIT,$0
|
||||
MOVQ $runtime·exceptionhandler(SB), AX
|
||||
JMP runtime·sigtramp(SB)
|
||||
|
||||
TEXT runtime·firstcontinuetramp(SB),NOSPLIT,$0-0
|
||||
MOVQ $runtime·firstcontinuehandler(SB), AX
|
||||
JMP runtime·sigtramp(SB)
|
||||
|
||||
TEXT runtime·lastcontinuetramp(SB),NOSPLIT,$0-0
|
||||
MOVQ $runtime·lastcontinuehandler(SB), AX
|
||||
JMP runtime·sigtramp(SB)
|
||||
|
||||
TEXT runtime·ctrlhandler(SB),NOSPLIT,$8
|
||||
MOVQ CX, 16(SP) // spill
|
||||
MOVQ $runtime·ctrlhandler1(SB), CX
|
||||
|
@ -494,42 +494,3 @@ func TestOutputDebugString(t *testing.T) {
|
||||
p := syscall.StringToUTF16Ptr("testing OutputDebugString")
|
||||
d.Proc("OutputDebugStringW").Call(uintptr(unsafe.Pointer(p)))
|
||||
}
|
||||
|
||||
func TestRaiseException(t *testing.T) {
|
||||
o := executeTest(t, raiseExceptionSource, nil)
|
||||
if strings.Contains(o, "RaiseException should not return") {
|
||||
t.Fatalf("RaiseException did not crash program: %v", o)
|
||||
}
|
||||
if !strings.Contains(o, "Exception 0xbad") {
|
||||
t.Fatalf("No stack trace: %v", o)
|
||||
}
|
||||
}
|
||||
|
||||
const raiseExceptionSource = `
|
||||
package main
|
||||
import "syscall"
|
||||
func main() {
|
||||
const EXCEPTION_NONCONTINUABLE = 1
|
||||
mod := syscall.MustLoadDLL("kernel32.dll")
|
||||
proc := mod.MustFindProc("RaiseException")
|
||||
proc.Call(0xbad, EXCEPTION_NONCONTINUABLE, 0, 0)
|
||||
println("RaiseException should not return")
|
||||
}
|
||||
`
|
||||
|
||||
func TestZeroDivisionException(t *testing.T) {
|
||||
o := executeTest(t, zeroDivisionExceptionSource, nil)
|
||||
if !strings.Contains(o, "panic: runtime error: integer divide by zero") {
|
||||
t.Fatalf("No stack trace: %v", o)
|
||||
}
|
||||
}
|
||||
|
||||
const zeroDivisionExceptionSource = `
|
||||
package main
|
||||
func main() {
|
||||
x := 1
|
||||
y := 0
|
||||
z := x / y
|
||||
println(z)
|
||||
}
|
||||
`
|
||||
|
Loading…
Reference in New Issue
Block a user