diff --git a/src/samples/test-sample/test.cpp b/src/samples/test-sample/test.cpp index a08be686..e8b6fe12 100644 --- a/src/samples/test-sample/test.cpp +++ b/src/samples/test-sample/test.cpp @@ -646,10 +646,105 @@ namespace return res; } + + INT32 test_guard_page_seh_filter(LPVOID address, DWORD code, struct _EXCEPTION_POINTERS* ep) + { + // We are only looking for guard page exceptions. + if (code != STATUS_GUARD_PAGE_VIOLATION) + { + return EXCEPTION_CONTINUE_SEARCH; + } + + // The number of defined elements in the ExceptionInformation array for + // a guard page violation should be 2. + if (ep->ExceptionRecord->NumberParameters != 2) + { + return EXCEPTION_CONTINUE_SEARCH; + } + + // The ExceptionInformation array specifies additional arguments that + // describe the exception. + auto *exception_information = ep->ExceptionRecord->ExceptionInformation; + + // If this value is zero, the thread attempted to read the inaccessible + // data. If this value is 1, the thread attempted to write to an + // inaccessible address. + if (exception_information[0] != 1) + { + return EXCEPTION_CONTINUE_SEARCH; + } + + // The second array element specifies the virtual address of the + // inaccessible data. + if (exception_information[1] != (ULONG_PTR)address) + { + return EXCEPTION_CONTINUE_SEARCH; + } + + return EXCEPTION_EXECUTE_HANDLER; + } + + bool test_guard_page_exception() + { + SYSTEM_INFO sys_info; + GetSystemInfo(&sys_info); + + // Allocate a guarded memory region with the length of the system page + // size. + auto *addr = static_cast(VirtualAlloc( + nullptr, + sys_info.dwPageSize, + MEM_RESERVE | MEM_COMMIT, + PAGE_READWRITE | PAGE_GUARD + )); + if (addr == nullptr) + { + puts("Failed to allocate guard page"); + return false; + } + + bool success = false; + + // We want to access some arbitrary offset into the guarded page, to + // ensure that ExceptionInformation correctly contains the virtual + // address of the inaccessible data, not the base address of the region. + constexpr size_t offset = 10; + + // Trigger a guard page violation + __try + { + addr[offset] = 255; + } + // If the filter function returns EXCEPTION_CONTINUE_SEARCH, the + // exception contains all of the correct information. + __except(test_guard_page_seh_filter( + addr + offset, + GetExceptionCode(), + GetExceptionInformation())) + { + success = true; + } + + // The page guard should be lifted, so no exception should be raised. + __try { + // The previous write should not have went through, this is probably + // superflous. + if (addr[offset] == 255) { + success = false; + } + } + __except(EXCEPTION_EXECUTE_HANDLER) + { + puts("Failed to read from page after guard exception!"); + success = false; + } + + return success; + } bool test_native_exceptions() { - return test_access_violation_exception() && test_illegal_instruction_exception(); + return test_access_violation_exception() && test_illegal_instruction_exception() && test_guard_page_exception(); } #endif @@ -721,101 +816,6 @@ namespace SleepEx(1, TRUE); return executions == 2; } - - INT32 test_guard_page_seh_filter(LPVOID address, DWORD code, struct _EXCEPTION_POINTERS* ep) - { - // We are only looking for guard page exceptions. - if (code != STATUS_GUARD_PAGE_VIOLATION) - { - return EXCEPTION_CONTINUE_SEARCH; - } - - // The number of defined elements in the ExceptionInformation array for - // a guard page violation should be 2. - if (ep->ExceptionRecord->NumberParameters != 2) - { - return EXCEPTION_CONTINUE_SEARCH; - } - - // The ExceptionInformation array specifies additional arguments that - // describe the exception. - auto *exception_information = ep->ExceptionRecord->ExceptionInformation; - - // If this value is zero, the thread attempted to read the inaccessible - // data. If this value is 1, the thread attempted to write to an - // inaccessible address. - if (exception_information[0] != 1) - { - return EXCEPTION_CONTINUE_SEARCH; - } - - // The second array element specifies the virtual address of the - // inaccessible data. - if (exception_information[1] != (ULONG_PTR)address) - { - return EXCEPTION_CONTINUE_SEARCH; - } - - return EXCEPTION_EXECUTE_HANDLER; - } - - bool test_guard_page() - { - SYSTEM_INFO sys_info; - GetSystemInfo(&sys_info); - - // Allocate a guarded memory region with the length of the system page - // size. - auto *addr = static_cast(VirtualAlloc( - nullptr, - sys_info.dwPageSize, - MEM_RESERVE | MEM_COMMIT, - PAGE_READWRITE | PAGE_GUARD - )); - if (addr == nullptr) - { - puts("Failed to allocate guard page"); - return false; - } - - bool success = false; - - // We want to access some arbitrary offset into the guarded page, to - // ensure that ExceptionInformation correctly contains the virtual - // address of the inaccessible data, not the base address of the region. - constexpr size_t offset = 10; - - // Trigger a guard page violation - __try - { - addr[offset] = 255; - } - // If the filter function returns EXCEPTION_CONTINUE_SEARCH, the - // exception contains all of the correct information. - __except(test_guard_page_seh_filter( - addr + offset, - GetExceptionCode(), - GetExceptionInformation())) - { - success = true; - } - - // The page guard should be lifted, so no exception should be raised. - __try { - // The previous write should not have went through, this is probably - // superflous. - if (addr[offset] == 255) { - success = false; - } - } - __except(EXCEPTION_EXECUTE_HANDLER) - { - puts("Failed to read from page after guard exception!"); - success = false; - } - - return success; - } } #define RUN_TEST(func, name) \ @@ -856,7 +856,6 @@ int main(const int argc, const char* argv[]) RUN_TEST(test_tls, "TLS") RUN_TEST(test_socket, "Socket") RUN_TEST(test_apc, "APC") - RUN_TEST(test_guard_page, "Guard Page") return valid ? 0 : 1; }