From: Paul Gofman pgofman@codeweavers.com
--- dlls/kernel32/tests/debugger.c | 47 ++++++++++++++++++++++++++++++++++ 1 file changed, 47 insertions(+)
diff --git a/dlls/kernel32/tests/debugger.c b/dlls/kernel32/tests/debugger.c index 13b6b13bfcd..442547c565e 100644 --- a/dlls/kernel32/tests/debugger.c +++ b/dlls/kernel32/tests/debugger.c @@ -2443,6 +2443,52 @@ static void test_OutputDebugString(void) ok(GetLastError() == 0xdeadbeef, "got %ld.\n", GetLastError()); }
+static LONG WINAPI test_unhandled_exception_filter_topfilter( EXCEPTION_POINTERS *ep ) +{ + static int depth; + EXCEPTION_RECORD *rec = ep->ExceptionRecord; + LONG ret; + + ++depth; + if (depth > 1) return EXCEPTION_CONTINUE_SEARCH; + + ret = UnhandledExceptionFilter( ep ); + ok( depth == 2, "got %d.\n", depth ); + --depth; + ok( ret == EXCEPTION_EXECUTE_HANDLER, "got %#lx.\n", ret ); + rec->ExceptionFlags = EXCEPTION_NESTED_CALL; + ret = UnhandledExceptionFilter( ep ); + todo_wine ok( depth == 1, "got %d.\n", depth ); + depth = 1; + todo_wine ok( ret == EXCEPTION_CONTINUE_SEARCH, "got %#lx.\n", ret ); + --depth; + rec->ExceptionFlags = 0; + return EXCEPTION_CONTINUE_SEARCH; +} + +static void test_unhandled_exception_filter(void) +{ + EXCEPTION_RECORD rec = { .ExceptionCode = 0xbeef }; + EXCEPTION_POINTERS ep = { .ExceptionRecord = &rec }; + LPTOP_LEVEL_EXCEPTION_FILTER old; + LONG ret; + + old = SetUnhandledExceptionFilter( test_unhandled_exception_filter_topfilter ); + ret = UnhandledExceptionFilter( &ep ); + ok( ret == EXCEPTION_EXECUTE_HANDLER, "got %ld.\n", ret ); + + SetUnhandledExceptionFilter( NULL ); + + rec.ExceptionFlags = EXCEPTION_NESTED_CALL; + ret = UnhandledExceptionFilter( &ep ); + todo_wine ok( ret == EXCEPTION_CONTINUE_SEARCH, "got %#lx.\n", ret ); + rec.ExceptionFlags &= ~EXCEPTION_NESTED_CALL; + ret = UnhandledExceptionFilter( &ep ); + ok( ret == EXCEPTION_EXECUTE_HANDLER, "got %#lx.\n", ret ); + + SetUnhandledExceptionFilter( old ); +} + START_TEST(debugger) { HMODULE hdll; @@ -2509,5 +2555,6 @@ START_TEST(debugger) test_debugger(myARGV[0]); test_kill_on_exit(myARGV[0]); test_OutputDebugString(); + test_unhandled_exception_filter(); } }
From: Paul Gofman pgofman@codeweavers.com
--- dlls/kernel32/tests/debugger.c | 2 +- dlls/kernelbase/debug.c | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-)
diff --git a/dlls/kernel32/tests/debugger.c b/dlls/kernel32/tests/debugger.c index 442547c565e..7d10266ce0b 100644 --- a/dlls/kernel32/tests/debugger.c +++ b/dlls/kernel32/tests/debugger.c @@ -2458,7 +2458,7 @@ static LONG WINAPI test_unhandled_exception_filter_topfilter( EXCEPTION_POINTERS ok( ret == EXCEPTION_EXECUTE_HANDLER, "got %#lx.\n", ret ); rec->ExceptionFlags = EXCEPTION_NESTED_CALL; ret = UnhandledExceptionFilter( ep ); - todo_wine ok( depth == 1, "got %d.\n", depth ); + ok( depth == 1, "got %d.\n", depth ); depth = 1; todo_wine ok( ret == EXCEPTION_CONTINUE_SEARCH, "got %#lx.\n", ret ); --depth; diff --git a/dlls/kernelbase/debug.c b/dlls/kernelbase/debug.c index 453b6114c2b..bf3547f9db8 100644 --- a/dlls/kernelbase/debug.c +++ b/dlls/kernelbase/debug.c @@ -752,6 +752,7 @@ static BOOL check_resource_write( void *addr ) LONG WINAPI UnhandledExceptionFilter( EXCEPTION_POINTERS *epointers ) { const EXCEPTION_RECORD *rec = epointers->ExceptionRecord; + BOOL nested;
if (rec->ExceptionCode == EXCEPTION_ACCESS_VIOLATION && rec->NumberParameters >= 2) { @@ -772,7 +773,8 @@ LONG WINAPI UnhandledExceptionFilter( EXCEPTION_POINTERS *epointers ) TerminateProcess( GetCurrentProcess(), 1 ); }
- if (top_filter) + nested = rec->ExceptionFlags & EXCEPTION_NESTED_CALL; + if (top_filter && !nested) { LONG ret = top_filter( epointers ); if (ret != EXCEPTION_CONTINUE_SEARCH) return ret;
From: Paul Gofman pgofman@codeweavers.com
--- dlls/kernel32/tests/debugger.c | 4 ++-- dlls/kernelbase/debug.c | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/dlls/kernel32/tests/debugger.c b/dlls/kernel32/tests/debugger.c index 7d10266ce0b..3d3dd0a402f 100644 --- a/dlls/kernel32/tests/debugger.c +++ b/dlls/kernel32/tests/debugger.c @@ -2460,7 +2460,7 @@ static LONG WINAPI test_unhandled_exception_filter_topfilter( EXCEPTION_POINTERS ret = UnhandledExceptionFilter( ep ); ok( depth == 1, "got %d.\n", depth ); depth = 1; - todo_wine ok( ret == EXCEPTION_CONTINUE_SEARCH, "got %#lx.\n", ret ); + ok( ret == EXCEPTION_CONTINUE_SEARCH, "got %#lx.\n", ret ); --depth; rec->ExceptionFlags = 0; return EXCEPTION_CONTINUE_SEARCH; @@ -2481,7 +2481,7 @@ static void test_unhandled_exception_filter(void)
rec.ExceptionFlags = EXCEPTION_NESTED_CALL; ret = UnhandledExceptionFilter( &ep ); - todo_wine ok( ret == EXCEPTION_CONTINUE_SEARCH, "got %#lx.\n", ret ); + ok( ret == EXCEPTION_CONTINUE_SEARCH, "got %#lx.\n", ret ); rec.ExceptionFlags &= ~EXCEPTION_NESTED_CALL; ret = UnhandledExceptionFilter( &ep ); ok( ret == EXCEPTION_EXECUTE_HANDLER, "got %#lx.\n", ret ); diff --git a/dlls/kernelbase/debug.c b/dlls/kernelbase/debug.c index bf3547f9db8..6a332e971ec 100644 --- a/dlls/kernelbase/debug.c +++ b/dlls/kernelbase/debug.c @@ -782,7 +782,7 @@ LONG WINAPI UnhandledExceptionFilter( EXCEPTION_POINTERS *epointers )
if ((GetErrorMode() & SEM_NOGPFAULTERRORBOX) || !start_debugger_atomic( epointers ) || !NtCurrentTeb()->Peb->BeingDebugged) - return EXCEPTION_EXECUTE_HANDLER; + return nested ? EXCEPTION_CONTINUE_SEARCH : EXCEPTION_EXECUTE_HANDLER; } return EXCEPTION_CONTINUE_SEARCH; }
The practical motivation is to handle the case of exception in app's top filter which currently results in nesting exceptions until stack overflow (which also does not necessarily kill the process) and instead let the process terminate at once.