Home | History | Annotate | Download | only in unittests
      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 <string>
     37 
     38 #include "breakpad_googletest_includes.h"
     39 #include "client/windows/crash_generation/crash_generation_server.h"
     40 #include "client/windows/handler/exception_handler.h"
     41 #include "client/windows/unittests/exception_handler_test.h"
     42 #include "common/windows/string_utils-inl.h"
     43 #include "google_breakpad/processor/minidump.h"
     44 
     45 namespace {
     46 
     47 using std::wstring;
     48 using namespace google_breakpad;
     49 
     50 const wchar_t kPipeName[] = L"\\\\.\\pipe\\BreakpadCrashTest\\TestCaseServer";
     51 const char kSuccessIndicator[] = "success";
     52 const char kFailureIndicator[] = "failure";
     53 
     54 // Utility function to test for a path's existence.
     55 BOOL DoesPathExist(const TCHAR *path_name);
     56 
     57 enum OutOfProcGuarantee {
     58   OUT_OF_PROC_GUARANTEED,
     59   OUT_OF_PROC_BEST_EFFORT,
     60 };
     61 
     62 class ExceptionHandlerDeathTest : public ::testing::Test {
     63  protected:
     64   // Member variable for each test that they can use
     65   // for temporary storage.
     66   TCHAR temp_path_[MAX_PATH];
     67   // Actually constructs a temp path name.
     68   virtual void SetUp();
     69   // A helper method that tests can use to crash.
     70   void DoCrashAccessViolation(const OutOfProcGuarantee out_of_proc_guarantee);
     71   void DoCrashPureVirtualCall();
     72 };
     73 
     74 void ExceptionHandlerDeathTest::SetUp() {
     75   const ::testing::TestInfo* const test_info =
     76     ::testing::UnitTest::GetInstance()->current_test_info();
     77   TCHAR temp_path[MAX_PATH] = { '\0' };
     78   TCHAR test_name_wide[MAX_PATH] = { '\0' };
     79   // We want the temporary directory to be what the OS returns
     80   // to us, + the test case name.
     81   GetTempPath(MAX_PATH, temp_path);
     82   // The test case name is exposed as a c-style string,
     83   // convert it to a wchar_t string.
     84   int dwRet = MultiByteToWideChar(CP_ACP, 0, test_info->name(),
     85                                   strlen(test_info->name()),
     86                                   test_name_wide,
     87                                   MAX_PATH);
     88   if (!dwRet) {
     89     assert(false);
     90   }
     91   StringCchPrintfW(temp_path_, MAX_PATH, L"%s%s", temp_path, test_name_wide);
     92   CreateDirectory(temp_path_, NULL);
     93 }
     94 
     95 BOOL DoesPathExist(const TCHAR *path_name) {
     96   DWORD flags = GetFileAttributes(path_name);
     97   if (flags == INVALID_FILE_ATTRIBUTES) {
     98     return FALSE;
     99   }
    100   return TRUE;
    101 }
    102 
    103 bool MinidumpWrittenCallback(const wchar_t* dump_path,
    104                              const wchar_t* minidump_id,
    105                              void* context,
    106                              EXCEPTION_POINTERS* exinfo,
    107                              MDRawAssertionInfo* assertion,
    108                              bool succeeded) {
    109   if (succeeded && DoesPathExist(dump_path)) {
    110     fprintf(stderr, kSuccessIndicator);
    111   } else {
    112     fprintf(stderr, kFailureIndicator);
    113   }
    114   // If we don't flush, the output doesn't get sent before
    115   // this process dies.
    116   fflush(stderr);
    117   return succeeded;
    118 }
    119 
    120 TEST_F(ExceptionHandlerDeathTest, InProcTest) {
    121   // For the in-proc test, we just need to instantiate an exception
    122   // handler in in-proc mode, and crash.   Since the entire test is
    123   // reexecuted in the child process, we don't have to worry about
    124   // the semantics of the exception handler being inherited/not
    125   // inherited across CreateProcess().
    126   ASSERT_TRUE(DoesPathExist(temp_path_));
    127   scoped_ptr<google_breakpad::ExceptionHandler> exc(
    128       new google_breakpad::ExceptionHandler(
    129           temp_path_,
    130           NULL,
    131           &MinidumpWrittenCallback,
    132           NULL,
    133           google_breakpad::ExceptionHandler::HANDLER_ALL));
    134 
    135   // Disable GTest SEH handler
    136   testing::DisableExceptionHandlerInScope disable_exception_handler;
    137 
    138   int *i = NULL;
    139   ASSERT_DEATH((*i)++, kSuccessIndicator);
    140 }
    141 
    142 static bool gDumpCallbackCalled = false;
    143 
    144 void clientDumpCallback(void *dump_context,
    145                         const google_breakpad::ClientInfo *client_info,
    146                         const std::wstring *dump_path) {
    147   gDumpCallbackCalled = true;
    148 }
    149 
    150 void ExceptionHandlerDeathTest::DoCrashAccessViolation(
    151     const OutOfProcGuarantee out_of_proc_guarantee) {
    152   scoped_ptr<google_breakpad::ExceptionHandler> exc;
    153 
    154   if (out_of_proc_guarantee == OUT_OF_PROC_GUARANTEED) {
    155     google_breakpad::CrashGenerationClient *client =
    156         new google_breakpad::CrashGenerationClient(kPipeName,
    157                                                    MiniDumpNormal,
    158                                                    NULL);  // custom_info
    159     ASSERT_TRUE(client->Register());
    160     exc.reset(new google_breakpad::ExceptionHandler(
    161         temp_path_,
    162         NULL,   // filter
    163         NULL,   // callback
    164         NULL,   // callback_context
    165         google_breakpad::ExceptionHandler::HANDLER_ALL,
    166         client));
    167   } else {
    168     ASSERT_TRUE(out_of_proc_guarantee == OUT_OF_PROC_BEST_EFFORT);
    169     exc.reset(new google_breakpad::ExceptionHandler(
    170         temp_path_,
    171         NULL,   // filter
    172         NULL,   // callback
    173         NULL,   // callback_context
    174         google_breakpad::ExceptionHandler::HANDLER_ALL,
    175         MiniDumpNormal,
    176         kPipeName,
    177         NULL));  // custom_info
    178   }
    179 
    180   // Disable GTest SEH handler
    181   testing::DisableExceptionHandlerInScope disable_exception_handler;
    182 
    183   // Although this is executing in the child process of the death test,
    184   // if it's not true we'll still get an error rather than the crash
    185   // being expected.
    186   ASSERT_TRUE(exc->IsOutOfProcess());
    187   int *i = NULL;
    188   printf("%d\n", (*i)++);
    189 }
    190 
    191 TEST_F(ExceptionHandlerDeathTest, OutOfProcTest) {
    192   // We can take advantage of a detail of google test here to save some
    193   // complexity in testing: when you do a death test, it actually forks.
    194   // So we can make the main test harness the crash generation server,
    195   // and call ASSERT_DEATH on a NULL dereference, it to expecting test
    196   // the out of process scenario, since it's happening in a different
    197   // process!  This is different from the above because, above, we pass
    198   // a NULL pipe name, and we also don't start a crash generation server.
    199 
    200   ASSERT_TRUE(DoesPathExist(temp_path_));
    201   std::wstring dump_path(temp_path_);
    202   google_breakpad::CrashGenerationServer server(
    203       kPipeName, NULL, NULL, NULL, &clientDumpCallback, NULL, NULL, NULL, NULL,
    204       NULL, true, &dump_path);
    205 
    206   // This HAS to be EXPECT_, because when this test case is executed in the
    207   // child process, the server registration will fail due to the named pipe
    208   // being the same.
    209   EXPECT_TRUE(server.Start());
    210   gDumpCallbackCalled = false;
    211   ASSERT_DEATH(this->DoCrashAccessViolation(OUT_OF_PROC_BEST_EFFORT), "");
    212   EXPECT_TRUE(gDumpCallbackCalled);
    213 }
    214 
    215 TEST_F(ExceptionHandlerDeathTest, OutOfProcGuaranteedTest) {
    216   // This is similar to the previous test (OutOfProcTest).  The only difference
    217   // is that in this test, the crash generation client is created and registered
    218   // with the crash generation server outside of the ExceptionHandler
    219   // constructor which allows breakpad users to opt out of the default
    220   // in-process dump generation when the registration with the crash generation
    221   // server fails.
    222 
    223   ASSERT_TRUE(DoesPathExist(temp_path_));
    224   std::wstring dump_path(temp_path_);
    225   google_breakpad::CrashGenerationServer server(
    226       kPipeName, NULL, NULL, NULL, &clientDumpCallback, NULL, NULL, NULL, NULL,
    227       NULL, true, &dump_path);
    228 
    229   // This HAS to be EXPECT_, because when this test case is executed in the
    230   // child process, the server registration will fail due to the named pipe
    231   // being the same.
    232   EXPECT_TRUE(server.Start());
    233   gDumpCallbackCalled = false;
    234   ASSERT_DEATH(this->DoCrashAccessViolation(OUT_OF_PROC_GUARANTEED), "");
    235   EXPECT_TRUE(gDumpCallbackCalled);
    236 }
    237 
    238 TEST_F(ExceptionHandlerDeathTest, InvalidParameterTest) {
    239   using google_breakpad::ExceptionHandler;
    240 
    241   ASSERT_TRUE(DoesPathExist(temp_path_));
    242   ExceptionHandler handler(temp_path_, NULL, NULL, NULL,
    243                            ExceptionHandler::HANDLER_INVALID_PARAMETER);
    244 
    245   // Disable the message box for assertions
    246   _CrtSetReportMode(_CRT_ASSERT, 0);
    247 
    248   // Call with a bad argument. The invalid parameter will be swallowed
    249   // and a dump will be generated, the process will exit(0).
    250   ASSERT_EXIT(printf(NULL), ::testing::ExitedWithCode(0), "");
    251 }
    252 
    253 
    254 struct PureVirtualCallBase {
    255   PureVirtualCallBase() {
    256     // We have to reinterpret so the linker doesn't get confused because the
    257     // method isn't defined.
    258     reinterpret_cast<PureVirtualCallBase*>(this)->PureFunction();
    259   }
    260   virtual ~PureVirtualCallBase() {}
    261   virtual void PureFunction() const = 0;
    262 };
    263 struct PureVirtualCall : public PureVirtualCallBase {
    264   PureVirtualCall() { PureFunction(); }
    265   virtual void PureFunction() const {}
    266 };
    267 
    268 void ExceptionHandlerDeathTest::DoCrashPureVirtualCall() {
    269   PureVirtualCall instance;
    270 }
    271 
    272 TEST_F(ExceptionHandlerDeathTest, PureVirtualCallTest) {
    273   using google_breakpad::ExceptionHandler;
    274 
    275   ASSERT_TRUE(DoesPathExist(temp_path_));
    276   ExceptionHandler handler(temp_path_, NULL, NULL, NULL,
    277                            ExceptionHandler::HANDLER_PURECALL);
    278 
    279   // Disable the message box for assertions
    280   _CrtSetReportMode(_CRT_ASSERT, 0);
    281 
    282   // Calls a pure virtual function.
    283   EXPECT_EXIT(DoCrashPureVirtualCall(), ::testing::ExitedWithCode(0), "");
    284 }
    285 
    286 wstring find_minidump_in_directory(const wstring &directory) {
    287   wstring search_path = directory + L"\\*";
    288   WIN32_FIND_DATA find_data;
    289   HANDLE find_handle = FindFirstFileW(search_path.c_str(), &find_data);
    290   if (find_handle == INVALID_HANDLE_VALUE)
    291     return wstring();
    292 
    293   wstring filename;
    294   do {
    295     const wchar_t extension[] = L".dmp";
    296     const int extension_length = sizeof(extension) / sizeof(extension[0]) - 1;
    297     const int filename_length = wcslen(find_data.cFileName);
    298     if (filename_length > extension_length &&
    299     wcsncmp(extension,
    300             find_data.cFileName + filename_length - extension_length,
    301             extension_length) == 0) {
    302       filename = directory + L"\\" + find_data.cFileName;
    303       break;
    304     }
    305   } while (FindNextFile(find_handle, &find_data));
    306   FindClose(find_handle);
    307   return filename;
    308 }
    309 
    310 #ifndef ADDRESS_SANITIZER
    311 
    312 TEST_F(ExceptionHandlerDeathTest, InstructionPointerMemory) {
    313   ASSERT_TRUE(DoesPathExist(temp_path_));
    314   scoped_ptr<google_breakpad::ExceptionHandler> exc(
    315       new google_breakpad::ExceptionHandler(
    316           temp_path_,
    317           NULL,
    318           NULL,
    319           NULL,
    320           google_breakpad::ExceptionHandler::HANDLER_ALL));
    321 
    322   // Disable GTest SEH handler
    323   testing::DisableExceptionHandlerInScope disable_exception_handler;
    324 
    325   // Get some executable memory.
    326   const uint32_t kMemorySize = 256;  // bytes
    327   const int kOffset = kMemorySize / 2;
    328   // This crashes with SIGILL on x86/x86-64/arm.
    329   const unsigned char instructions[] = { 0xff, 0xff, 0xff, 0xff };
    330   char* memory = reinterpret_cast<char*>(VirtualAlloc(NULL,
    331                                                       kMemorySize,
    332                                                       MEM_COMMIT | MEM_RESERVE,
    333                                                       PAGE_EXECUTE_READWRITE));
    334   ASSERT_TRUE(memory);
    335 
    336   // Write some instructions that will crash. Put them
    337   // in the middle of the block of memory, because the
    338   // minidump should contain 128 bytes on either side of the
    339   // instruction pointer.
    340   memcpy(memory + kOffset, instructions, sizeof(instructions));
    341 
    342   // Now execute the instructions, which should crash.
    343   typedef void (*void_function)(void);
    344   void_function memory_function =
    345       reinterpret_cast<void_function>(memory + kOffset);
    346   ASSERT_DEATH(memory_function(), "");
    347 
    348   // free the memory.
    349   VirtualFree(memory, 0, MEM_RELEASE);
    350 
    351   // Verify that the resulting minidump contains the memory around the IP
    352   wstring minidump_filename_wide = find_minidump_in_directory(temp_path_);
    353   ASSERT_FALSE(minidump_filename_wide.empty());
    354   string minidump_filename;
    355   ASSERT_TRUE(WindowsStringUtils::safe_wcstombs(minidump_filename_wide,
    356                                                 &minidump_filename));
    357 
    358   // Read the minidump. Locate the exception record and the
    359   // memory list, and then ensure that there is a memory region
    360   // in the memory list that covers the instruction pointer from
    361   // the exception record.
    362   {
    363     Minidump minidump(minidump_filename);
    364     ASSERT_TRUE(minidump.Read());
    365 
    366     MinidumpException* exception = minidump.GetException();
    367     MinidumpMemoryList* memory_list = minidump.GetMemoryList();
    368     ASSERT_TRUE(exception);
    369     ASSERT_TRUE(memory_list);
    370     ASSERT_LT((unsigned)0, memory_list->region_count());
    371 
    372     MinidumpContext* context = exception->GetContext();
    373     ASSERT_TRUE(context);
    374 
    375     uint64_t instruction_pointer;
    376     ASSERT_TRUE(context->GetInstructionPointer(&instruction_pointer));
    377 
    378     MinidumpMemoryRegion* region =
    379         memory_list->GetMemoryRegionForAddress(instruction_pointer);
    380     ASSERT_TRUE(region);
    381 
    382     EXPECT_EQ(kMemorySize, region->GetSize());
    383     const uint8_t* bytes = region->GetMemory();
    384     ASSERT_TRUE(bytes);
    385 
    386     uint8_t prefix_bytes[kOffset];
    387     uint8_t suffix_bytes[kMemorySize - kOffset - sizeof(instructions)];
    388     memset(prefix_bytes, 0, sizeof(prefix_bytes));
    389     memset(suffix_bytes, 0, sizeof(suffix_bytes));
    390     EXPECT_EQ(0, memcmp(bytes, prefix_bytes, sizeof(prefix_bytes)));
    391     EXPECT_EQ(0, memcmp(bytes + kOffset, instructions, sizeof(instructions)));
    392     EXPECT_EQ(0, memcmp(bytes + kOffset + sizeof(instructions),
    393                         suffix_bytes, sizeof(suffix_bytes)));
    394   }
    395 
    396   DeleteFileW(minidump_filename_wide.c_str());
    397 }
    398 
    399 TEST_F(ExceptionHandlerDeathTest, InstructionPointerMemoryMinBound) {
    400   ASSERT_TRUE(DoesPathExist(temp_path_));
    401   scoped_ptr<google_breakpad::ExceptionHandler> exc(
    402       new google_breakpad::ExceptionHandler(
    403           temp_path_,
    404           NULL,
    405           NULL,
    406           NULL,
    407           google_breakpad::ExceptionHandler::HANDLER_ALL));
    408 
    409   // Disable GTest SEH handler
    410   testing::DisableExceptionHandlerInScope disable_exception_handler;
    411 
    412   SYSTEM_INFO sSysInfo;         // Useful information about the system
    413   GetSystemInfo(&sSysInfo);     // Initialize the structure.
    414 
    415   const uint32_t kMemorySize = 256;  // bytes
    416   const DWORD kPageSize = sSysInfo.dwPageSize;
    417   const int kOffset = 0;
    418   // This crashes with SIGILL on x86/x86-64/arm.
    419   const unsigned char instructions[] = { 0xff, 0xff, 0xff, 0xff };
    420   // Get some executable memory. Specifically, reserve two pages,
    421   // but only commit the second.
    422   char* all_memory = reinterpret_cast<char*>(VirtualAlloc(NULL,
    423                                                           kPageSize * 2,
    424                                                           MEM_RESERVE,
    425                                                           PAGE_NOACCESS));
    426   ASSERT_TRUE(all_memory);
    427   char* memory = all_memory + kPageSize;
    428   ASSERT_TRUE(VirtualAlloc(memory, kPageSize,
    429                            MEM_COMMIT, PAGE_EXECUTE_READWRITE));
    430 
    431   // Write some instructions that will crash. Put them
    432   // in the middle of the block of memory, because the
    433   // minidump should contain 128 bytes on either side of the
    434   // instruction pointer.
    435   memcpy(memory + kOffset, instructions, sizeof(instructions));
    436 
    437   // Now execute the instructions, which should crash.
    438   typedef void (*void_function)(void);
    439   void_function memory_function =
    440       reinterpret_cast<void_function>(memory + kOffset);
    441   ASSERT_DEATH(memory_function(), "");
    442 
    443   // free the memory.
    444   VirtualFree(memory, 0, MEM_RELEASE);
    445 
    446   // Verify that the resulting minidump contains the memory around the IP
    447   wstring minidump_filename_wide = find_minidump_in_directory(temp_path_);
    448   ASSERT_FALSE(minidump_filename_wide.empty());
    449   string minidump_filename;
    450   ASSERT_TRUE(WindowsStringUtils::safe_wcstombs(minidump_filename_wide,
    451                                                 &minidump_filename));
    452 
    453   // Read the minidump. Locate the exception record and the
    454   // memory list, and then ensure that there is a memory region
    455   // in the memory list that covers the instruction pointer from
    456   // the exception record.
    457   {
    458     Minidump minidump(minidump_filename);
    459     ASSERT_TRUE(minidump.Read());
    460 
    461     MinidumpException* exception = minidump.GetException();
    462     MinidumpMemoryList* memory_list = minidump.GetMemoryList();
    463     ASSERT_TRUE(exception);
    464     ASSERT_TRUE(memory_list);
    465     ASSERT_LT((unsigned)0, memory_list->region_count());
    466 
    467     MinidumpContext* context = exception->GetContext();
    468     ASSERT_TRUE(context);
    469 
    470     uint64_t instruction_pointer;
    471     ASSERT_TRUE(context->GetInstructionPointer(&instruction_pointer));
    472 
    473     MinidumpMemoryRegion* region =
    474         memory_list->GetMemoryRegionForAddress(instruction_pointer);
    475     ASSERT_TRUE(region);
    476 
    477     EXPECT_EQ(kMemorySize / 2, region->GetSize());
    478     const uint8_t* bytes = region->GetMemory();
    479     ASSERT_TRUE(bytes);
    480 
    481     uint8_t suffix_bytes[kMemorySize / 2 - sizeof(instructions)];
    482     memset(suffix_bytes, 0, sizeof(suffix_bytes));
    483     EXPECT_TRUE(memcmp(bytes + kOffset,
    484                        instructions, sizeof(instructions)) == 0);
    485     EXPECT_TRUE(memcmp(bytes + kOffset + sizeof(instructions),
    486                        suffix_bytes, sizeof(suffix_bytes)) == 0);
    487   }
    488 
    489   DeleteFileW(minidump_filename_wide.c_str());
    490 }
    491 
    492 TEST_F(ExceptionHandlerDeathTest, InstructionPointerMemoryMaxBound) {
    493   ASSERT_TRUE(DoesPathExist(temp_path_));
    494   scoped_ptr<google_breakpad::ExceptionHandler> exc(
    495       new google_breakpad::ExceptionHandler(
    496           temp_path_,
    497           NULL,
    498           NULL,
    499           NULL,
    500           google_breakpad::ExceptionHandler::HANDLER_ALL));
    501 
    502   // Disable GTest SEH handler
    503   testing::DisableExceptionHandlerInScope disable_exception_handler;
    504 
    505   SYSTEM_INFO sSysInfo;         // Useful information about the system
    506   GetSystemInfo(&sSysInfo);     // Initialize the structure.
    507 
    508   const DWORD kPageSize = sSysInfo.dwPageSize;
    509   // This crashes with SIGILL on x86/x86-64/arm.
    510   const unsigned char instructions[] = { 0xff, 0xff, 0xff, 0xff };
    511   const int kOffset = kPageSize - sizeof(instructions);
    512   // Get some executable memory. Specifically, reserve two pages,
    513   // but only commit the first.
    514   char* memory = reinterpret_cast<char*>(VirtualAlloc(NULL,
    515                                                       kPageSize * 2,
    516                                                       MEM_RESERVE,
    517                                                       PAGE_NOACCESS));
    518   ASSERT_TRUE(memory);
    519   ASSERT_TRUE(VirtualAlloc(memory, kPageSize,
    520                            MEM_COMMIT, PAGE_EXECUTE_READWRITE));
    521 
    522   // Write some instructions that will crash.
    523   memcpy(memory + kOffset, instructions, sizeof(instructions));
    524 
    525   // Now execute the instructions, which should crash.
    526   typedef void (*void_function)(void);
    527   void_function memory_function =
    528       reinterpret_cast<void_function>(memory + kOffset);
    529   ASSERT_DEATH(memory_function(), "");
    530 
    531   // free the memory.
    532   VirtualFree(memory, 0, MEM_RELEASE);
    533 
    534   // Verify that the resulting minidump contains the memory around the IP
    535   wstring minidump_filename_wide = find_minidump_in_directory(temp_path_);
    536   ASSERT_FALSE(minidump_filename_wide.empty());
    537   string minidump_filename;
    538   ASSERT_TRUE(WindowsStringUtils::safe_wcstombs(minidump_filename_wide,
    539                                                 &minidump_filename));
    540 
    541   // Read the minidump. Locate the exception record and the
    542   // memory list, and then ensure that there is a memory region
    543   // in the memory list that covers the instruction pointer from
    544   // the exception record.
    545   {
    546     Minidump minidump(minidump_filename);
    547     ASSERT_TRUE(minidump.Read());
    548 
    549     MinidumpException* exception = minidump.GetException();
    550     MinidumpMemoryList* memory_list = minidump.GetMemoryList();
    551     ASSERT_TRUE(exception);
    552     ASSERT_TRUE(memory_list);
    553     ASSERT_LT((unsigned)0, memory_list->region_count());
    554 
    555     MinidumpContext* context = exception->GetContext();
    556     ASSERT_TRUE(context);
    557 
    558     uint64_t instruction_pointer;
    559     ASSERT_TRUE(context->GetInstructionPointer(&instruction_pointer));
    560 
    561     MinidumpMemoryRegion* region =
    562         memory_list->GetMemoryRegionForAddress(instruction_pointer);
    563     ASSERT_TRUE(region);
    564 
    565     const size_t kPrefixSize = 128;  // bytes
    566     EXPECT_EQ(kPrefixSize + sizeof(instructions), region->GetSize());
    567     const uint8_t* bytes = region->GetMemory();
    568     ASSERT_TRUE(bytes);
    569 
    570     uint8_t prefix_bytes[kPrefixSize];
    571     memset(prefix_bytes, 0, sizeof(prefix_bytes));
    572     EXPECT_EQ(0, memcmp(bytes, prefix_bytes, sizeof(prefix_bytes)));
    573     EXPECT_EQ(0, memcmp(bytes + kPrefixSize,
    574                         instructions, sizeof(instructions)));
    575   }
    576 
    577   DeleteFileW(minidump_filename_wide.c_str());
    578 }
    579 
    580 #endif  // !ADDRESS_SANITIZER
    581 
    582 }  // namespace
    583