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
45namespace {
46
47using std::wstring;
48using namespace google_breakpad;
49
50const wchar_t kPipeName[] = L"\\\\.\\pipe\\BreakpadCrashTest\\TestCaseServer";
51const char kSuccessIndicator[] = "success";
52const char kFailureIndicator[] = "failure";
53
54// Utility function to test for a path's existence.
55BOOL DoesPathExist(const TCHAR *path_name);
56
57enum OutOfProcGuarantee {
58  OUT_OF_PROC_GUARANTEED,
59  OUT_OF_PROC_BEST_EFFORT,
60};
61
62class 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
74void 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
95BOOL 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
103bool 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
120TEST_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
142static bool gDumpCallbackCalled = false;
143
144void clientDumpCallback(void *dump_context,
145                        const google_breakpad::ClientInfo *client_info,
146                        const std::wstring *dump_path) {
147  gDumpCallbackCalled = true;
148}
149
150void 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
191TEST_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
215TEST_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
238TEST_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
254struct 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};
263struct PureVirtualCall : public PureVirtualCallBase {
264  PureVirtualCall() { PureFunction(); }
265  virtual void PureFunction() const {}
266};
267
268void ExceptionHandlerDeathTest::DoCrashPureVirtualCall() {
269  PureVirtualCall instance;
270}
271
272TEST_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
286wstring 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
312TEST_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
399TEST_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
492TEST_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