Home | History | Annotate | Download | only in tests
      1 // Copyright (c) 2010, 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 // exception_handler_test.cc: Unit tests for google_breakpad::ExceptionHandler
     31 
     32 #include <pthread.h>
     33 #include <sys/mman.h>
     34 #include <sys/stat.h>
     35 #include <unistd.h>
     36 
     37 #include "breakpad_googletest_includes.h"
     38 #include "client/mac/handler/exception_handler.h"
     39 #include "common/mac/MachIPC.h"
     40 #include "common/tests/auto_tempdir.h"
     41 #include "google_breakpad/processor/minidump.h"
     42 
     43 namespace google_breakpad {
     44 // This acts as the log sink for INFO logging from the processor
     45 // logging code. The logging output confuses XCode and makes it think
     46 // there are unit test failures. testlogging.h handles the overriding.
     47 std::ostringstream info_log;
     48 }
     49 
     50 namespace {
     51 using std::string;
     52 using google_breakpad::AutoTempDir;
     53 using google_breakpad::ExceptionHandler;
     54 using google_breakpad::MachPortSender;
     55 using google_breakpad::MachReceiveMessage;
     56 using google_breakpad::MachSendMessage;
     57 using google_breakpad::Minidump;
     58 using google_breakpad::MinidumpContext;
     59 using google_breakpad::MinidumpException;
     60 using google_breakpad::MinidumpMemoryList;
     61 using google_breakpad::MinidumpMemoryRegion;
     62 using google_breakpad::ReceivePort;
     63 using testing::Test;
     64 
     65 class ExceptionHandlerTest : public Test {
     66  public:
     67   void InProcessCrash(bool aborting);
     68   AutoTempDir tempDir;
     69   string lastDumpName;
     70 };
     71 
     72 static void Crasher() {
     73   int *a = (int*)0x42;
     74 
     75   fprintf(stdout, "Going to crash...\n");
     76   fprintf(stdout, "A = %d", *a);
     77 }
     78 
     79 static void AbortCrasher() {
     80   fprintf(stdout, "Going to crash...\n");
     81   abort();
     82 }
     83 
     84 static void SoonToCrash(void(*crasher)()) {
     85   crasher();
     86 }
     87 
     88 static bool MDCallback(const char *dump_dir, const char *file_name,
     89                        void *context, bool success) {
     90   string path(dump_dir);
     91   path.append("/");
     92   path.append(file_name);
     93   path.append(".dmp");
     94 
     95   int fd = *reinterpret_cast<int*>(context);
     96   (void)write(fd, path.c_str(), path.length() + 1);
     97   close(fd);
     98   exit(0);
     99   // not reached
    100   return true;
    101 }
    102 
    103 void ExceptionHandlerTest::InProcessCrash(bool aborting) {
    104   // Give the child process a pipe to report back on.
    105   int fds[2];
    106   ASSERT_EQ(0, pipe(fds));
    107   // Fork off a child process so it can crash.
    108   pid_t pid = fork();
    109   if (pid == 0) {
    110     // In the child process.
    111     close(fds[0]);
    112     ExceptionHandler eh(tempDir.path(), NULL, MDCallback, &fds[1], true, NULL);
    113     // crash
    114     SoonToCrash(aborting ? &AbortCrasher : &Crasher);
    115     // not reached
    116     exit(1);
    117   }
    118   // In the parent process.
    119   ASSERT_NE(-1, pid);
    120   // Wait for the background process to return the minidump file.
    121   close(fds[1]);
    122   char minidump_file[PATH_MAX];
    123   ssize_t nbytes = read(fds[0], minidump_file, sizeof(minidump_file));
    124   ASSERT_NE(0, nbytes);
    125 
    126   Minidump minidump(minidump_file);
    127   ASSERT_TRUE(minidump.Read());
    128 
    129   MinidumpException* exception = minidump.GetException();
    130   ASSERT_TRUE(exception);
    131 
    132   const MDRawExceptionStream* raw_exception = exception->exception();
    133   ASSERT_TRUE(raw_exception);
    134 
    135   if (aborting) {
    136     EXPECT_EQ(MD_EXCEPTION_MAC_SOFTWARE,
    137               raw_exception->exception_record.exception_code);
    138     EXPECT_EQ(MD_EXCEPTION_CODE_MAC_ABORT,
    139               raw_exception->exception_record.exception_flags);
    140   } else {
    141     EXPECT_EQ(MD_EXCEPTION_MAC_BAD_ACCESS,
    142               raw_exception->exception_record.exception_code);
    143 #if defined(__x86_64__)
    144     EXPECT_EQ(MD_EXCEPTION_CODE_MAC_INVALID_ADDRESS,
    145               raw_exception->exception_record.exception_flags);
    146 #elif defined(__i386__)
    147     EXPECT_EQ(MD_EXCEPTION_CODE_MAC_PROTECTION_FAILURE,
    148               raw_exception->exception_record.exception_flags);
    149 #endif
    150   }
    151 
    152   const MinidumpContext* context = exception->GetContext();
    153   ASSERT_TRUE(context);
    154 
    155   uint64_t instruction_pointer;
    156   ASSERT_TRUE(context->GetInstructionPointer(&instruction_pointer));
    157 
    158   // Ideally would like to sanity check that abort() is on the stack
    159   // but that's hard.
    160   MinidumpMemoryList* memory_list = minidump.GetMemoryList();
    161   ASSERT_TRUE(memory_list);
    162   MinidumpMemoryRegion* region =
    163       memory_list->GetMemoryRegionForAddress(instruction_pointer);
    164   EXPECT_TRUE(region);
    165 
    166   // Child process should have exited with a zero status.
    167   int ret;
    168   ASSERT_EQ(pid, waitpid(pid, &ret, 0));
    169   EXPECT_NE(0, WIFEXITED(ret));
    170   EXPECT_EQ(0, WEXITSTATUS(ret));
    171 }
    172 
    173 TEST_F(ExceptionHandlerTest, InProcess) {
    174   InProcessCrash(false);
    175 }
    176 
    177 TEST_F(ExceptionHandlerTest, InProcessAbort) {
    178   InProcessCrash(true);
    179 }
    180 
    181 static bool DumpNameMDCallback(const char *dump_dir, const char *file_name,
    182                                void *context, bool success) {
    183   ExceptionHandlerTest *self = reinterpret_cast<ExceptionHandlerTest*>(context);
    184   if (dump_dir && file_name) {
    185     self->lastDumpName = dump_dir;
    186     self->lastDumpName += "/";
    187     self->lastDumpName += file_name;
    188     self->lastDumpName += ".dmp";
    189   }
    190   return true;
    191 }
    192 
    193 TEST_F(ExceptionHandlerTest, WriteMinidump) {
    194   ExceptionHandler eh(tempDir.path(), NULL, DumpNameMDCallback, this, true,
    195                       NULL);
    196   ASSERT_TRUE(eh.WriteMinidump());
    197 
    198   // Ensure that minidump file exists and is > 0 bytes.
    199   ASSERT_FALSE(lastDumpName.empty());
    200   struct stat st;
    201   ASSERT_EQ(0, stat(lastDumpName.c_str(), &st));
    202   ASSERT_LT(0, st.st_size);
    203 
    204   // The minidump should not contain an exception stream.
    205   Minidump minidump(lastDumpName);
    206   ASSERT_TRUE(minidump.Read());
    207 
    208   MinidumpException* exception = minidump.GetException();
    209   EXPECT_FALSE(exception);
    210 }
    211 
    212 TEST_F(ExceptionHandlerTest, WriteMinidumpWithException) {
    213   ExceptionHandler eh(tempDir.path(), NULL, DumpNameMDCallback, this, true,
    214                       NULL);
    215   ASSERT_TRUE(eh.WriteMinidump(true));
    216 
    217   // Ensure that minidump file exists and is > 0 bytes.
    218   ASSERT_FALSE(lastDumpName.empty());
    219   struct stat st;
    220   ASSERT_EQ(0, stat(lastDumpName.c_str(), &st));
    221   ASSERT_LT(0, st.st_size);
    222 
    223   // The minidump should contain an exception stream.
    224   Minidump minidump(lastDumpName);
    225   ASSERT_TRUE(minidump.Read());
    226 
    227   MinidumpException* exception = minidump.GetException();
    228   ASSERT_TRUE(exception);
    229   const MDRawExceptionStream* raw_exception = exception->exception();
    230   ASSERT_TRUE(raw_exception);
    231 
    232   EXPECT_EQ(MD_EXCEPTION_MAC_BREAKPOINT,
    233             raw_exception->exception_record.exception_code);
    234 }
    235 
    236 TEST_F(ExceptionHandlerTest, DumpChildProcess) {
    237   const int kTimeoutMs = 2000;
    238   // Create a mach port to receive the child task on.
    239   char machPortName[128];
    240   sprintf(machPortName, "ExceptionHandlerTest.%d", getpid());
    241   ReceivePort parent_recv_port(machPortName);
    242 
    243   // Give the child process a pipe to block on.
    244   int fds[2];
    245   ASSERT_EQ(0, pipe(fds));
    246 
    247   // Fork off a child process to dump.
    248   pid_t pid = fork();
    249   if (pid == 0) {
    250     // In the child process
    251     close(fds[1]);
    252 
    253     // Send parent process the task and thread ports.
    254     MachSendMessage child_message(0);
    255     child_message.AddDescriptor(mach_task_self());
    256     child_message.AddDescriptor(mach_thread_self());
    257 
    258     MachPortSender child_sender(machPortName);
    259     if (child_sender.SendMessage(child_message, kTimeoutMs) != KERN_SUCCESS)
    260       exit(1);
    261 
    262     // Wait for the parent process.
    263     uint8_t data;
    264     read(fds[0], &data, 1);
    265     exit(0);
    266   }
    267   // In the parent process.
    268   ASSERT_NE(-1, pid);
    269   close(fds[0]);
    270 
    271   // Read the child's task and thread ports.
    272   MachReceiveMessage child_message;
    273   ASSERT_EQ(KERN_SUCCESS,
    274 	    parent_recv_port.WaitForMessage(&child_message, kTimeoutMs));
    275   mach_port_t child_task = child_message.GetTranslatedPort(0);
    276   mach_port_t child_thread = child_message.GetTranslatedPort(1);
    277   ASSERT_NE((mach_port_t)MACH_PORT_NULL, child_task);
    278   ASSERT_NE((mach_port_t)MACH_PORT_NULL, child_thread);
    279 
    280   // Write a minidump of the child process.
    281   bool result = ExceptionHandler::WriteMinidumpForChild(child_task,
    282                                                         child_thread,
    283                                                         tempDir.path(),
    284                                                         DumpNameMDCallback,
    285                                                         this);
    286   ASSERT_EQ(true, result);
    287 
    288   // Ensure that minidump file exists and is > 0 bytes.
    289   ASSERT_FALSE(lastDumpName.empty());
    290   struct stat st;
    291   ASSERT_EQ(0, stat(lastDumpName.c_str(), &st));
    292   ASSERT_LT(0, st.st_size);
    293 
    294   // Unblock child process
    295   uint8_t data = 1;
    296   (void)write(fds[1], &data, 1);
    297 
    298   // Child process should have exited with a zero status.
    299   int ret;
    300   ASSERT_EQ(pid, waitpid(pid, &ret, 0));
    301   EXPECT_NE(0, WIFEXITED(ret));
    302   EXPECT_EQ(0, WEXITSTATUS(ret));
    303 }
    304 
    305 // Test that memory around the instruction pointer is written
    306 // to the dump as a MinidumpMemoryRegion.
    307 TEST_F(ExceptionHandlerTest, InstructionPointerMemory) {
    308   // Give the child process a pipe to report back on.
    309   int fds[2];
    310   ASSERT_EQ(0, pipe(fds));
    311 
    312   // These are defined here so the parent can use them to check the
    313   // data from the minidump afterwards.
    314   const uint32_t kMemorySize = 256;  // bytes
    315   const int kOffset = kMemorySize / 2;
    316   // This crashes with SIGILL on x86/x86-64/arm.
    317   const unsigned char instructions[] = { 0xff, 0xff, 0xff, 0xff };
    318 
    319   pid_t pid = fork();
    320   if (pid == 0) {
    321     close(fds[0]);
    322     ExceptionHandler eh(tempDir.path(), NULL, MDCallback, &fds[1], true, NULL);
    323     // Get some executable memory.
    324     char* memory =
    325       reinterpret_cast<char*>(mmap(NULL,
    326                                    kMemorySize,
    327                                    PROT_READ | PROT_WRITE | PROT_EXEC,
    328                                    MAP_PRIVATE | MAP_ANON,
    329                                    -1,
    330                                    0));
    331     if (!memory)
    332       exit(0);
    333 
    334     // Write some instructions that will crash. Put them in the middle
    335     // of the block of memory, because the minidump should contain 128
    336     // bytes on either side of the instruction pointer.
    337     memcpy(memory + kOffset, instructions, sizeof(instructions));
    338 
    339     // Now execute the instructions, which should crash.
    340     typedef void (*void_function)(void);
    341     void_function memory_function =
    342       reinterpret_cast<void_function>(memory + kOffset);
    343     memory_function();
    344     // not reached
    345     exit(1);
    346   }
    347   // In the parent process.
    348   ASSERT_NE(-1, pid);
    349   close(fds[1]);
    350 
    351   // Wait for the background process to return the minidump file.
    352   close(fds[1]);
    353   char minidump_file[PATH_MAX];
    354   ssize_t nbytes = read(fds[0], minidump_file, sizeof(minidump_file));
    355   ASSERT_NE(0, nbytes);
    356   // Ensure that minidump file exists and is > 0 bytes.
    357   struct stat st;
    358   ASSERT_EQ(0, stat(minidump_file, &st));
    359   ASSERT_LT(0, st.st_size);
    360 
    361   // Child process should have exited with a zero status.
    362   int ret;
    363   ASSERT_EQ(pid, waitpid(pid, &ret, 0));
    364   EXPECT_NE(0, WIFEXITED(ret));
    365   EXPECT_EQ(0, WEXITSTATUS(ret));
    366 
    367   // Read the minidump. Locate the exception record and the
    368   // memory list, and then ensure that there is a memory region
    369   // in the memory list that covers the instruction pointer from
    370   // the exception record.
    371   Minidump minidump(minidump_file);
    372   ASSERT_TRUE(minidump.Read());
    373 
    374   MinidumpException* exception = minidump.GetException();
    375   MinidumpMemoryList* memory_list = minidump.GetMemoryList();
    376   ASSERT_TRUE(exception);
    377   ASSERT_TRUE(memory_list);
    378   ASSERT_NE((unsigned int)0, memory_list->region_count());
    379 
    380   MinidumpContext* context = exception->GetContext();
    381   ASSERT_TRUE(context);
    382 
    383   uint64_t instruction_pointer;
    384   ASSERT_TRUE(context->GetInstructionPointer(&instruction_pointer));
    385 
    386   MinidumpMemoryRegion* region =
    387     memory_list->GetMemoryRegionForAddress(instruction_pointer);
    388   EXPECT_TRUE(region);
    389 
    390   EXPECT_EQ(kMemorySize, region->GetSize());
    391   const uint8_t* bytes = region->GetMemory();
    392   ASSERT_TRUE(bytes);
    393 
    394   uint8_t prefix_bytes[kOffset];
    395   uint8_t suffix_bytes[kMemorySize - kOffset - sizeof(instructions)];
    396   memset(prefix_bytes, 0, sizeof(prefix_bytes));
    397   memset(suffix_bytes, 0, sizeof(suffix_bytes));
    398   EXPECT_TRUE(memcmp(bytes, prefix_bytes, sizeof(prefix_bytes)) == 0);
    399   EXPECT_TRUE(memcmp(bytes + kOffset, instructions, sizeof(instructions)) == 0);
    400   EXPECT_TRUE(memcmp(bytes + kOffset + sizeof(instructions),
    401                      suffix_bytes, sizeof(suffix_bytes)) == 0);
    402 }
    403 
    404 // Test that the memory region around the instruction pointer is
    405 // bounded correctly on the low end.
    406 TEST_F(ExceptionHandlerTest, InstructionPointerMemoryMinBound) {
    407   // Give the child process a pipe to report back on.
    408   int fds[2];
    409   ASSERT_EQ(0, pipe(fds));
    410 
    411   // These are defined here so the parent can use them to check the
    412   // data from the minidump afterwards.
    413   const uint32_t kMemorySize = 256;  // bytes
    414   const int kOffset = 0;
    415   // This crashes with SIGILL on x86/x86-64/arm.
    416   const unsigned char instructions[] = { 0xff, 0xff, 0xff, 0xff };
    417 
    418   pid_t pid = fork();
    419   if (pid == 0) {
    420     close(fds[0]);
    421     ExceptionHandler eh(tempDir.path(), NULL, MDCallback, &fds[1], true, NULL);
    422     // Get some executable memory.
    423     char* memory =
    424       reinterpret_cast<char*>(mmap(NULL,
    425                                    kMemorySize,
    426                                    PROT_READ | PROT_WRITE | PROT_EXEC,
    427                                    MAP_PRIVATE | MAP_ANON,
    428                                    -1,
    429                                    0));
    430     if (!memory)
    431       exit(0);
    432 
    433     // Write some instructions that will crash. Put them at the start
    434     // of the block of memory, to ensure that the memory bounding
    435     // works properly.
    436     memcpy(memory + kOffset, instructions, sizeof(instructions));
    437 
    438     // Now execute the instructions, which should crash.
    439     typedef void (*void_function)(void);
    440     void_function memory_function =
    441       reinterpret_cast<void_function>(memory + kOffset);
    442     memory_function();
    443     // not reached
    444     exit(1);
    445   }
    446   // In the parent process.
    447   ASSERT_NE(-1, pid);
    448   close(fds[1]);
    449 
    450   // Wait for the background process to return the minidump file.
    451   close(fds[1]);
    452   char minidump_file[PATH_MAX];
    453   ssize_t nbytes = read(fds[0], minidump_file, sizeof(minidump_file));
    454   ASSERT_NE(0, nbytes);
    455   // Ensure that minidump file exists and is > 0 bytes.
    456   struct stat st;
    457   ASSERT_EQ(0, stat(minidump_file, &st));
    458   ASSERT_LT(0, st.st_size);
    459 
    460   // Child process should have exited with a zero status.
    461   int ret;
    462   ASSERT_EQ(pid, waitpid(pid, &ret, 0));
    463   EXPECT_NE(0, WIFEXITED(ret));
    464   EXPECT_EQ(0, WEXITSTATUS(ret));
    465 
    466   // Read the minidump. Locate the exception record and the
    467   // memory list, and then ensure that there is a memory region
    468   // in the memory list that covers the instruction pointer from
    469   // the exception record.
    470   Minidump minidump(minidump_file);
    471   ASSERT_TRUE(minidump.Read());
    472 
    473   MinidumpException* exception = minidump.GetException();
    474   MinidumpMemoryList* memory_list = minidump.GetMemoryList();
    475   ASSERT_TRUE(exception);
    476   ASSERT_TRUE(memory_list);
    477   ASSERT_NE((unsigned int)0, memory_list->region_count());
    478 
    479   MinidumpContext* context = exception->GetContext();
    480   ASSERT_TRUE(context);
    481 
    482   uint64_t instruction_pointer;
    483   ASSERT_TRUE(context->GetInstructionPointer(&instruction_pointer));
    484 
    485   MinidumpMemoryRegion* region =
    486     memory_list->GetMemoryRegionForAddress(instruction_pointer);
    487   EXPECT_TRUE(region);
    488 
    489   EXPECT_EQ(kMemorySize / 2, region->GetSize());
    490   const uint8_t* bytes = region->GetMemory();
    491   ASSERT_TRUE(bytes);
    492 
    493   uint8_t suffix_bytes[kMemorySize / 2 - sizeof(instructions)];
    494   memset(suffix_bytes, 0, sizeof(suffix_bytes));
    495   EXPECT_TRUE(memcmp(bytes + kOffset, instructions, sizeof(instructions)) == 0);
    496   EXPECT_TRUE(memcmp(bytes + kOffset + sizeof(instructions),
    497                      suffix_bytes, sizeof(suffix_bytes)) == 0);
    498 }
    499 
    500 // Test that the memory region around the instruction pointer is
    501 // bounded correctly on the high end.
    502 TEST_F(ExceptionHandlerTest, InstructionPointerMemoryMaxBound) {
    503   // Give the child process a pipe to report back on.
    504   int fds[2];
    505   ASSERT_EQ(0, pipe(fds));
    506 
    507   // These are defined here so the parent can use them to check the
    508   // data from the minidump afterwards.
    509   // Use 4k here because the OS will hand out a single page even
    510   // if a smaller size is requested, and this test wants to
    511   // test the upper bound of the memory range.
    512   const uint32_t kMemorySize = 4096;  // bytes
    513   // This crashes with SIGILL on x86/x86-64/arm.
    514   const unsigned char instructions[] = { 0xff, 0xff, 0xff, 0xff };
    515   const int kOffset = kMemorySize - sizeof(instructions);
    516 
    517   pid_t pid = fork();
    518   if (pid == 0) {
    519     close(fds[0]);
    520     ExceptionHandler eh(tempDir.path(), NULL, MDCallback, &fds[1], true, NULL);
    521     // Get some executable memory.
    522     char* memory =
    523       reinterpret_cast<char*>(mmap(NULL,
    524                                    kMemorySize,
    525                                    PROT_READ | PROT_WRITE | PROT_EXEC,
    526                                    MAP_PRIVATE | MAP_ANON,
    527                                    -1,
    528                                    0));
    529     if (!memory)
    530       exit(0);
    531 
    532     // Write some instructions that will crash. Put them at the start
    533     // of the block of memory, to ensure that the memory bounding
    534     // works properly.
    535     memcpy(memory + kOffset, instructions, sizeof(instructions));
    536 
    537     // Now execute the instructions, which should crash.
    538     typedef void (*void_function)(void);
    539     void_function memory_function =
    540       reinterpret_cast<void_function>(memory + kOffset);
    541     memory_function();
    542     // not reached
    543     exit(1);
    544   }
    545   // In the parent process.
    546   ASSERT_NE(-1, pid);
    547   close(fds[1]);
    548 
    549   // Wait for the background process to return the minidump file.
    550   close(fds[1]);
    551   char minidump_file[PATH_MAX];
    552   ssize_t nbytes = read(fds[0], minidump_file, sizeof(minidump_file));
    553   ASSERT_NE(0, nbytes);
    554   // Ensure that minidump file exists and is > 0 bytes.
    555   struct stat st;
    556   ASSERT_EQ(0, stat(minidump_file, &st));
    557   ASSERT_LT(0, st.st_size);
    558 
    559   // Child process should have exited with a zero status.
    560   int ret;
    561   ASSERT_EQ(pid, waitpid(pid, &ret, 0));
    562   EXPECT_NE(0, WIFEXITED(ret));
    563   EXPECT_EQ(0, WEXITSTATUS(ret));
    564 
    565   // Read the minidump. Locate the exception record and the
    566   // memory list, and then ensure that there is a memory region
    567   // in the memory list that covers the instruction pointer from
    568   // the exception record.
    569   Minidump minidump(minidump_file);
    570   ASSERT_TRUE(minidump.Read());
    571 
    572   MinidumpException* exception = minidump.GetException();
    573   MinidumpMemoryList* memory_list = minidump.GetMemoryList();
    574   ASSERT_TRUE(exception);
    575   ASSERT_TRUE(memory_list);
    576   ASSERT_NE((unsigned int)0, memory_list->region_count());
    577 
    578   MinidumpContext* context = exception->GetContext();
    579   ASSERT_TRUE(context);
    580 
    581   uint64_t instruction_pointer;
    582   ASSERT_TRUE(context->GetInstructionPointer(&instruction_pointer));
    583 
    584   MinidumpMemoryRegion* region =
    585     memory_list->GetMemoryRegionForAddress(instruction_pointer);
    586   EXPECT_TRUE(region);
    587 
    588   const size_t kPrefixSize = 128;  // bytes
    589   EXPECT_EQ(kPrefixSize + sizeof(instructions), region->GetSize());
    590   const uint8_t* bytes = region->GetMemory();
    591   ASSERT_TRUE(bytes);
    592 
    593   uint8_t prefix_bytes[kPrefixSize];
    594   memset(prefix_bytes, 0, sizeof(prefix_bytes));
    595   EXPECT_TRUE(memcmp(bytes, prefix_bytes, sizeof(prefix_bytes)) == 0);
    596   EXPECT_TRUE(memcmp(bytes + kPrefixSize,
    597                      instructions, sizeof(instructions)) == 0);
    598 }
    599 
    600 // Ensure that an extra memory block doesn't get added when the
    601 // instruction pointer is not in mapped memory.
    602 TEST_F(ExceptionHandlerTest, InstructionPointerMemoryNullPointer) {
    603   // Give the child process a pipe to report back on.
    604   int fds[2];
    605   ASSERT_EQ(0, pipe(fds));
    606 
    607   pid_t pid = fork();
    608   if (pid == 0) {
    609     close(fds[0]);
    610     ExceptionHandler eh(tempDir.path(), NULL, MDCallback, &fds[1], true, NULL);
    611     // Try calling a NULL pointer.
    612     typedef void (*void_function)(void);
    613     void_function memory_function =
    614       reinterpret_cast<void_function>(NULL);
    615     memory_function();
    616     // not reached
    617     exit(1);
    618   }
    619   // In the parent process.
    620   ASSERT_NE(-1, pid);
    621   close(fds[1]);
    622 
    623   // Wait for the background process to return the minidump file.
    624   close(fds[1]);
    625   char minidump_file[PATH_MAX];
    626   ssize_t nbytes = read(fds[0], minidump_file, sizeof(minidump_file));
    627   ASSERT_NE(0, nbytes);
    628   // Ensure that minidump file exists and is > 0 bytes.
    629   struct stat st;
    630   ASSERT_EQ(0, stat(minidump_file, &st));
    631   ASSERT_LT(0, st.st_size);
    632 
    633   // Child process should have exited with a zero status.
    634   int ret;
    635   ASSERT_EQ(pid, waitpid(pid, &ret, 0));
    636   EXPECT_NE(0, WIFEXITED(ret));
    637   EXPECT_EQ(0, WEXITSTATUS(ret));
    638 
    639   // Read the minidump. Locate the exception record and the
    640   // memory list, and then ensure that there is only one memory region
    641   // in the memory list (the thread memory from the single thread).
    642   Minidump minidump(minidump_file);
    643   ASSERT_TRUE(minidump.Read());
    644 
    645   MinidumpException* exception = minidump.GetException();
    646   MinidumpMemoryList* memory_list = minidump.GetMemoryList();
    647   ASSERT_TRUE(exception);
    648   ASSERT_TRUE(memory_list);
    649   ASSERT_EQ((unsigned int)1, memory_list->region_count());
    650 }
    651 
    652 static void *Junk(void *) {
    653   sleep(1000000);
    654   return NULL;
    655 }
    656 
    657 // Test that the memory list gets written correctly when multiple
    658 // threads are running.
    659 TEST_F(ExceptionHandlerTest, MemoryListMultipleThreads) {
    660   // Give the child process a pipe to report back on.
    661   int fds[2];
    662   ASSERT_EQ(0, pipe(fds));
    663 
    664   pid_t pid = fork();
    665   if (pid == 0) {
    666     close(fds[0]);
    667     ExceptionHandler eh(tempDir.path(), NULL, MDCallback, &fds[1], true, NULL);
    668 
    669     // Run an extra thread so >2 memory regions will be written.
    670     pthread_t junk_thread;
    671     if (pthread_create(&junk_thread, NULL, Junk, NULL) == 0)
    672       pthread_detach(junk_thread);
    673 
    674     // Just crash.
    675     Crasher();
    676 
    677     // not reached
    678     exit(1);
    679   }
    680   // In the parent process.
    681   ASSERT_NE(-1, pid);
    682   close(fds[1]);
    683 
    684   // Wait for the background process to return the minidump file.
    685   close(fds[1]);
    686   char minidump_file[PATH_MAX];
    687   ssize_t nbytes = read(fds[0], minidump_file, sizeof(minidump_file));
    688   ASSERT_NE(0, nbytes);
    689   // Ensure that minidump file exists and is > 0 bytes.
    690   struct stat st;
    691   ASSERT_EQ(0, stat(minidump_file, &st));
    692   ASSERT_LT(0, st.st_size);
    693 
    694   // Child process should have exited with a zero status.
    695   int ret;
    696   ASSERT_EQ(pid, waitpid(pid, &ret, 0));
    697   EXPECT_NE(0, WIFEXITED(ret));
    698   EXPECT_EQ(0, WEXITSTATUS(ret));
    699 
    700   // Read the minidump, and verify that the memory list can be read.
    701   Minidump minidump(minidump_file);
    702   ASSERT_TRUE(minidump.Read());
    703 
    704   MinidumpMemoryList* memory_list = minidump.GetMemoryList();
    705   ASSERT_TRUE(memory_list);
    706   // Verify that there are three memory regions:
    707   // one per thread, and one for the instruction pointer memory.
    708   ASSERT_EQ((unsigned int)3, memory_list->region_count());
    709 }
    710 
    711 }
    712