#include "winbase.h"
#include "winnt.h"
#include "winreg.h"
-#include "winternl.h"
+#include "wine/winternl.h"
#include "wine/exception.h"
#include "wine/test.h"
static PVOID (WINAPI *pRtlUnwind)(PVOID, PVOID, PEXCEPTION_RECORD, PVOID);
static PVOID (WINAPI *pRtlAddVectoredExceptionHandler)(ULONG first, PVECTORED_EXCEPTION_HANDLER func);
static ULONG (WINAPI *pRtlRemoveVectoredExceptionHandler)(PVOID handler);
+static PVOID (WINAPI *pRtlAddVectoredContinueHandler)(ULONG first, PVECTORED_EXCEPTION_HANDLER func);
+static ULONG (WINAPI *pRtlRemoveVectoredContinueHandler)(PVOID handler);
static NTSTATUS (WINAPI *pNtReadVirtualMemory)(HANDLE, const void*, void*, SIZE_T, SIZE_T*);
static NTSTATUS (WINAPI *pNtTerminateProcess)(HANDLE handle, LONG exit_code);
static NTSTATUS (WINAPI *pNtQueryInformationProcess)(HANDLE, PROCESSINFOCLASS, PVOID, ULONG, PULONG);
static NTSTATUS (WINAPI *pNtSetInformationProcess)(HANDLE, PROCESSINFOCLASS, PVOID, ULONG);
static BOOL (WINAPI *pIsWow64Process)(HANDLE, PBOOL);
+static NTSTATUS (WINAPI *pNtClose)(HANDLE);
#if defined(__x86_64__)
static BOOLEAN (CDECL *pRtlAddFunctionTable)(RUNTIME_FUNCTION*, DWORD, DWORD64);
/* here we handle exception */
}
}
+ else if (stage == 7 || stage == 8)
+ {
+ ok(de.u.Exception.ExceptionRecord.ExceptionCode == EXCEPTION_INVALID_HANDLE,
+ "unexpected exception code %08x, expected %08x\n", de.u.Exception.ExceptionRecord.ExceptionCode,
+ EXCEPTION_INVALID_HANDLE);
+ ok(de.u.Exception.ExceptionRecord.NumberParameters == 0,
+ "unexpected number of parameters %d, expected 0\n", de.u.Exception.ExceptionRecord.NumberParameters);
+
+ if (stage == 8) continuestatus = DBG_EXCEPTION_NOT_HANDLED;
+ }
else
ok(FALSE, "unexpected stage %x\n", stage);
else if (de.dwDebugEventCode == OUTPUT_DEBUG_STRING_EVENT)
{
int stage;
+#ifdef __REACTOS__
+ /* This will catch our DPRINTs, such as
+ * "WARNING: RtlpDphTargetDllsLogicInitialize at ..\..\lib\rtl\heappage.c:1283 is UNIMPLEMENTED!"
+ * so we need a full-size buffer to avoid a stack overflow
+ */
+ char buffer[513];
+#else
char buffer[64];
+#endif
status = pNtReadVirtualMemory(pi.hProcess, &test_stage, &stage,
sizeof(stage), &size_read);
ok(!status,"NtReadVirtualMemory failed with 0x%x\n", status);
- ok(!de.u.DebugString.fUnicode, "unepxected unicode debug string event\n");
+ ok(!de.u.DebugString.fUnicode, "unexpected unicode debug string event\n");
ok(de.u.DebugString.nDebugStringLength < sizeof(buffer) - 1, "buffer not large enough to hold %d bytes\n",
de.u.DebugString.nDebugStringLength);
#endif /* __x86_64__ */
+#if defined(__i386__) || defined(__x86_64__)
static DWORD outputdebugstring_exceptions;
static LONG CALLBACK outputdebugstring_vectored_handler(EXCEPTION_POINTERS *ExceptionInfo)
return EXCEPTION_CONTINUE_SEARCH;
}
-static void test_outputdebugstring(DWORD numexc, BOOL todo)
+static void test_outputdebugstring(DWORD numexc)
{
PVOID vectored_handler;
outputdebugstring_exceptions = 0;
OutputDebugStringA("Hello World");
- if (todo)
- todo_wine
- ok(outputdebugstring_exceptions == numexc, "OutputDebugStringA generated %d exceptions, expected %d\n",
- outputdebugstring_exceptions, numexc);
- else
- ok(outputdebugstring_exceptions == numexc, "OutputDebugStringA generated %d exceptions, expected %d\n",
- outputdebugstring_exceptions, numexc);
+ ok(outputdebugstring_exceptions == numexc, "OutputDebugStringA generated %d exceptions, expected %d\n",
+ outputdebugstring_exceptions, numexc);
pRtlRemoveVectoredExceptionHandler(vectored_handler);
}
pRtlRemoveVectoredExceptionHandler(vectored_handler);
}
+static DWORD invalid_handle_exceptions;
+
+static LONG CALLBACK invalid_handle_vectored_handler(EXCEPTION_POINTERS *ExceptionInfo)
+{
+ PEXCEPTION_RECORD rec = ExceptionInfo->ExceptionRecord;
+ trace("vect. handler %08x addr:%p\n", rec->ExceptionCode, rec->ExceptionAddress);
+
+ ok(rec->ExceptionCode == EXCEPTION_INVALID_HANDLE, "ExceptionCode is %08x instead of %08x\n",
+ rec->ExceptionCode, EXCEPTION_INVALID_HANDLE);
+ ok(rec->NumberParameters == 0, "ExceptionParameters is %d instead of 0\n", rec->NumberParameters);
+
+ invalid_handle_exceptions++;
+ return (rec->ExceptionCode == EXCEPTION_INVALID_HANDLE) ? EXCEPTION_CONTINUE_EXECUTION : EXCEPTION_CONTINUE_SEARCH;
+}
+
+static void test_closehandle(DWORD numexc)
+{
+ PVOID vectored_handler;
+ NTSTATUS status;
+ DWORD res;
+
+ if (!pRtlAddVectoredExceptionHandler || !pRtlRemoveVectoredExceptionHandler || !pRtlRaiseException)
+ {
+ skip("RtlAddVectoredExceptionHandler or RtlRemoveVectoredExceptionHandler or RtlRaiseException not found\n");
+ return;
+ }
+
+ vectored_handler = pRtlAddVectoredExceptionHandler(TRUE, &invalid_handle_vectored_handler);
+ ok(vectored_handler != 0, "RtlAddVectoredExceptionHandler failed\n");
+
+ invalid_handle_exceptions = 0;
+ res = CloseHandle((HANDLE)0xdeadbeef);
+ ok(!res, "CloseHandle(0xdeadbeef) unexpectedly succeeded\n");
+ ok(GetLastError() == ERROR_INVALID_HANDLE, "wrong error code %d instead of %d\n",
+ GetLastError(), ERROR_INVALID_HANDLE);
+ ok(invalid_handle_exceptions == numexc, "CloseHandle generated %d exceptions, expected %d\n",
+ invalid_handle_exceptions, numexc);
+
+ invalid_handle_exceptions = 0;
+ status = pNtClose((HANDLE)0xdeadbeef);
+ ok(status == STATUS_INVALID_HANDLE, "NtClose(0xdeadbeef) returned status %08x\n", status);
+ ok(invalid_handle_exceptions == numexc, "NtClose generated %d exceptions, expected %d\n",
+ invalid_handle_exceptions, numexc);
+
+ pRtlRemoveVectoredExceptionHandler(vectored_handler);
+}
+
+static void test_vectored_continue_handler(void)
+{
+ PVOID handler1, handler2;
+ ULONG ret;
+
+ if (!pRtlAddVectoredContinueHandler || !pRtlRemoveVectoredContinueHandler)
+ {
+ skip("RtlAddVectoredContinueHandler or RtlRemoveVectoredContinueHandler not found\n");
+ return;
+ }
+
+ handler1 = pRtlAddVectoredContinueHandler(TRUE, (void *)0xdeadbeef);
+ ok(handler1 != 0, "RtlAddVectoredContinueHandler failed\n");
+
+ handler2 = pRtlAddVectoredContinueHandler(TRUE, (void *)0xdeadbeef);
+ ok(handler2 != 0, "RtlAddVectoredContinueHandler failed\n");
+ ok(handler1 != handler2, "RtlAddVectoredContinueHandler returned same handler\n");
+
+ if (pRtlRemoveVectoredExceptionHandler)
+ {
+ ret = pRtlRemoveVectoredExceptionHandler(handler1);
+ ok(!ret, "RtlRemoveVectoredExceptionHandler succeeded\n");
+ }
+
+ ret = pRtlRemoveVectoredContinueHandler(handler1);
+ ok(ret, "RtlRemoveVectoredContinueHandler failed\n");
+
+ ret = pRtlRemoveVectoredContinueHandler(handler2);
+ ok(ret, "RtlRemoveVectoredContinueHandler failed\n");
+
+ ret = pRtlRemoveVectoredContinueHandler(handler1);
+ ok(!ret, "RtlRemoveVectoredContinueHandler succeeded\n");
+
+ ret = pRtlRemoveVectoredContinueHandler((void *)0x11223344);
+ ok(!ret, "RtlRemoveVectoredContinueHandler succeeded\n");
+}
+#endif /* defined(__i386__) || defined(__x86_64__) */
+
START_TEST(exception)
{
HMODULE hntdll = GetModuleHandleA("ntdll.dll");
pNtGetContextThread = (void *)GetProcAddress( hntdll, "NtGetContextThread" );
pNtSetContextThread = (void *)GetProcAddress( hntdll, "NtSetContextThread" );
pNtReadVirtualMemory = (void *)GetProcAddress( hntdll, "NtReadVirtualMemory" );
+ pNtClose = (void *)GetProcAddress( hntdll, "NtClose" );
pRtlUnwind = (void *)GetProcAddress( hntdll, "RtlUnwind" );
pRtlRaiseException = (void *)GetProcAddress( hntdll, "RtlRaiseException" );
pNtTerminateProcess = (void *)GetProcAddress( hntdll, "NtTerminateProcess" );
"RtlAddVectoredExceptionHandler" );
pRtlRemoveVectoredExceptionHandler = (void *)GetProcAddress( hntdll,
"RtlRemoveVectoredExceptionHandler" );
+ pRtlAddVectoredContinueHandler = (void *)GetProcAddress( hntdll,
+ "RtlAddVectoredContinueHandler" );
+ pRtlRemoveVectoredContinueHandler = (void *)GetProcAddress( hntdll,
+ "RtlRemoveVectoredContinueHandler" );
pNtQueryInformationProcess = (void*)GetProcAddress( hntdll,
"NtQueryInformationProcess" );
pNtSetInformationProcess = (void*)GetProcAddress( hntdll,
run_rtlraiseexception_test(EXCEPTION_BREAKPOINT);
run_rtlraiseexception_test(EXCEPTION_INVALID_HANDLE);
test_stage = 3;
- test_outputdebugstring(0, FALSE);
+ test_outputdebugstring(0);
test_stage = 4;
- test_outputdebugstring(2, TRUE); /* is this a Windows bug? */
+ test_outputdebugstring(2);
test_stage = 5;
test_ripevent(0);
test_stage = 6;
test_ripevent(1);
+ test_stage = 7;
+ test_closehandle(0);
+ test_stage = 8;
+ test_closehandle(1);
}
else
skip( "RtlRaiseException not found\n" );
test_unwind();
test_exceptions();
test_rtlraiseexception();
- test_outputdebugstring(1, FALSE);
+ test_outputdebugstring(1);
test_ripevent(1);
+ test_closehandle(0);
+ test_vectored_continue_handler();
test_debugger();
test_simd_exceptions();
test_fpu_exceptions();
pRtlLookupFunctionEntry = (void *)GetProcAddress( hntdll,
"RtlLookupFunctionEntry" );
- test_outputdebugstring(1, FALSE);
+ test_outputdebugstring(1);
test_ripevent(1);
+ test_closehandle(0);
+ test_vectored_continue_handler();
test_virtual_unwind();
if (pRtlAddFunctionTable && pRtlDeleteFunctionTable && pRtlInstallFunctionTableCallback && pRtlLookupFunctionEntry)