| OLD | NEW |
| 1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "gtest/gtest.h" | 5 #include "gtest/gtest.h" |
| 6 #include "chrome_frame/exception_barrier.h" | 6 #include "chrome_frame/exception_barrier.h" |
| 7 | 7 |
| 8 namespace { | 8 namespace { |
| 9 | 9 |
| 10 // retrieves the top SEH registration record | 10 // retrieves the top SEH registration record |
| (...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 68 } | 68 } |
| 69 } | 69 } |
| 70 | 70 |
| 71 void AccessViolationCrash() { | 71 void AccessViolationCrash() { |
| 72 volatile char* null = NULL; | 72 volatile char* null = NULL; |
| 73 *null = '\0'; | 73 *null = '\0'; |
| 74 } | 74 } |
| 75 | 75 |
| 76 // A simple crash over the exception barrier | 76 // A simple crash over the exception barrier |
| 77 void CrashOverExceptionBarrier() { | 77 void CrashOverExceptionBarrier() { |
| 78 ExceptionBarrier barrier; | 78 ExceptionBarrierCustomHandler barrier; |
| 79 | 79 |
| 80 TestSEHChainSane(); | 80 TestSEHChainSane(); |
| 81 | 81 |
| 82 AccessViolationCrash(); | 82 AccessViolationCrash(); |
| 83 | 83 |
| 84 TestSEHChainSane(); | 84 TestSEHChainSane(); |
| 85 } | 85 } |
| 86 | 86 |
| 87 #pragma warning(push) | 87 #pragma warning(push) |
| 88 // Inline asm assigning to 'FS:0' : handler not registered as safe handler | 88 // Inline asm assigning to 'FS:0' : handler not registered as safe handler |
| 89 // This warning is in error (the compiler can't know that we register the | 89 // This warning is in error (the compiler can't know that we register the |
| 90 // handler as a safe SEH handler in an .asm file) | 90 // handler as a safe SEH handler in an .asm file) |
| 91 #pragma warning(disable:4733) | 91 #pragma warning(disable:4733) |
| 92 // Hand-generate an SEH frame implicating the ExceptionBarrierHandler, | 92 // Hand-generate an SEH frame implicating the ExceptionBarrierCallCustomHandler, |
| 93 // then crash to invoke it. | 93 // then crash to invoke it. |
| 94 __declspec(naked) void CrashOnManualSEHBarrierHandler() { | 94 __declspec(naked) void CrashOnManualSEHBarrierHandler() { |
| 95 __asm { | 95 __asm { |
| 96 push ExceptionBarrierHandler | 96 push ExceptionBarrierCallCustomHandler |
| 97 push FS:0 | 97 push FS:0 |
| 98 mov FS:0, esp | 98 mov FS:0, esp |
| 99 call AccessViolationCrash | 99 call AccessViolationCrash |
| 100 ret | 100 ret |
| 101 } | 101 } |
| 102 } | 102 } |
| 103 #pragma warning(pop) | 103 #pragma warning(pop) |
| 104 | 104 |
| 105 |
| 105 class ExceptionBarrierTest: public testing::Test { | 106 class ExceptionBarrierTest: public testing::Test { |
| 106 public: | 107 public: |
| 107 ExceptionBarrierTest() : old_handler_(NULL) { | 108 ExceptionBarrierTest() { |
| 108 } | 109 } |
| 109 | 110 |
| 110 // Install an exception handler for the ExceptionBarrier, and | 111 // Install an exception handler for the ExceptionBarrier, and |
| 111 // set the handled flag to false. This allows us to see whether | 112 // set the handled flag to false. This allows us to see whether |
| 112 // the ExceptionBarrier gets to handle the exception | 113 // the ExceptionBarrier gets to handle the exception |
| 113 virtual void SetUp() { | 114 virtual void SetUp() { |
| 114 old_handler_ = ExceptionBarrier::handler(); | 115 ExceptionBarrierConfig::set_enabled(true); |
| 115 ExceptionBarrier::set_handler(ExceptionHandler); | 116 ExceptionBarrierCustomHandler::set_custom_handler(&ExceptionHandler); |
| 116 s_handled_ = false; | 117 s_handled_ = false; |
| 117 | 118 |
| 118 TestSEHChainSane(); | 119 TestSEHChainSane(); |
| 119 } | 120 } |
| 120 | 121 |
| 121 virtual void TearDown() { | 122 virtual void TearDown() { |
| 122 ExceptionBarrier::set_handler(old_handler_); | |
| 123 | |
| 124 TestSEHChainSane(); | 123 TestSEHChainSane(); |
| 124 ExceptionBarrierCustomHandler::set_custom_handler(NULL); |
| 125 ExceptionBarrierConfig::set_enabled(false); |
| 125 } | 126 } |
| 126 | 127 |
| 127 // The exception notification callback, sets the handled flag. | 128 // The exception notification callback, sets the handled flag. |
| 128 static void CALLBACK ExceptionHandler(EXCEPTION_POINTERS* ptrs) { | 129 static void CALLBACK ExceptionHandler(EXCEPTION_POINTERS* ptrs) { |
| 129 TestSEHChainSane(); | 130 TestSEHChainSane(); |
| 130 | |
| 131 s_handled_ = true; | 131 s_handled_ = true; |
| 132 } | 132 } |
| 133 | 133 |
| 134 // Old handler to restore on TearDown | |
| 135 ExceptionBarrier::ExceptionHandler old_handler_; | |
| 136 | |
| 137 // Flag is set by handler | 134 // Flag is set by handler |
| 138 static bool s_handled_; | 135 static bool s_handled_; |
| 139 }; | 136 }; |
| 140 | 137 |
| 141 bool ExceptionBarrierTest::s_handled_; | 138 bool ExceptionBarrierTest::s_handled_ = false; |
| 142 | 139 |
| 143 bool TestExceptionExceptionBarrierHandler() { | 140 bool TestExceptionExceptionBarrierHandler() { |
| 144 TestSEHChainSane(); | 141 TestSEHChainSane(); |
| 145 __try { | 142 __try { |
| 146 CrashOnManualSEHBarrierHandler(); | 143 CrashOnManualSEHBarrierHandler(); |
| 147 return false; // not reached | 144 return false; // not reached |
| 148 } __except(EXCEPTION_ACCESS_VIOLATION == GetExceptionCode() ? | 145 } __except(EXCEPTION_ACCESS_VIOLATION == GetExceptionCode() ? |
| 149 EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH) { | 146 EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH) { |
| 150 TestSEHChainSane(); | 147 TestSEHChainSane(); |
| 151 return true; | 148 return true; |
| (...skipping 112 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 264 } __except(EXCEPTION_EXECUTE_HANDLER) { | 261 } __except(EXCEPTION_EXECUTE_HANDLER) { |
| 265 // we should have unrolled to our frame by now | 262 // we should have unrolled to our frame by now |
| 266 if (GetTopRegistration() != my_top) | 263 if (GetTopRegistration() != my_top) |
| 267 return false; | 264 return false; |
| 268 } | 265 } |
| 269 | 266 |
| 270 return true; | 267 return true; |
| 271 } | 268 } |
| 272 | 269 |
| 273 void RecurseAndCrashOverBarrier(int depth, bool crash) { | 270 void RecurseAndCrashOverBarrier(int depth, bool crash) { |
| 274 ExceptionBarrier barrier; | 271 ExceptionBarrierCustomHandler barrier; |
| 275 | 272 |
| 276 if (0 == depth) { | 273 if (0 == depth) { |
| 277 if (crash) | 274 if (crash) |
| 278 AccessViolationCrash(); | 275 AccessViolationCrash(); |
| 279 } else { | 276 } else { |
| 280 RecurseAndCrashOverBarrier(depth - 1, crash); | 277 RecurseAndCrashOverBarrier(depth - 1, crash); |
| 281 } | 278 } |
| 282 } | 279 } |
| 283 | 280 |
| 284 // Test that ExceptionBarrier doesn't molest the SEH chain, neither | 281 // Test that ExceptionBarrier doesn't molest the SEH chain, neither |
| (...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 352 return TestRegularChaining(top) && TestExceptionBarrierChaining(top); | 349 return TestRegularChaining(top) && TestExceptionBarrierChaining(top); |
| 353 } | 350 } |
| 354 | 351 |
| 355 // Test that the SEH chain is unmolested by exception barrier, both under | 352 // Test that the SEH chain is unmolested by exception barrier, both under |
| 356 // regular unroll, and under exception unroll. | 353 // regular unroll, and under exception unroll. |
| 357 TEST_F(ExceptionBarrierTest, SEHChainIsSaneAfterException) { | 354 TEST_F(ExceptionBarrierTest, SEHChainIsSaneAfterException) { |
| 358 EXPECT_TRUE(TestChaining()); | 355 EXPECT_TRUE(TestChaining()); |
| 359 } | 356 } |
| 360 | 357 |
| 361 } // namespace | 358 } // namespace |
| OLD | NEW |