__fastfail() is used by the Visual C++ runtime and Windows system libraries to signal that the in-process state is corrupted and unrecoverable.
If __fastfail() is invoked, the NT kernel raises a second-chance non-continuable exception STATUS_STACK_BUFFER_OVERRUN. This quickly terminates the process, bypassing all in-process exception handlers (since they all rely on the potentially corrupted process state).
Signed-off-by: Jinoh Kang jinoh.kang.kr@gmail.com ---
Notes: v3 -> v4: fix BRK #0xF003 detection on ARM64 add comments
dlls/ntdll/tests/exception.c | 1 - dlls/ntdll/unix/signal_arm.c | 14 ++++++++++++-- dlls/ntdll/unix/signal_arm64.c | 15 +++++++++++++++ dlls/ntdll/unix/signal_i386.c | 7 +++++++ dlls/ntdll/unix/signal_x86_64.c | 7 +++++++ 5 files changed, 41 insertions(+), 3 deletions(-)
diff --git a/dlls/ntdll/tests/exception.c b/dlls/ntdll/tests/exception.c index c0d3ae19a51..14b1396dbc2 100644 --- a/dlls/ntdll/tests/exception.c +++ b/dlls/ntdll/tests/exception.c @@ -8429,7 +8429,6 @@ static void subtest_fastfail(unsigned int code)
} while (de.dwDebugEventCode != EXIT_PROCESS_DEBUG_EVENT);
- todo_wine ok(had_ff || broken(had_se) /* Win7 */, "fast fail did not occur\n");
wait_child_process( pi.hProcess ); diff --git a/dlls/ntdll/unix/signal_arm.c b/dlls/ntdll/unix/signal_arm.c index dbc2770f72e..1816e210644 100644 --- a/dlls/ntdll/unix/signal_arm.c +++ b/dlls/ntdll/unix/signal_arm.c @@ -809,13 +809,23 @@ static void segv_handler( int signal, siginfo_t *siginfo, void *sigcontext ) switch (get_trap_code(signal, context)) { case TRAP_ARM_PRIVINFLT: /* Invalid opcode exception */ - if (*(WORD *)PC_sig(context) == 0xdefe) /* breakpoint */ + switch (*(WORD *)PC_sig(context)) { + case 0xdefb: /* __fastfail */ + rec.ExceptionCode = STATUS_STACK_BUFFER_OVERRUN; + rec.ExceptionFlags = EH_NONCONTINUABLE; + rec.NumberParameters = 1; + rec.ExceptionInformation[0] = REGn_sig(0, context); + setup_exception( context, &rec, FALSE ); + return; + case 0xdefe: /* breakpoint */ rec.ExceptionCode = EXCEPTION_BREAKPOINT; rec.NumberParameters = 1; break; + default: + rec.ExceptionCode = EXCEPTION_ILLEGAL_INSTRUCTION; + break; } - rec.ExceptionCode = EXCEPTION_ILLEGAL_INSTRUCTION; break; case TRAP_ARM_PAGEFLT: /* Page fault */ rec.NumberParameters = 2; diff --git a/dlls/ntdll/unix/signal_arm64.c b/dlls/ntdll/unix/signal_arm64.c index 6349c72323c..ae44fb02982 100644 --- a/dlls/ntdll/unix/signal_arm64.c +++ b/dlls/ntdll/unix/signal_arm64.c @@ -905,6 +905,7 @@ static void bus_handler( int signal, siginfo_t *siginfo, void *sigcontext ) static void trap_handler( int signal, siginfo_t *siginfo, void *sigcontext ) { EXCEPTION_RECORD rec = { 0 }; + ucontext_t *context = sigcontext;
switch (siginfo->si_code) { @@ -913,6 +914,20 @@ static void trap_handler( int signal, siginfo_t *siginfo, void *sigcontext ) break; case TRAP_BRKPT: default: + /* debug exceptions do not update ESR on Linux, + * so we fetch the instruction directly. */ + if (!(PSTATE_sig( context ) & 0x10) && /* AArch64 (not WoW) */ + !(PC_sig( context ) & 3) && + *(ULONG *)PC_sig( context ) == 0xd43e0060UL) /* brk #0xf003 */ + { + /* __fastfail */ + rec.ExceptionCode = STATUS_STACK_BUFFER_OVERRUN; + rec.ExceptionFlags = EH_NONCONTINUABLE; + rec.NumberParameters = 1; + rec.ExceptionInformation[0] = REGn_sig( 0, context ); + setup_exception( sigcontext, &rec, FALSE ); + return; + } rec.ExceptionCode = EXCEPTION_BREAKPOINT; rec.NumberParameters = 1; break; diff --git a/dlls/ntdll/unix/signal_i386.c b/dlls/ntdll/unix/signal_i386.c index e18aed2c222..1ec85240612 100644 --- a/dlls/ntdll/unix/signal_i386.c +++ b/dlls/ntdll/unix/signal_i386.c @@ -1660,6 +1660,13 @@ static BOOL handle_interrupt( unsigned int interrupt, ucontext_t *sigcontext, vo
switch(interrupt) { + case 0x29: /* __fastfail */ + rec->ExceptionCode = STATUS_STACK_BUFFER_OVERRUN; + rec->ExceptionFlags = EH_NONCONTINUABLE; + rec->NumberParameters = 1; + rec->ExceptionInformation[0] = context->Ecx; + setup_raise_exception( sigcontext, stack, rec, xcontext, FALSE ); + return TRUE; case 0x2d: if (!is_wow64) { diff --git a/dlls/ntdll/unix/signal_x86_64.c b/dlls/ntdll/unix/signal_x86_64.c index 7e920d31978..3d7b8e256b4 100644 --- a/dlls/ntdll/unix/signal_x86_64.c +++ b/dlls/ntdll/unix/signal_x86_64.c @@ -2441,6 +2441,13 @@ static inline BOOL handle_interrupt( ucontext_t *sigcontext, EXCEPTION_RECORD *r
switch (ERROR_sig(sigcontext) >> 3) { + case 0x29: /* __fastfail */ + rec->ExceptionCode = STATUS_STACK_BUFFER_OVERRUN; + rec->ExceptionFlags = EH_NONCONTINUABLE; + rec->NumberParameters = 1; + rec->ExceptionInformation[0] = context->Rcx; + setup_raise_exception( sigcontext, rec, xcontext, FALSE ); + return TRUE; case 0x2c: rec->ExceptionCode = STATUS_ASSERTION_FAILURE; break;