// utxcpt4.c - user mode seh test #3. #include // Define function prototypes. VOID bar (IN NTSTATUS Status, IN PULONG Counter); VOID eret (IN NTSTATUS Status, IN PULONG Counter); VOID foo (IN NTSTATUS Status); VOID fret (IN PULONG Counter); BOOLEAN Tkm (VOID); // Define static storage. PTESTFCN TestFunction = Tkm; main() { Tkm(); } BOOLEAN Tkm () { EXCEPTION_RECORD ExceptionRecord; LONG Counter; // Announce start of exception test. DbgPrint("Start of exception test\n"); // Initialize exception record. ExceptionRecord.ExceptionCode = STATUS_INTEGER_OVERFLOW; ExceptionRecord.ExceptionFlags = 0; ExceptionRecord.ExceptionRecord = NULL; ExceptionRecord.NumberParameters = 0; // Simply try statement with a finally clause that is entered sequentially. DbgPrint(" test1..."); Counter = 0; try { Counter += 1; } finally { if (abnormal_termination() == FALSE) { Counter += 1; } } if (Counter != 2) { DbgPrint("failed\n"); } else { DbgPrint("succeeded\n"); } // Simple try statement with an exception clause that is never executed // because there is no exception raised in the try clause. DbgPrint(" test2..."); Counter = 0; try { Counter += 1; } except (Counter) { Counter += 1; } if (Counter != 1) { DbgPrint("failed\n"); } else { DbgPrint("succeeded\n"); } // Simple try statement with an exception handler that is never executed // because the exception expression continues execution. DbgPrint(" test3..."); Counter = 0; try { Counter -= 1; RtlRaiseException(&ExceptionRecord); } except (Counter) { Counter -= 1; } if (Counter != - 1) { DbgPrint("failed\n"); } else { DbgPrint("succeeded\n"); } // Simple try statement with an exception clause that is always executed. DbgPrint(" test4..."); Counter = 0; try { Counter += 1; RtlRaiseStatus(STATUS_INTEGER_OVERFLOW); } except (Counter) { Counter += 1; } if (Counter != 2) { DbgPrint("failed\n"); } else { DbgPrint("succeeded\n"); } // Simply try statement with a finally clause that is entered as the // result of an exception. DbgPrint(" test5..."); Counter = 0; try { try { Counter += 1; RtlRaiseException(&ExceptionRecord); } finally { if (abnormal_termination() != FALSE) { Counter += 1; } } } except (Counter) { if (Counter == 2) { Counter += 1; } } if (Counter != 3) { DbgPrint("failed\n"); } else { DbgPrint("succeeded\n"); } // Simple try that calls a function which raises an exception. DbgPrint(" test6..."); Counter = 0; try { Counter += 1; foo(STATUS_ACCESS_VIOLATION); } except ((GetExceptionCode() == STATUS_ACCESS_VIOLATION) ? EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH) { Counter += 1; } if (Counter != 2) { DbgPrint("failed\n"); } else { DbgPrint("succeeded\n"); } // Simple try that calls a function which calls a function that // raises an exception. The first function has a finally clause // that must be executed for this test to work. DbgPrint(" test7..."); Counter = 0; try { bar(STATUS_ACCESS_VIOLATION, (PULONG)&Counter); } except ((GetExceptionCode() == STATUS_ACCESS_VIOLATION) ? EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH) { Counter -= 1; } if (Counter != 98) { DbgPrint("failed\n"); } else { DbgPrint("succeeded\n"); } // A try within an except DbgPrint(" test8..."); Counter = 0; try { foo(STATUS_ACCESS_VIOLATION); } except ((GetExceptionCode() == STATUS_ACCESS_VIOLATION) ? EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH) { Counter += 1; try { foo(STATUS_SUCCESS); } except ((GetExceptionCode() == STATUS_SUCCESS) ? EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH) { if (Counter != 1) { DbgPrint("failed..."); } else { DbgPrint("succeeded..."); } Counter += 1; } } if (Counter != 2) { DbgPrint("failed\n"); } else { DbgPrint("succeeded\n"); } // A goto from an exception clause that needs to pass // through a finally DbgPrint(" test9..."); Counter = 0; try { try { foo(STATUS_ACCESS_VIOLATION); } except ((GetExceptionCode() == STATUS_ACCESS_VIOLATION) ? EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH) { Counter += 1; goto t9; } } finally { Counter += 1; } t9:; if (Counter != 2) { DbgPrint("failed\n"); } else { DbgPrint("succeeded\n"); } // A goto from an finally clause that needs to pass // through a finally DbgPrint(" test10..."); Counter = 0; try { try { Counter += 1; } finally { Counter += 1; goto t10; } } finally { Counter += 1; } t10:; if (Counter != 3) { DbgPrint("failed\n"); } else { DbgPrint("succeeded\n"); } // A goto from an exception clause that needs to pass // through a finally into the outer finally clause. DbgPrint(" test11..."); Counter = 0; try { try { try { Counter += 1; foo(STATUS_INTEGER_OVERFLOW); } except (EXCEPTION_EXECUTE_HANDLER) { Counter += 1; goto t11; } } finally { Counter += 1; } t11:; } finally { Counter += 1; } if (Counter != 4) { DbgPrint("failed\n"); } else { DbgPrint("succeeded\n"); } // A goto from an finally clause that needs to pass // through a finally into the outer finally clause. DbgPrint(" test12..."); Counter = 0; try { try { Counter += 1; } finally { Counter += 1; goto t12; } t12:; } finally { Counter += 1; } if (Counter != 3) { DbgPrint("failed\n"); } else { DbgPrint("succeeded\n"); } // A return from an except clause DbgPrint(" test13..."); Counter = 0; try { Counter += 1; eret(STATUS_ACCESS_VIOLATION, (PULONG)&Counter); } finally { Counter += 1; } if (Counter != 4) { DbgPrint("failed\n"); } else { DbgPrint("succeeded\n"); } // A return from a finally clause DbgPrint(" test14..."); Counter = 0; try { Counter += 1; fret((PULONG)&Counter); } finally { Counter += 1; } if (Counter != 5) { DbgPrint("failed\n"); } else { DbgPrint("succeeded\n"); } // Announce end of exception test. DbgPrint("End of exception test\n"); return TRUE; } VOID fret( IN PULONG Counter ) { try { try { *Counter += 1; } finally { *Counter += 1; return; } } finally { *Counter += 1; } return; } VOID eret( IN NTSTATUS Status, IN PULONG Counter ) { try { try { foo(Status); } except ((GetExceptionCode() == Status) ? EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH) { *Counter += 1; return; } } finally { *Counter += 1; } return; } VOID bar ( IN NTSTATUS Status, IN PULONG Counter ) { try { foo(Status); } finally { if (abnormal_termination() != FALSE) { *Counter = 99; } else { *Counter = 100; } } return; } VOID foo( IN NTSTATUS Status ) { // Raise exception. RtlRaiseStatus(Status); return; }