This is most likely a typo from MSDN.
Signed-off-by: Rémi Bernon rbernon@codeweavers.com ---
v2: Use RtlRaiseException as the exception address, testing shows that the address on Windows varies, and is sometimes around DbgPrint or RtlRaiseException, but nothing matching exactly.
Supersedes: 196206-196209
include/dpfilter.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/include/dpfilter.h b/include/dpfilter.h index 5b09dc9c23c..deb8db3fc41 100644 --- a/include/dpfilter.h +++ b/include/dpfilter.h @@ -23,7 +23,7 @@ #define DPFLTR_WARNING_LEVEL 1 #define DPFLTR_TRACE_LEVEL 2 #define DPFLTR_INFO_LEVEL 3 -#define DPFLTR_MASK 0x8000000 +#define DPFLTR_MASK 0x80000000
typedef enum _DPFLTR_TYPE {
Signed-off-by: Rémi Bernon rbernon@codeweavers.com --- dlls/ntdll/tests/rtl.c | 117 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 117 insertions(+)
diff --git a/dlls/ntdll/tests/rtl.c b/dlls/ntdll/tests/rtl.c index 7a62670ea05..76288545cc2 100644 --- a/dlls/ntdll/tests/rtl.c +++ b/dlls/ntdll/tests/rtl.c @@ -3483,6 +3483,122 @@ static void test_LdrRegisterDllNotification(void) pLdrUnregisterDllNotification(cookie); }
+static BOOL test_dbg_print_except; +static LONG test_dbg_print_except_ret; + +static LONG CALLBACK test_dbg_print_except_handler( EXCEPTION_POINTERS *eptrs ) +{ + if (eptrs->ExceptionRecord->ExceptionCode == DBG_PRINTEXCEPTION_C) + { + ok( eptrs->ExceptionRecord->NumberParameters == 2, + "Unexpected NumberParameters: %d\n", eptrs->ExceptionRecord->NumberParameters ); + ok( eptrs->ExceptionRecord->ExceptionInformation[0] == strlen("test_DbgPrint: Hello World") + 1, + "Unexpected ExceptionInformation[0]: %d\n", (int)eptrs->ExceptionRecord->ExceptionInformation[0] ); + ok( !strcmp((char *)eptrs->ExceptionRecord->ExceptionInformation[1], "test_DbgPrint: Hello World"), + "Unexpected ExceptionInformation[1]: %s\n", wine_dbgstr_a((char *)eptrs->ExceptionRecord->ExceptionInformation[1]) ); + test_dbg_print_except = TRUE; + return test_dbg_print_except_ret; + } + + return (LONG)EXCEPTION_CONTINUE_SEARCH; +} + +static NTSTATUS test_vDbgPrintEx( ULONG id, ULONG level, const char *fmt, ... ) +{ + NTSTATUS status; + va_list args; + va_start( args, fmt ); + status = vDbgPrintEx( id, level, fmt, args ); + va_end( args ); + return status; +} + +static NTSTATUS test_vDbgPrintExWithPrefix( const char *prefix, ULONG id, ULONG level, const char *fmt, ... ) +{ + NTSTATUS status; + va_list args; + va_start( args, fmt ); + status = vDbgPrintExWithPrefix( prefix, id, level, fmt, args ); + va_end( args ); + return status; +} + +static void test_DbgPrint(void) +{ + NTSTATUS status; + void *handler = RtlAddVectoredExceptionHandler( TRUE, test_dbg_print_except_handler ); + PEB *Peb = NtCurrentTeb()->Peb; + BOOL debugged = Peb->BeingDebugged; + + test_dbg_print_except = FALSE; + test_dbg_print_except_ret = (LONG)EXCEPTION_EXECUTE_HANDLER; + status = DbgPrint( "test_DbgPrint: %s", "Hello World" ); + ok( !status, "DbgPrint returned %x\n", status ); + ok( !test_dbg_print_except, "DBG_PRINTEXCEPTION_C received\n" ); + + Peb->BeingDebugged = TRUE; + test_dbg_print_except = FALSE; + test_dbg_print_except_ret = (LONG)EXCEPTION_EXECUTE_HANDLER; + status = DbgPrint( "test_DbgPrint: %s", "Hello World" ); + ok( !status, "DbgPrint returned %x\n", status ); + todo_wine ok( test_dbg_print_except, "DBG_PRINTEXCEPTION_C not received\n" ); + + test_dbg_print_except = FALSE; + test_dbg_print_except_ret = (LONG)EXCEPTION_CONTINUE_EXECUTION; + status = DbgPrint( "test_DbgPrint: %s", "Hello World" ); + ok( !status, "DbgPrint returned %x\n", status ); + todo_wine ok( test_dbg_print_except, "DBG_PRINTEXCEPTION_C not received\n" ); + + test_dbg_print_except = FALSE; + test_dbg_print_except_ret = (LONG)EXCEPTION_CONTINUE_SEARCH; + status = DbgPrint( "test_DbgPrint: %s", "Hello World" ); + ok( !status, "DbgPrint returned %x\n", status ); + todo_wine ok( test_dbg_print_except, "DBG_PRINTEXCEPTION_C not received\n" ); + + + /* FIXME: NtSetDebugFilterState / DbgSetDebugFilterState are probably what's controlling these */ + + test_dbg_print_except = FALSE; + test_dbg_print_except_ret = (LONG)EXCEPTION_EXECUTE_HANDLER; + status = DbgPrintEx( 0, DPFLTR_ERROR_LEVEL, "test_DbgPrint: %s", "Hello World" ); + ok( !status, "DbgPrintEx returned %x\n", status ); + todo_wine ok( test_dbg_print_except, "DBG_PRINTEXCEPTION_C not received\n" ); + + test_dbg_print_except = FALSE; + test_dbg_print_except_ret = (LONG)EXCEPTION_EXECUTE_HANDLER; + status = DbgPrintEx( 0, DPFLTR_WARNING_LEVEL, "test_DbgPrint: %s", "Hello World" ); + ok( !status, "DbgPrintEx returned %x\n", status ); + ok( !test_dbg_print_except, "DBG_PRINTEXCEPTION_C not received\n" ); + + test_dbg_print_except = FALSE; + test_dbg_print_except_ret = (LONG)EXCEPTION_EXECUTE_HANDLER; + status = DbgPrintEx( 0, DPFLTR_MASK|(1 << DPFLTR_ERROR_LEVEL), "test_DbgPrint: %s", "Hello World" ); + ok( !status, "DbgPrintEx returned %x\n", status ); + todo_wine ok( test_dbg_print_except, "DBG_PRINTEXCEPTION_C not received\n" ); + + test_dbg_print_except = FALSE; + test_dbg_print_except_ret = (LONG)EXCEPTION_EXECUTE_HANDLER; + status = DbgPrintEx( 0, DPFLTR_MASK|(1 << DPFLTR_WARNING_LEVEL), "test_DbgPrint: %s", "Hello World" ); + ok( !status, "DbgPrintEx returned %x\n", status ); + ok( !test_dbg_print_except, "DBG_PRINTEXCEPTION_C not received\n" ); + + + test_dbg_print_except = FALSE; + test_dbg_print_except_ret = (LONG)EXCEPTION_EXECUTE_HANDLER; + status = test_vDbgPrintEx( 0, 0xFFFFFFFF, "test_DbgPrint: %s", "Hello World" ); + ok( !status, "vDbgPrintEx returned %x\n", status ); + todo_wine ok( test_dbg_print_except, "DBG_PRINTEXCEPTION_C not received\n" ); + + test_dbg_print_except = FALSE; + test_dbg_print_except_ret = (LONG)EXCEPTION_EXECUTE_HANDLER; + status = test_vDbgPrintExWithPrefix( "test_", 0, 0xFFFFFFFF, "DbgPrint: %s", "Hello World" ); + ok( !status, "vDbgPrintExWithPrefix returned %x\n", status ); + todo_wine ok( test_dbg_print_except, "DBG_PRINTEXCEPTION_C not received\n" ); + + Peb->BeingDebugged = debugged; + RtlRemoveVectoredExceptionHandler( handler ); +} + START_TEST(rtl) { InitFunctionPtrs(); @@ -3523,4 +3639,5 @@ START_TEST(rtl) test_LdrEnumerateLoadedModules(); test_RtlMakeSelfRelativeSD(); test_LdrRegisterDllNotification(); + test_DbgPrint(); }
Signed-off-by: Rémi Bernon rbernon@codeweavers.com --- dlls/ntdll/rtl.c | 56 +++++++++++++++++++++++++++++------------- dlls/ntdll/tests/rtl.c | 14 +++++------ 2 files changed, 46 insertions(+), 24 deletions(-)
diff --git a/dlls/ntdll/rtl.c b/dlls/ntdll/rtl.c index ca4fea84209..11dbc63a3b3 100644 --- a/dlls/ntdll/rtl.c +++ b/dlls/ntdll/rtl.c @@ -39,6 +39,7 @@ #include "ddk/ntddk.h"
WINE_DEFAULT_DEBUG_CHANNEL(ntdll); +WINE_DECLARE_DEBUG_CHANNEL(debugstr);
/* CRC polynomial 0xedb88320 */ static const DWORD CRC_table[256] = @@ -297,21 +298,24 @@ void WINAPI RtlDumpResource(LPRTL_RWLOCK rwl) * misc functions */
+static LONG WINAPI debug_exception_handler( EXCEPTION_POINTERS *eptr ) +{ + EXCEPTION_RECORD *rec = eptr->ExceptionRecord; + return (rec->ExceptionCode == DBG_PRINTEXCEPTION_C) ? EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH; +} + /****************************************************************************** * DbgPrint [NTDLL.@] */ NTSTATUS WINAPIV DbgPrint(LPCSTR fmt, ...) { - char buf[512]; - __ms_va_list args; - - __ms_va_start(args, fmt); - _vsnprintf(buf, sizeof(buf), fmt, args); - __ms_va_end(args); + NTSTATUS ret; + __ms_va_list args;
- MESSAGE("DbgPrint says: %s",buf); - /* hmm, raise exception? */ - return STATUS_SUCCESS; + __ms_va_start(args, fmt); + ret = vDbgPrintEx(0, DPFLTR_ERROR_LEVEL, fmt, args); + __ms_va_end(args); + return ret; }
@@ -342,18 +346,36 @@ NTSTATUS WINAPI vDbgPrintEx( ULONG id, ULONG level, LPCSTR fmt, __ms_va_list arg */ NTSTATUS WINAPI vDbgPrintExWithPrefix( LPCSTR prefix, ULONG id, ULONG level, LPCSTR fmt, __ms_va_list args ) { - char buf[1024]; + ULONG level_mask = level <= 31 ? (1 << level) : level; + SIZE_T len = strlen( prefix ); + char buf[1024], *end;
- _vsnprintf(buf, sizeof(buf), fmt, args); + strcpy( buf, prefix ); + len += _vsnprintf( buf + len, sizeof(buf) - len, fmt, args ); + end = buf + len - 1;
- switch (level & DPFLTR_MASK) + WARN_(debugstr)(*end == '\n' ? "%08x:%08x: %s" : "%08x:%08x: %s\n", id, level_mask, buf); + + if (level_mask & (1 << DPFLTR_ERROR_LEVEL) && NtCurrentTeb()->Peb->BeingDebugged) { - case DPFLTR_ERROR_LEVEL: ERR("%s%x: %s", prefix, id, buf); break; - case DPFLTR_WARNING_LEVEL: WARN("%s%x: %s", prefix, id, buf); break; - case DPFLTR_TRACE_LEVEL: - case DPFLTR_INFO_LEVEL: - default: TRACE("%s%x: %s", prefix, id, buf); break; + __TRY + { + EXCEPTION_RECORD record; + record.ExceptionCode = DBG_PRINTEXCEPTION_C; + record.ExceptionFlags = 0; + record.ExceptionRecord = NULL; + record.ExceptionAddress = RtlRaiseException; + record.NumberParameters = 2; + record.ExceptionInformation[1] = (ULONG_PTR)buf; + record.ExceptionInformation[0] = strlen( buf ) + 1; + RtlRaiseException( &record ); + } + __EXCEPT(debug_exception_handler) + { + } + __ENDTRY } + return STATUS_SUCCESS; }
diff --git a/dlls/ntdll/tests/rtl.c b/dlls/ntdll/tests/rtl.c index 76288545cc2..796b98c4e76 100644 --- a/dlls/ntdll/tests/rtl.c +++ b/dlls/ntdll/tests/rtl.c @@ -3541,19 +3541,19 @@ static void test_DbgPrint(void) test_dbg_print_except_ret = (LONG)EXCEPTION_EXECUTE_HANDLER; status = DbgPrint( "test_DbgPrint: %s", "Hello World" ); ok( !status, "DbgPrint returned %x\n", status ); - todo_wine ok( test_dbg_print_except, "DBG_PRINTEXCEPTION_C not received\n" ); + ok( test_dbg_print_except, "DBG_PRINTEXCEPTION_C not received\n" );
test_dbg_print_except = FALSE; test_dbg_print_except_ret = (LONG)EXCEPTION_CONTINUE_EXECUTION; status = DbgPrint( "test_DbgPrint: %s", "Hello World" ); ok( !status, "DbgPrint returned %x\n", status ); - todo_wine ok( test_dbg_print_except, "DBG_PRINTEXCEPTION_C not received\n" ); + ok( test_dbg_print_except, "DBG_PRINTEXCEPTION_C not received\n" );
test_dbg_print_except = FALSE; test_dbg_print_except_ret = (LONG)EXCEPTION_CONTINUE_SEARCH; status = DbgPrint( "test_DbgPrint: %s", "Hello World" ); ok( !status, "DbgPrint returned %x\n", status ); - todo_wine ok( test_dbg_print_except, "DBG_PRINTEXCEPTION_C not received\n" ); + ok( test_dbg_print_except, "DBG_PRINTEXCEPTION_C not received\n" );
/* FIXME: NtSetDebugFilterState / DbgSetDebugFilterState are probably what's controlling these */ @@ -3562,7 +3562,7 @@ static void test_DbgPrint(void) test_dbg_print_except_ret = (LONG)EXCEPTION_EXECUTE_HANDLER; status = DbgPrintEx( 0, DPFLTR_ERROR_LEVEL, "test_DbgPrint: %s", "Hello World" ); ok( !status, "DbgPrintEx returned %x\n", status ); - todo_wine ok( test_dbg_print_except, "DBG_PRINTEXCEPTION_C not received\n" ); + ok( test_dbg_print_except, "DBG_PRINTEXCEPTION_C not received\n" );
test_dbg_print_except = FALSE; test_dbg_print_except_ret = (LONG)EXCEPTION_EXECUTE_HANDLER; @@ -3574,7 +3574,7 @@ static void test_DbgPrint(void) test_dbg_print_except_ret = (LONG)EXCEPTION_EXECUTE_HANDLER; status = DbgPrintEx( 0, DPFLTR_MASK|(1 << DPFLTR_ERROR_LEVEL), "test_DbgPrint: %s", "Hello World" ); ok( !status, "DbgPrintEx returned %x\n", status ); - todo_wine ok( test_dbg_print_except, "DBG_PRINTEXCEPTION_C not received\n" ); + ok( test_dbg_print_except, "DBG_PRINTEXCEPTION_C not received\n" );
test_dbg_print_except = FALSE; test_dbg_print_except_ret = (LONG)EXCEPTION_EXECUTE_HANDLER; @@ -3587,13 +3587,13 @@ static void test_DbgPrint(void) test_dbg_print_except_ret = (LONG)EXCEPTION_EXECUTE_HANDLER; status = test_vDbgPrintEx( 0, 0xFFFFFFFF, "test_DbgPrint: %s", "Hello World" ); ok( !status, "vDbgPrintEx returned %x\n", status ); - todo_wine ok( test_dbg_print_except, "DBG_PRINTEXCEPTION_C not received\n" ); + ok( test_dbg_print_except, "DBG_PRINTEXCEPTION_C not received\n" );
test_dbg_print_except = FALSE; test_dbg_print_except_ret = (LONG)EXCEPTION_EXECUTE_HANDLER; status = test_vDbgPrintExWithPrefix( "test_", 0, 0xFFFFFFFF, "DbgPrint: %s", "Hello World" ); ok( !status, "vDbgPrintExWithPrefix returned %x\n", status ); - todo_wine ok( test_dbg_print_except, "DBG_PRINTEXCEPTION_C not received\n" ); + ok( test_dbg_print_except, "DBG_PRINTEXCEPTION_C not received\n" );
Peb->BeingDebugged = debugged; RtlRemoveVectoredExceptionHandler( handler );
And when PEB->BeingDebugged is set to 1. Lords Of The Fallen anti-tamper does this and only continues if a DBG_PRINTEXCEPTION_C is received.
Signed-off-by: Rémi Bernon rbernon@codeweavers.com --- dlls/ntdll/heap.c | 6 ++++ dlls/ntdll/tests/rtl.c | 66 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 72 insertions(+)
diff --git a/dlls/ntdll/heap.c b/dlls/ntdll/heap.c index 1ac0cb24806..88db935746a 100644 --- a/dlls/ntdll/heap.c +++ b/dlls/ntdll/heap.c @@ -1589,6 +1589,12 @@ HANDLE WINAPI RtlDestroyHeap( HANDLE heap ) void *addr;
TRACE("%p\n", heap ); + if (!heapPtr && heap && (((HEAP *)heap)->flags & HEAP_VALIDATE_PARAMS) && + NtCurrentTeb()->Peb->BeingDebugged) + { + DbgPrint( "Attempt to destroy an invalid heap\n" ); + DbgBreakPoint(); + } if (!heapPtr) return heap;
if (heap == processHeap) return heap; /* cannot delete the main process heap */ diff --git a/dlls/ntdll/tests/rtl.c b/dlls/ntdll/tests/rtl.c index 796b98c4e76..360bffe5195 100644 --- a/dlls/ntdll/tests/rtl.c +++ b/dlls/ntdll/tests/rtl.c @@ -3599,6 +3599,71 @@ static void test_DbgPrint(void) RtlRemoveVectoredExceptionHandler( handler ); }
+static BOOL test_heap_destroy_dbgstr = FALSE; +static BOOL test_heap_destroy_break = FALSE; + +static LONG CALLBACK test_heap_destroy_except_handler( EXCEPTION_POINTERS *eptrs ) +{ + if (eptrs->ExceptionRecord->ExceptionCode == STATUS_BREAKPOINT) + { +#if defined( __i386__ ) + eptrs->ContextRecord->Eip += 1; + test_heap_destroy_break = TRUE; + return (LONG)EXCEPTION_CONTINUE_EXECUTION; +#elif defined( __x86_64__ ) + eptrs->ContextRecord->Rip += 1; + test_heap_destroy_break = TRUE; + return (LONG)EXCEPTION_CONTINUE_EXECUTION; +#endif + } + + if (eptrs->ExceptionRecord->ExceptionCode == DBG_PRINTEXCEPTION_C) + { + test_heap_destroy_dbgstr = TRUE; + return (LONG)EXCEPTION_CONTINUE_EXECUTION; + } + + return (LONG)EXCEPTION_CONTINUE_SEARCH; +} + +/* partially copied from ntdll/heap.c */ +#define HEAP_VALIDATE_PARAMS 0x40000000 + +struct heap +{ + DWORD_PTR unknown1[2]; + DWORD unknown2[2]; + DWORD_PTR unknown3[4]; + DWORD unknown4; + DWORD_PTR unknown5[2]; + DWORD unknown6[3]; + DWORD_PTR unknown7[2]; + DWORD flags; + DWORD force_flags; + DWORD_PTR unknown8[6]; +}; + +static void test_RtlDestroyHeap(void) +{ + const struct heap invalid = {{0, 0}, {0, HEAP_VALIDATE_PARAMS}, {0, 0, 0, 0}, 0, {0, 0}, {0, 0, 0}, {0, 0}, HEAP_VALIDATE_PARAMS, 0, {0}}; + HANDLE heap = (HANDLE)&invalid, ret; + PEB *Peb = NtCurrentTeb()->Peb; + BOOL debugged; + void *handler = RtlAddVectoredExceptionHandler( TRUE, test_heap_destroy_except_handler ); + + test_heap_destroy_dbgstr = FALSE; + test_heap_destroy_break = FALSE; + debugged = Peb->BeingDebugged; + Peb->BeingDebugged = TRUE; + ret = RtlDestroyHeap( heap ); + ok( ret == heap, "RtlDestroyHeap(%p) returned %p\n", heap, ret ); + ok( test_heap_destroy_dbgstr, "HeapDestroy didn't call OutputDebugStrA\n" ); + ok( test_heap_destroy_break, "HeapDestroy didn't call DbgBreakPoint\n" ); + Peb->BeingDebugged = debugged; + + RtlRemoveVectoredExceptionHandler( handler ); +} + START_TEST(rtl) { InitFunctionPtrs(); @@ -3640,4 +3705,5 @@ START_TEST(rtl) test_RtlMakeSelfRelativeSD(); test_LdrRegisterDllNotification(); test_DbgPrint(); + test_RtlDestroyHeap(); }