[NTDLL_WINETEST] Sync with Wine Staging 1.7.55. CORE-10536
[reactos.git] / rostests / winetests / ntdll / exception.c
index 04cea9c..2455e1b 100644 (file)
@@ -33,7 +33,7 @@
 #include "winbase.h"
 #include "winnt.h"
 #include "winreg.h"
-#include "winternl.h"
+#include "wine/winternl.h"
 #include "wine/exception.h"
 #include "wine/test.h"
 
@@ -46,11 +46,14 @@ static NTSTATUS  (WINAPI *pRtlRaiseException)(EXCEPTION_RECORD *rec);
 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);
@@ -936,6 +939,16 @@ static void test_debugger(void)
                         /* 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);
 
@@ -946,13 +959,21 @@ static void test_debugger(void)
         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);
 
@@ -1695,6 +1716,7 @@ static void test_dynamic_unwind(void)
 
 #endif  /* __x86_64__ */
 
+#if defined(__i386__) || defined(__x86_64__)
 static DWORD outputdebugstring_exceptions;
 
 static LONG CALLBACK outputdebugstring_vectored_handler(EXCEPTION_POINTERS *ExceptionInfo)
@@ -1713,7 +1735,7 @@ static LONG CALLBACK outputdebugstring_vectored_handler(EXCEPTION_POINTERS *Exce
     return EXCEPTION_CONTINUE_SEARCH;
 }
 
-static void test_outputdebugstring(DWORD numexc, BOOL todo)
+static void test_outputdebugstring(DWORD numexc)
 {
     PVOID vectored_handler;
 
@@ -1728,13 +1750,8 @@ static void test_outputdebugstring(DWORD numexc, BOOL todo)
 
     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);
 }
@@ -1788,6 +1805,91 @@ static void test_ripevent(DWORD numexc)
     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");
@@ -1802,6 +1904,7 @@ START_TEST(exception)
     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" );
@@ -1809,6 +1912,10 @@ START_TEST(exception)
                                                                  "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,
@@ -1858,13 +1965,17 @@ START_TEST(exception)
             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" );
@@ -1876,8 +1987,10 @@ START_TEST(exception)
     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();
@@ -1894,8 +2007,10 @@ START_TEST(exception)
     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)