OLD | NEW |
(Empty) | |
| 1 // Copyright 2009, Google Inc. |
| 2 // All rights reserved. |
| 3 // |
| 4 // Redistribution and use in source and binary forms, with or without |
| 5 // modification, are permitted provided that the following conditions are |
| 6 // met: |
| 7 // |
| 8 // * Redistributions of source code must retain the above copyright |
| 9 // notice, this list of conditions and the following disclaimer. |
| 10 // * Redistributions in binary form must reproduce the above |
| 11 // copyright notice, this list of conditions and the following disclaimer |
| 12 // in the documentation and/or other materials provided with the |
| 13 // distribution. |
| 14 // * Neither the name of Google Inc. nor the names of its |
| 15 // contributors may be used to endorse or promote products derived from |
| 16 // this software without specific prior written permission. |
| 17 // |
| 18 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
| 19 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
| 20 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
| 21 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
| 22 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
| 23 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
| 24 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
| 25 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
| 26 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| 27 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
| 28 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| 29 |
| 30 #include <windows.h> |
| 31 #include <dbghelp.h> |
| 32 #include <strsafe.h> |
| 33 #include <objbase.h> |
| 34 #include <shellapi.h> |
| 35 |
| 36 #include "../../../breakpad_googletest_includes.h" |
| 37 #include "../crash_generation/crash_generation_server.h" |
| 38 #include "../handler/exception_handler.h" |
| 39 |
| 40 namespace { |
| 41 const wchar_t kPipeName[] = L"\\\\.\\pipe\\BreakpadCrashTest\\TestCaseServer"; |
| 42 const char kSuccessIndicator[] = "success"; |
| 43 const char kFailureIndicator[] = "failure"; |
| 44 |
| 45 // Utility function to test for a path's existence. |
| 46 BOOL DoesPathExist(const TCHAR *path_name); |
| 47 |
| 48 class ExceptionHandlerDeathTest : public ::testing::Test { |
| 49 protected: |
| 50 // Member variable for each test that they can use |
| 51 // for temporary storage. |
| 52 TCHAR temp_path_[MAX_PATH]; |
| 53 // Actually constructs a temp path name. |
| 54 virtual void SetUp(); |
| 55 // A helper method that tests can use to crash. |
| 56 void DoCrash(); |
| 57 }; |
| 58 |
| 59 void ExceptionHandlerDeathTest::SetUp() { |
| 60 const ::testing::TestInfo* const test_info = |
| 61 ::testing::UnitTest::GetInstance()->current_test_info(); |
| 62 TCHAR temp_path[MAX_PATH] = { '\0' }; |
| 63 TCHAR test_name_wide[MAX_PATH] = { '\0' }; |
| 64 // We want the temporary directory to be what the OS returns |
| 65 // to us, + the test case name. |
| 66 GetTempPath(MAX_PATH, temp_path); |
| 67 // THe test case name is exposed to use as a c-style string, |
| 68 // But we might be working in UNICODE here on Windows. |
| 69 int dwRet = MultiByteToWideChar(CP_ACP, 0, test_info->name(), |
| 70 strlen(test_info->name()), |
| 71 test_name_wide, |
| 72 MAX_PATH); |
| 73 if (!dwRet) { |
| 74 assert(false); |
| 75 } |
| 76 StringCchPrintfW(temp_path_, MAX_PATH, L"%s%s", temp_path, test_name_wide); |
| 77 CreateDirectory(temp_path_, NULL); |
| 78 } |
| 79 |
| 80 BOOL DoesPathExist(const TCHAR *path_name) { |
| 81 DWORD flags = GetFileAttributes(path_name); |
| 82 if (flags == INVALID_FILE_ATTRIBUTES) { |
| 83 return FALSE; |
| 84 } |
| 85 return TRUE; |
| 86 } |
| 87 |
| 88 bool MinidumpWrittenCallback(const wchar_t* dump_path, |
| 89 const wchar_t* minidump_id, |
| 90 void* context, |
| 91 EXCEPTION_POINTERS* exinfo, |
| 92 MDRawAssertionInfo* assertion, |
| 93 bool succeeded) { |
| 94 if (succeeded && DoesPathExist(dump_path)) { |
| 95 fprintf(stderr, kSuccessIndicator); |
| 96 } else { |
| 97 fprintf(stderr, kFailureIndicator); |
| 98 } |
| 99 // If we don't flush, the output doesn't get sent before |
| 100 // this process dies. |
| 101 fflush(stderr); |
| 102 return succeeded; |
| 103 } |
| 104 |
| 105 TEST_F(ExceptionHandlerDeathTest, InProcTest) { |
| 106 // For the in-proc test, we just need to instantiate an exception |
| 107 // handler in in-proc mode, and crash. Since the entire test is |
| 108 // reexecuted in the child process, we don't have to worry about |
| 109 // the semantics of the exception handler being inherited/not |
| 110 // inherited across CreateProcess(). |
| 111 ASSERT_TRUE(DoesPathExist(temp_path_)); |
| 112 google_breakpad::ExceptionHandler *exc = |
| 113 new google_breakpad::ExceptionHandler( |
| 114 temp_path_, NULL, &MinidumpWrittenCallback, NULL, |
| 115 google_breakpad::ExceptionHandler::HANDLER_ALL); |
| 116 int *i = NULL; |
| 117 ASSERT_DEATH((*i)++, kSuccessIndicator); |
| 118 delete exc; |
| 119 } |
| 120 |
| 121 static bool gDumpCallbackCalled = false; |
| 122 |
| 123 void clientDumpCallback(void *dump_context, |
| 124 const google_breakpad::ClientInfo *client_info, |
| 125 const std::wstring *dump_path) { |
| 126 gDumpCallbackCalled = true; |
| 127 } |
| 128 |
| 129 void ExceptionHandlerDeathTest::DoCrash() { |
| 130 google_breakpad::ExceptionHandler *exc = |
| 131 new google_breakpad::ExceptionHandler( |
| 132 temp_path_, NULL, NULL, NULL, |
| 133 google_breakpad::ExceptionHandler::HANDLER_ALL, MiniDumpNormal, kPipeName, |
| 134 NULL); |
| 135 // Although this is executing in the child process of the death test, |
| 136 // if it's not true we'll still get an error rather than the crash |
| 137 // being expected. |
| 138 ASSERT_TRUE(exc->IsOutOfProcess()); |
| 139 int *i = NULL; |
| 140 printf("%d\n", (*i)++); |
| 141 } |
| 142 |
| 143 TEST_F(ExceptionHandlerDeathTest, OutOfProcTest) { |
| 144 // We can take advantage of a detail of google test here to save some |
| 145 // complexity in testing: when you do a death test, it actually forks. |
| 146 // So we can make the main test harness the crash generation server, |
| 147 // and call ASSERT_DEATH on a NULL dereference, it to expecting test |
| 148 // the out of process scenario, since it's happening in a different |
| 149 // process! This is different from the above because, above, we pass |
| 150 // a NULL pipe name, and we also don't start a crash generation server. |
| 151 |
| 152 ASSERT_TRUE(DoesPathExist(temp_path_)); |
| 153 std::wstring dump_path(temp_path_); |
| 154 google_breakpad::CrashGenerationServer server( |
| 155 kPipeName, NULL, NULL, NULL, &clientDumpCallback, NULL, NULL, NULL, true, |
| 156 &dump_path); |
| 157 |
| 158 // This HAS to be EXPECT_, because when this test case is executed in the |
| 159 // child process, the server registration will fail due to the named pipe |
| 160 // being the same. |
| 161 EXPECT_TRUE(server.Start()); |
| 162 EXPECT_FALSE(gDumpCallbackCalled); |
| 163 ASSERT_DEATH(this->DoCrash(), ""); |
| 164 EXPECT_TRUE(gDumpCallbackCalled); |
| 165 } |
| 166 } |
OLD | NEW |