Upstream version 9.38.198.0
[platform/framework/web/crosswalk.git] / src / breakpad / src / client / linux / handler / exception_handler_unittest.cc
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 #include <stdint.h>
31 #include <unistd.h>
32 #include <signal.h>
33 #include <sys/mman.h>
34 #include <sys/poll.h>
35 #include <sys/socket.h>
36 #include <sys/uio.h>
37 #include <sys/wait.h>
38 #if defined(__mips__)
39 #include <sys/cachectl.h>
40 #endif
41
42 #include <string>
43
44 #include "breakpad_googletest_includes.h"
45 #include "client/linux/handler/exception_handler.h"
46 #include "client/linux/minidump_writer/minidump_writer.h"
47 #include "common/linux/eintr_wrapper.h"
48 #include "common/linux/file_id.h"
49 #include "common/linux/ignore_ret.h"
50 #include "common/linux/linux_libc_support.h"
51 #include "common/tests/auto_tempdir.h"
52 #include "common/using_std_string.h"
53 #include "third_party/lss/linux_syscall_support.h"
54 #include "google_breakpad/processor/minidump.h"
55
56 using namespace google_breakpad;
57
58 namespace {
59
60 // Flush the instruction cache for a given memory range.
61 // Only required on ARM and mips.
62 void FlushInstructionCache(const char* memory, uint32_t memory_size) {
63 #if defined(__arm__)
64   long begin = reinterpret_cast<long>(memory);
65   long end = begin + static_cast<long>(memory_size);
66 # if defined(__ANDROID__)
67   // Provided by Android's <unistd.h>
68   cacheflush(begin, end, 0);
69 # elif defined(__linux__)
70   // GLibc/ARM doesn't provide a wrapper for it, do a direct syscall.
71 #  ifndef __ARM_NR_cacheflush
72 #  define __ARM_NR_cacheflush 0xf0002
73 #  endif
74   syscall(__ARM_NR_cacheflush, begin, end, 0);
75 # else
76 #   error "Your operating system is not supported yet"
77 # endif
78 #elif defined(__mips__)
79 # if defined(__ANDROID__)
80   // Provided by Android's <unistd.h>
81   long begin = reinterpret_cast<long>(memory);
82   long end = begin + static_cast<long>(memory_size);
83   cacheflush(begin, end, 0);
84 # elif defined(__linux__)
85   // See http://www.linux-mips.org/wiki/Cacheflush_Syscall.
86   cacheflush(const_cast<char*>(memory), memory_size, ICACHE);
87 # else
88 #   error "Your operating system is not supported yet"
89 # endif
90 #endif
91 }
92
93 // Length of a formatted GUID string =
94 // sizeof(MDGUID) * 2 + 4 (for dashes) + 1 (null terminator)
95 const int kGUIDStringSize = 37;
96
97 void sigchld_handler(int signo) { }
98
99 int CreateTMPFile(const string& dir, string* path) {
100   string file = dir + "/exception-handler-unittest.XXXXXX";
101   const char* c_file = file.c_str();
102   // Copy that string, mkstemp needs a C string it can modify.
103   char* c_path = strdup(c_file);
104   const int fd = mkstemp(c_path);
105   if (fd >= 0)
106     *path = c_path;
107   free(c_path);
108   return fd;
109 }
110
111 class ExceptionHandlerTest : public ::testing::Test {
112  protected:
113   void SetUp() {
114     // We need to be able to wait for children, so SIGCHLD cannot be SIG_IGN.
115     struct sigaction sa;
116     memset(&sa, 0, sizeof(sa));
117     sa.sa_handler = sigchld_handler;
118     ASSERT_NE(sigaction(SIGCHLD, &sa, &old_action), -1);
119   }
120
121   void TearDown() {
122     sigaction(SIGCHLD, &old_action, NULL);
123   }
124
125   struct sigaction old_action;
126 };
127
128
129 void WaitForProcessToTerminate(pid_t process_id, int expected_status) {
130   int status;
131   ASSERT_NE(HANDLE_EINTR(waitpid(process_id, &status, 0)), -1);
132   ASSERT_TRUE(WIFSIGNALED(status));
133   ASSERT_EQ(expected_status, WTERMSIG(status));
134 }
135
136 // Reads the minidump path sent over the pipe |fd| and sets it in |path|.
137 void ReadMinidumpPathFromPipe(int fd, string* path) {
138   struct pollfd pfd;
139   memset(&pfd, 0, sizeof(pfd));
140   pfd.fd = fd;
141   pfd.events = POLLIN | POLLERR;
142
143   const int r = HANDLE_EINTR(poll(&pfd, 1, 0));
144   ASSERT_EQ(1, r);
145   ASSERT_TRUE(pfd.revents & POLLIN);
146
147   int32_t len;
148   ASSERT_EQ(static_cast<ssize_t>(sizeof(len)), read(fd, &len, sizeof(len)));
149   ASSERT_LT(len, 2048);
150   char* filename = static_cast<char*>(malloc(len + 1));
151   ASSERT_EQ(len, read(fd, filename, len));
152   filename[len] = 0;
153   close(fd);
154   *path = filename;
155   free(filename);
156 }
157
158 }  // namespace
159
160 TEST(ExceptionHandlerTest, SimpleWithPath) {
161   AutoTempDir temp_dir;
162   ExceptionHandler handler(
163       MinidumpDescriptor(temp_dir.path()), NULL, NULL, NULL, true, -1);
164   EXPECT_EQ(temp_dir.path(), handler.minidump_descriptor().directory());
165   string temp_subdir = temp_dir.path() + "/subdir";
166   handler.set_minidump_descriptor(MinidumpDescriptor(temp_subdir));
167   EXPECT_EQ(temp_subdir, handler.minidump_descriptor().directory());
168 }
169
170 TEST(ExceptionHandlerTest, SimpleWithFD) {
171   AutoTempDir temp_dir;
172   string path;
173   const int fd = CreateTMPFile(temp_dir.path(), &path);
174   ExceptionHandler handler(MinidumpDescriptor(fd), NULL, NULL, NULL, true, -1);
175   close(fd);
176 }
177
178 static bool DoneCallback(const MinidumpDescriptor& descriptor,
179                          void* context,
180                          bool succeeded) {
181   if (!succeeded)
182     return false;
183
184   if (!descriptor.IsFD()) {
185     int fd = reinterpret_cast<intptr_t>(context);
186     uint32_t len = 0;
187     len = my_strlen(descriptor.path());
188     IGNORE_RET(HANDLE_EINTR(sys_write(fd, &len, sizeof(len))));
189     IGNORE_RET(HANDLE_EINTR(sys_write(fd, descriptor.path(), len)));
190   }
191   return true;
192 }
193
194 #ifndef ADDRESS_SANITIZER
195
196 // This is a replacement for "*reinterpret_cast<volatile int*>(NULL) = 0;"
197 // It is needed because GCC is allowed to assume that the program will
198 // not execute any undefined behavior (UB) operation. Further, when GCC
199 // observes that UB statement is reached, it can assume that all statements
200 // leading to the UB one are never executed either, and can completely
201 // optimize them out. In the case of ExceptionHandlerTest::ExternalDumper,
202 // GCC-4.9 optimized out the entire set up of ExceptionHandler, causing
203 // test failure.
204 volatile int *p_null;  // external linkage, so GCC can't tell that it
205                        // remains NULL. Volatile just for a good measure.
206 static void DoNullPointerDereference() {
207   *p_null = 1;
208 }
209
210 void ChildCrash(bool use_fd) {
211   AutoTempDir temp_dir;
212   int fds[2] = {0};
213   int minidump_fd = -1;
214   string minidump_path;
215   if (use_fd) {
216     minidump_fd = CreateTMPFile(temp_dir.path(), &minidump_path);
217   } else {
218     ASSERT_NE(pipe(fds), -1);
219   }
220
221   const pid_t child = fork();
222   if (child == 0) {
223     {
224       google_breakpad::scoped_ptr<ExceptionHandler> handler;
225       if (use_fd) {
226         handler.reset(new ExceptionHandler(MinidumpDescriptor(minidump_fd),
227                                            NULL, NULL, NULL, true, -1));
228       } else {
229         close(fds[0]);  // Close the reading end.
230         void* fd_param = reinterpret_cast<void*>(fds[1]);
231         handler.reset(new ExceptionHandler(MinidumpDescriptor(temp_dir.path()),
232                                            NULL, DoneCallback, fd_param,
233                                            true, -1));
234       }
235       // Crash with the exception handler in scope.
236       DoNullPointerDereference();
237     }
238   }
239   if (!use_fd)
240     close(fds[1]);  // Close the writting end.
241
242   ASSERT_NO_FATAL_FAILURE(WaitForProcessToTerminate(child, SIGSEGV));
243
244   if (!use_fd)
245     ASSERT_NO_FATAL_FAILURE(ReadMinidumpPathFromPipe(fds[0], &minidump_path));
246
247   struct stat st;
248   ASSERT_EQ(0, stat(minidump_path.c_str(), &st));
249   ASSERT_GT(st.st_size, 0);
250   unlink(minidump_path.c_str());
251 }
252
253 TEST(ExceptionHandlerTest, ChildCrashWithPath) {
254   ASSERT_NO_FATAL_FAILURE(ChildCrash(false));
255 }
256
257 TEST(ExceptionHandlerTest, ChildCrashWithFD) {
258   ASSERT_NO_FATAL_FAILURE(ChildCrash(true));
259 }
260
261 #endif  // !ADDRESS_SANITIZER
262
263 static bool DoneCallbackReturnFalse(const MinidumpDescriptor& descriptor,
264                                     void* context,
265                                     bool succeeded) {
266   return false;
267 }
268
269 static bool DoneCallbackReturnTrue(const MinidumpDescriptor& descriptor,
270                                    void* context,
271                                    bool succeeded) {
272   return true;
273 }
274
275 static bool DoneCallbackRaiseSIGKILL(const MinidumpDescriptor& descriptor,
276                                      void* context,
277                                      bool succeeded) {
278   raise(SIGKILL);
279   return true;
280 }
281
282 static bool FilterCallbackReturnFalse(void* context) {
283   return false;
284 }
285
286 static bool FilterCallbackReturnTrue(void* context) {
287   return true;
288 }
289
290 // SIGKILL cannot be blocked and a handler cannot be installed for it. In the
291 // following tests, if the child dies with signal SIGKILL, then the signal was
292 // redelivered to this handler. If the child dies with SIGSEGV then it wasn't.
293 static void RaiseSIGKILL(int sig) {
294   raise(SIGKILL);
295 }
296
297 static bool InstallRaiseSIGKILL() {
298   struct sigaction sa;
299   memset(&sa, 0, sizeof(sa));
300   sa.sa_handler = RaiseSIGKILL;
301   return sigaction(SIGSEGV, &sa, NULL) != -1;
302 }
303
304 #ifndef ADDRESS_SANITIZER
305
306 static void CrashWithCallbacks(ExceptionHandler::FilterCallback filter,
307                                ExceptionHandler::MinidumpCallback done,
308                                string path) {
309   ExceptionHandler handler(
310       MinidumpDescriptor(path), filter, done, NULL, true, -1);
311   // Crash with the exception handler in scope.
312   DoNullPointerDereference();
313 }
314
315 TEST(ExceptionHandlerTest, RedeliveryOnFilterCallbackFalse) {
316   AutoTempDir temp_dir;
317
318   const pid_t child = fork();
319   if (child == 0) {
320     ASSERT_TRUE(InstallRaiseSIGKILL());
321     CrashWithCallbacks(FilterCallbackReturnFalse, NULL, temp_dir.path());
322   }
323
324   ASSERT_NO_FATAL_FAILURE(WaitForProcessToTerminate(child, SIGKILL));
325 }
326
327 TEST(ExceptionHandlerTest, RedeliveryOnDoneCallbackFalse) {
328   AutoTempDir temp_dir;
329
330   const pid_t child = fork();
331   if (child == 0) {
332     ASSERT_TRUE(InstallRaiseSIGKILL());
333     CrashWithCallbacks(NULL, DoneCallbackReturnFalse, temp_dir.path());
334   }
335
336   ASSERT_NO_FATAL_FAILURE(WaitForProcessToTerminate(child, SIGKILL));
337 }
338
339 TEST(ExceptionHandlerTest, NoRedeliveryOnDoneCallbackTrue) {
340   AutoTempDir temp_dir;
341
342   const pid_t child = fork();
343   if (child == 0) {
344     ASSERT_TRUE(InstallRaiseSIGKILL());
345     CrashWithCallbacks(NULL, DoneCallbackReturnTrue, temp_dir.path());
346   }
347
348   ASSERT_NO_FATAL_FAILURE(WaitForProcessToTerminate(child, SIGSEGV));
349 }
350
351 TEST(ExceptionHandlerTest, NoRedeliveryOnFilterCallbackTrue) {
352   AutoTempDir temp_dir;
353
354   const pid_t child = fork();
355   if (child == 0) {
356     ASSERT_TRUE(InstallRaiseSIGKILL());
357     CrashWithCallbacks(FilterCallbackReturnTrue, NULL, temp_dir.path());
358   }
359
360   ASSERT_NO_FATAL_FAILURE(WaitForProcessToTerminate(child, SIGSEGV));
361 }
362
363 TEST(ExceptionHandlerTest, RedeliveryToDefaultHandler) {
364   AutoTempDir temp_dir;
365
366   const pid_t child = fork();
367   if (child == 0) {
368     CrashWithCallbacks(FilterCallbackReturnFalse, NULL, temp_dir.path());
369   }
370
371   // As RaiseSIGKILL wasn't installed, the redelivery should just kill the child
372   // with SIGSEGV.
373   ASSERT_NO_FATAL_FAILURE(WaitForProcessToTerminate(child, SIGSEGV));
374 }
375
376 // Check that saving and restoring the signal handler with 'signal'
377 // instead of 'sigaction' doesn't make the Breakpad signal handler
378 // crash. See comments in ExceptionHandler::SignalHandler for full
379 // details.
380 TEST(ExceptionHandlerTest, RedeliveryOnBadSignalHandlerFlag) {
381   AutoTempDir temp_dir;
382   const pid_t child = fork();
383   if (child == 0) {
384     // Install the RaiseSIGKILL handler for SIGSEGV.
385     ASSERT_TRUE(InstallRaiseSIGKILL());
386
387     // Create a new exception handler, this installs a new SIGSEGV
388     // handler, after saving the old one.
389     ExceptionHandler handler(
390         MinidumpDescriptor(temp_dir.path()), NULL,
391         DoneCallbackReturnFalse, NULL, true, -1);
392
393     // Install the default SIGSEGV handler, saving the current one.
394     // Then re-install the current one with 'signal', this loses the
395     // SA_SIGINFO flag associated with the Breakpad handler.
396     sighandler_t old_handler = signal(SIGSEGV, SIG_DFL);
397     ASSERT_NE(reinterpret_cast<void*>(old_handler),
398               reinterpret_cast<void*>(SIG_ERR));
399     ASSERT_NE(reinterpret_cast<void*>(signal(SIGSEGV, old_handler)),
400               reinterpret_cast<void*>(SIG_ERR));
401
402     // Crash with the exception handler in scope.
403     DoNullPointerDereference();
404   }
405   // SIGKILL means Breakpad's signal handler didn't crash.
406   ASSERT_NO_FATAL_FAILURE(WaitForProcessToTerminate(child, SIGKILL));
407 }
408
409 TEST(ExceptionHandlerTest, StackedHandlersDeliveredToTop) {
410   AutoTempDir temp_dir;
411
412   const pid_t child = fork();
413   if (child == 0) {
414     ExceptionHandler bottom(MinidumpDescriptor(temp_dir.path()),
415                             NULL,
416                             NULL,
417                             NULL,
418                             true,
419                             -1);
420     CrashWithCallbacks(NULL, DoneCallbackRaiseSIGKILL, temp_dir.path());
421   }
422   ASSERT_NO_FATAL_FAILURE(WaitForProcessToTerminate(child, SIGKILL));
423 }
424
425 TEST(ExceptionHandlerTest, StackedHandlersNotDeliveredToBottom) {
426   AutoTempDir temp_dir;
427
428   const pid_t child = fork();
429   if (child == 0) {
430     ExceptionHandler bottom(MinidumpDescriptor(temp_dir.path()),
431                             NULL,
432                             DoneCallbackRaiseSIGKILL,
433                             NULL,
434                             true,
435                             -1);
436     CrashWithCallbacks(NULL, NULL, temp_dir.path());
437   }
438   ASSERT_NO_FATAL_FAILURE(WaitForProcessToTerminate(child, SIGSEGV));
439 }
440
441 TEST(ExceptionHandlerTest, StackedHandlersFilteredToBottom) {
442   AutoTempDir temp_dir;
443
444   const pid_t child = fork();
445   if (child == 0) {
446     ExceptionHandler bottom(MinidumpDescriptor(temp_dir.path()),
447                             NULL,
448                             DoneCallbackRaiseSIGKILL,
449                             NULL,
450                             true,
451                             -1);
452     CrashWithCallbacks(FilterCallbackReturnFalse, NULL, temp_dir.path());
453   }
454   ASSERT_NO_FATAL_FAILURE(WaitForProcessToTerminate(child, SIGKILL));
455 }
456
457 TEST(ExceptionHandlerTest, StackedHandlersUnhandledToBottom) {
458   AutoTempDir temp_dir;
459
460   const pid_t child = fork();
461   if (child == 0) {
462     ExceptionHandler bottom(MinidumpDescriptor(temp_dir.path()),
463                             NULL,
464                             DoneCallbackRaiseSIGKILL,
465                             NULL,
466                             true,
467                             -1);
468     CrashWithCallbacks(NULL, DoneCallbackReturnFalse, temp_dir.path());
469   }
470   ASSERT_NO_FATAL_FAILURE(WaitForProcessToTerminate(child, SIGKILL));
471 }
472
473 #endif  // !ADDRESS_SANITIZER
474
475 const unsigned char kIllegalInstruction[] = {
476 #if defined(__mips__)
477   // mfc2 zero,Impl - usually illegal in userspace.
478   0x48, 0x00, 0x00, 0x48
479 #else
480   // This crashes with SIGILL on x86/x86-64/arm.
481   0xff, 0xff, 0xff, 0xff
482 #endif
483 };
484
485 // Test that memory around the instruction pointer is written
486 // to the dump as a MinidumpMemoryRegion.
487 TEST(ExceptionHandlerTest, InstructionPointerMemory) {
488   AutoTempDir temp_dir;
489   int fds[2];
490   ASSERT_NE(pipe(fds), -1);
491
492   // These are defined here so the parent can use them to check the
493   // data from the minidump afterwards.
494   const uint32_t kMemorySize = 256;  // bytes
495   const int kOffset = kMemorySize / 2;
496
497   const pid_t child = fork();
498   if (child == 0) {
499     close(fds[0]);
500     ExceptionHandler handler(MinidumpDescriptor(temp_dir.path()), NULL,
501                              DoneCallback, reinterpret_cast<void*>(fds[1]),
502                              true, -1);
503     // Get some executable memory.
504     char* memory =
505       reinterpret_cast<char*>(mmap(NULL,
506                                    kMemorySize,
507                                    PROT_READ | PROT_WRITE | PROT_EXEC,
508                                    MAP_PRIVATE | MAP_ANON,
509                                    -1,
510                                    0));
511     if (!memory)
512       exit(0);
513
514     // Write some instructions that will crash. Put them in the middle
515     // of the block of memory, because the minidump should contain 128
516     // bytes on either side of the instruction pointer.
517     memcpy(memory + kOffset, kIllegalInstruction, sizeof(kIllegalInstruction));
518     FlushInstructionCache(memory, kMemorySize);
519
520     // Now execute the instructions, which should crash.
521     typedef void (*void_function)(void);
522     void_function memory_function =
523         reinterpret_cast<void_function>(memory + kOffset);
524     memory_function();
525   }
526   close(fds[1]);
527
528   ASSERT_NO_FATAL_FAILURE(WaitForProcessToTerminate(child, SIGILL));
529
530   string minidump_path;
531   ASSERT_NO_FATAL_FAILURE(ReadMinidumpPathFromPipe(fds[0], &minidump_path));
532
533   struct stat st;
534   ASSERT_EQ(0, stat(minidump_path.c_str(), &st));
535   ASSERT_GT(st.st_size, 0);
536
537   // Read the minidump. Locate the exception record and the
538   // memory list, and then ensure that there is a memory region
539   // in the memory list that covers the instruction pointer from
540   // the exception record.
541   Minidump minidump(minidump_path);
542   ASSERT_TRUE(minidump.Read());
543
544   MinidumpException* exception = minidump.GetException();
545   MinidumpMemoryList* memory_list = minidump.GetMemoryList();
546   ASSERT_TRUE(exception);
547   ASSERT_TRUE(memory_list);
548   ASSERT_LT(0U, memory_list->region_count());
549
550   MinidumpContext* context = exception->GetContext();
551   ASSERT_TRUE(context);
552
553   uint64_t instruction_pointer;
554   ASSERT_TRUE(context->GetInstructionPointer(&instruction_pointer));
555
556   MinidumpMemoryRegion* region =
557       memory_list->GetMemoryRegionForAddress(instruction_pointer);
558   ASSERT_TRUE(region);
559
560   EXPECT_EQ(kMemorySize, region->GetSize());
561   const uint8_t* bytes = region->GetMemory();
562   ASSERT_TRUE(bytes);
563
564   uint8_t prefix_bytes[kOffset];
565   uint8_t suffix_bytes[kMemorySize - kOffset - sizeof(kIllegalInstruction)];
566   memset(prefix_bytes, 0, sizeof(prefix_bytes));
567   memset(suffix_bytes, 0, sizeof(suffix_bytes));
568   EXPECT_TRUE(memcmp(bytes, prefix_bytes, sizeof(prefix_bytes)) == 0);
569   EXPECT_TRUE(memcmp(bytes + kOffset, kIllegalInstruction, 
570                      sizeof(kIllegalInstruction)) == 0);
571   EXPECT_TRUE(memcmp(bytes + kOffset + sizeof(kIllegalInstruction),
572                      suffix_bytes, sizeof(suffix_bytes)) == 0);
573
574   unlink(minidump_path.c_str());
575 }
576
577 // Test that the memory region around the instruction pointer is
578 // bounded correctly on the low end.
579 TEST(ExceptionHandlerTest, InstructionPointerMemoryMinBound) {
580   AutoTempDir temp_dir;
581   int fds[2];
582   ASSERT_NE(pipe(fds), -1);
583
584   // These are defined here so the parent can use them to check the
585   // data from the minidump afterwards.
586   const uint32_t kMemorySize = 256;  // bytes
587   const int kOffset = 0;
588
589   const pid_t child = fork();
590   if (child == 0) {
591     close(fds[0]);
592     ExceptionHandler handler(MinidumpDescriptor(temp_dir.path()), NULL,
593                              DoneCallback, reinterpret_cast<void*>(fds[1]),
594                              true, -1);
595     // Get some executable memory.
596     char* memory =
597         reinterpret_cast<char*>(mmap(NULL,
598                                      kMemorySize,
599                                      PROT_READ | PROT_WRITE | PROT_EXEC,
600                                      MAP_PRIVATE | MAP_ANON,
601                                      -1,
602                                      0));
603     if (!memory)
604       exit(0);
605
606     // Write some instructions that will crash. Put them in the middle
607     // of the block of memory, because the minidump should contain 128
608     // bytes on either side of the instruction pointer.
609     memcpy(memory + kOffset, kIllegalInstruction, sizeof(kIllegalInstruction));
610     FlushInstructionCache(memory, kMemorySize);
611
612     // Now execute the instructions, which should crash.
613     typedef void (*void_function)(void);
614     void_function memory_function =
615         reinterpret_cast<void_function>(memory + kOffset);
616     memory_function();
617   }
618   close(fds[1]);
619
620   ASSERT_NO_FATAL_FAILURE(WaitForProcessToTerminate(child, SIGILL));
621
622   string minidump_path;
623   ASSERT_NO_FATAL_FAILURE(ReadMinidumpPathFromPipe(fds[0], &minidump_path));
624
625   struct stat st;
626   ASSERT_EQ(0, stat(minidump_path.c_str(), &st));
627   ASSERT_GT(st.st_size, 0);
628
629   // Read the minidump. Locate the exception record and the
630   // memory list, and then ensure that there is a memory region
631   // in the memory list that covers the instruction pointer from
632   // the exception record.
633   Minidump minidump(minidump_path);
634   ASSERT_TRUE(minidump.Read());
635
636   MinidumpException* exception = minidump.GetException();
637   MinidumpMemoryList* memory_list = minidump.GetMemoryList();
638   ASSERT_TRUE(exception);
639   ASSERT_TRUE(memory_list);
640   ASSERT_LT(0U, memory_list->region_count());
641
642   MinidumpContext* context = exception->GetContext();
643   ASSERT_TRUE(context);
644
645   uint64_t instruction_pointer;
646   ASSERT_TRUE(context->GetInstructionPointer(&instruction_pointer));
647
648   MinidumpMemoryRegion* region =
649       memory_list->GetMemoryRegionForAddress(instruction_pointer);
650   ASSERT_TRUE(region);
651
652   EXPECT_EQ(kMemorySize / 2, region->GetSize());
653   const uint8_t* bytes = region->GetMemory();
654   ASSERT_TRUE(bytes);
655
656   uint8_t suffix_bytes[kMemorySize / 2 - sizeof(kIllegalInstruction)];
657   memset(suffix_bytes, 0, sizeof(suffix_bytes));
658   EXPECT_TRUE(memcmp(bytes + kOffset, kIllegalInstruction, 
659                      sizeof(kIllegalInstruction)) == 0);
660   EXPECT_TRUE(memcmp(bytes + kOffset + sizeof(kIllegalInstruction),
661                      suffix_bytes, sizeof(suffix_bytes)) == 0);
662   unlink(minidump_path.c_str());
663 }
664
665 // Test that the memory region around the instruction pointer is
666 // bounded correctly on the high end.
667 TEST(ExceptionHandlerTest, InstructionPointerMemoryMaxBound) {
668   AutoTempDir temp_dir;
669   int fds[2];
670   ASSERT_NE(pipe(fds), -1);
671
672   // These are defined here so the parent can use them to check the
673   // data from the minidump afterwards.
674   // Use 4k here because the OS will hand out a single page even
675   // if a smaller size is requested, and this test wants to
676   // test the upper bound of the memory range.
677   const uint32_t kMemorySize = 4096;  // bytes
678   const int kOffset = kMemorySize - sizeof(kIllegalInstruction);
679
680   const pid_t child = fork();
681   if (child == 0) {
682     close(fds[0]);
683     ExceptionHandler handler(MinidumpDescriptor(temp_dir.path()), NULL,
684                              DoneCallback, reinterpret_cast<void*>(fds[1]),
685                              true, -1);
686     // Get some executable memory.
687     char* memory =
688         reinterpret_cast<char*>(mmap(NULL,
689                                      kMemorySize,
690                                      PROT_READ | PROT_WRITE | PROT_EXEC,
691                                      MAP_PRIVATE | MAP_ANON,
692                                      -1,
693                                      0));
694     if (!memory)
695       exit(0);
696
697     // Write some instructions that will crash. Put them in the middle
698     // of the block of memory, because the minidump should contain 128
699     // bytes on either side of the instruction pointer.
700     memcpy(memory + kOffset, kIllegalInstruction, sizeof(kIllegalInstruction));
701     FlushInstructionCache(memory, kMemorySize);
702
703     // Now execute the instructions, which should crash.
704     typedef void (*void_function)(void);
705     void_function memory_function =
706         reinterpret_cast<void_function>(memory + kOffset);
707     memory_function();
708   }
709   close(fds[1]);
710
711   ASSERT_NO_FATAL_FAILURE(WaitForProcessToTerminate(child, SIGILL));
712
713   string minidump_path;
714   ASSERT_NO_FATAL_FAILURE(ReadMinidumpPathFromPipe(fds[0], &minidump_path));
715
716   struct stat st;
717   ASSERT_EQ(0, stat(minidump_path.c_str(), &st));
718   ASSERT_GT(st.st_size, 0);
719
720   // Read the minidump. Locate the exception record and the memory list, and
721   // then ensure that there is a memory region in the memory list that covers
722   // the instruction pointer from the exception record.
723   Minidump minidump(minidump_path);
724   ASSERT_TRUE(minidump.Read());
725
726   MinidumpException* exception = minidump.GetException();
727   MinidumpMemoryList* memory_list = minidump.GetMemoryList();
728   ASSERT_TRUE(exception);
729   ASSERT_TRUE(memory_list);
730   ASSERT_LT(0U, memory_list->region_count());
731
732   MinidumpContext* context = exception->GetContext();
733   ASSERT_TRUE(context);
734
735   uint64_t instruction_pointer;
736   ASSERT_TRUE(context->GetInstructionPointer(&instruction_pointer));
737
738   MinidumpMemoryRegion* region =
739       memory_list->GetMemoryRegionForAddress(instruction_pointer);
740   ASSERT_TRUE(region);
741
742   const size_t kPrefixSize = 128;  // bytes
743   EXPECT_EQ(kPrefixSize + sizeof(kIllegalInstruction), region->GetSize());
744   const uint8_t* bytes = region->GetMemory();
745   ASSERT_TRUE(bytes);
746
747   uint8_t prefix_bytes[kPrefixSize];
748   memset(prefix_bytes, 0, sizeof(prefix_bytes));
749   EXPECT_TRUE(memcmp(bytes, prefix_bytes, sizeof(prefix_bytes)) == 0);
750   EXPECT_TRUE(memcmp(bytes + kPrefixSize,
751                      kIllegalInstruction, sizeof(kIllegalInstruction)) == 0);
752
753   unlink(minidump_path.c_str());
754 }
755
756 #ifndef ADDRESS_SANITIZER
757
758 // Ensure that an extra memory block doesn't get added when the instruction
759 // pointer is not in mapped memory.
760 TEST(ExceptionHandlerTest, InstructionPointerMemoryNullPointer) {
761   AutoTempDir temp_dir;
762   int fds[2];
763   ASSERT_NE(pipe(fds), -1);
764
765   const pid_t child = fork();
766   if (child == 0) {
767     close(fds[0]);
768     ExceptionHandler handler(MinidumpDescriptor(temp_dir.path()), NULL,
769                              DoneCallback, reinterpret_cast<void*>(fds[1]),
770                              true, -1);
771     // Try calling a NULL pointer.
772     typedef void (*void_function)(void);
773     void_function memory_function = reinterpret_cast<void_function>(NULL);
774     memory_function();
775   }
776   close(fds[1]);
777
778   ASSERT_NO_FATAL_FAILURE(WaitForProcessToTerminate(child, SIGSEGV));
779
780   string minidump_path;
781   ASSERT_NO_FATAL_FAILURE(ReadMinidumpPathFromPipe(fds[0], &minidump_path));
782
783   struct stat st;
784   ASSERT_EQ(0, stat(minidump_path.c_str(), &st));
785   ASSERT_GT(st.st_size, 0);
786
787   // Read the minidump. Locate the exception record and the
788   // memory list, and then ensure that there is a memory region
789   // in the memory list that covers the instruction pointer from
790   // the exception record.
791   Minidump minidump(minidump_path);
792   ASSERT_TRUE(minidump.Read());
793
794   MinidumpException* exception = minidump.GetException();
795   MinidumpMemoryList* memory_list = minidump.GetMemoryList();
796   ASSERT_TRUE(exception);
797   ASSERT_TRUE(memory_list);
798   ASSERT_EQ(static_cast<unsigned int>(1), memory_list->region_count());
799
800   unlink(minidump_path.c_str());
801 }
802
803 #endif  // !ADDRESS_SANITIZER
804
805 // Test that anonymous memory maps can be annotated with names and IDs.
806 TEST(ExceptionHandlerTest, ModuleInfo) {
807   // These are defined here so the parent can use them to check the
808   // data from the minidump afterwards.
809   const uint32_t kMemorySize = sysconf(_SC_PAGESIZE);
810   const char* kMemoryName = "a fake module";
811   const uint8_t kModuleGUID[sizeof(MDGUID)] = {
812     0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77,
813     0x88, 0x99, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF
814   };
815   char module_identifier_buffer[kGUIDStringSize];
816   FileID::ConvertIdentifierToString(kModuleGUID,
817                                     module_identifier_buffer,
818                                     sizeof(module_identifier_buffer));
819   string module_identifier(module_identifier_buffer);
820   // Strip out dashes
821   size_t pos;
822   while ((pos = module_identifier.find('-')) != string::npos) {
823     module_identifier.erase(pos, 1);
824   }
825   // And append a zero, because module IDs include an "age" field
826   // which is always zero on Linux.
827   module_identifier += "0";
828
829   // Get some memory.
830   char* memory =
831       reinterpret_cast<char*>(mmap(NULL,
832                                    kMemorySize,
833                                    PROT_READ | PROT_WRITE,
834                                    MAP_PRIVATE | MAP_ANON,
835                                    -1,
836                                    0));
837   const uintptr_t kMemoryAddress = reinterpret_cast<uintptr_t>(memory);
838   ASSERT_TRUE(memory);
839
840   AutoTempDir temp_dir;
841   ExceptionHandler handler(
842       MinidumpDescriptor(temp_dir.path()), NULL, NULL, NULL, true, -1);
843
844   // Add info about the anonymous memory mapping.
845   handler.AddMappingInfo(kMemoryName,
846                          kModuleGUID,
847                          kMemoryAddress,
848                          kMemorySize,
849                          0);
850   ASSERT_TRUE(handler.WriteMinidump());
851
852   const MinidumpDescriptor& minidump_desc = handler.minidump_descriptor();
853   // Read the minidump. Load the module list, and ensure that the mmap'ed
854   // |memory| is listed with the given module name and debug ID.
855   Minidump minidump(minidump_desc.path());
856   ASSERT_TRUE(minidump.Read());
857
858   MinidumpModuleList* module_list = minidump.GetModuleList();
859   ASSERT_TRUE(module_list);
860   const MinidumpModule* module =
861       module_list->GetModuleForAddress(kMemoryAddress);
862   ASSERT_TRUE(module);
863
864   EXPECT_EQ(kMemoryAddress, module->base_address());
865   EXPECT_EQ(kMemorySize, module->size());
866   EXPECT_EQ(kMemoryName, module->code_file());
867   EXPECT_EQ(module_identifier, module->debug_identifier());
868
869   unlink(minidump_desc.path());
870 }
871
872 static const unsigned kControlMsgSize =
873     CMSG_SPACE(sizeof(int)) + CMSG_SPACE(sizeof(struct ucred));
874
875 static bool
876 CrashHandler(const void* crash_context, size_t crash_context_size,
877              void* context) {
878   const int fd = (intptr_t) context;
879   int fds[2];
880   if (pipe(fds) == -1) {
881     // There doesn't seem to be any way to reliably handle
882     // this failure without the parent process hanging
883     // At least make sure that this process doesn't access
884     // unexpected file descriptors
885     fds[0] = -1;
886     fds[1] = -1;
887   }
888   struct kernel_msghdr msg = {0};
889   struct kernel_iovec iov;
890   iov.iov_base = const_cast<void*>(crash_context);
891   iov.iov_len = crash_context_size;
892   msg.msg_iov = &iov;
893   msg.msg_iovlen = 1;
894   char cmsg[kControlMsgSize];
895   memset(cmsg, 0, kControlMsgSize);
896   msg.msg_control = cmsg;
897   msg.msg_controllen = sizeof(cmsg);
898
899   struct cmsghdr *hdr = CMSG_FIRSTHDR(&msg);
900   hdr->cmsg_level = SOL_SOCKET;
901   hdr->cmsg_type = SCM_RIGHTS;
902   hdr->cmsg_len = CMSG_LEN(sizeof(int));
903   *((int*) CMSG_DATA(hdr)) = fds[1];
904   hdr = CMSG_NXTHDR((struct msghdr*) &msg, hdr);
905   hdr->cmsg_level = SOL_SOCKET;
906   hdr->cmsg_type = SCM_CREDENTIALS;
907   hdr->cmsg_len = CMSG_LEN(sizeof(struct ucred));
908   struct ucred *cred = reinterpret_cast<struct ucred*>(CMSG_DATA(hdr));
909   cred->uid = getuid();
910   cred->gid = getgid();
911   cred->pid = getpid();
912
913   ssize_t ret = HANDLE_EINTR(sys_sendmsg(fd, &msg, 0));
914   sys_close(fds[1]);
915   if (ret <= 0)
916     return false;
917
918   char b;
919   IGNORE_RET(HANDLE_EINTR(sys_read(fds[0], &b, 1)));
920
921   return true;
922 }
923
924 #ifndef ADDRESS_SANITIZER
925
926 TEST(ExceptionHandlerTest, ExternalDumper) {
927   int fds[2];
928   ASSERT_NE(socketpair(AF_UNIX, SOCK_DGRAM, 0, fds), -1);
929   static const int on = 1;
930   setsockopt(fds[0], SOL_SOCKET, SO_PASSCRED, &on, sizeof(on));
931   setsockopt(fds[1], SOL_SOCKET, SO_PASSCRED, &on, sizeof(on));
932
933   const pid_t child = fork();
934   if (child == 0) {
935     close(fds[0]);
936     ExceptionHandler handler(MinidumpDescriptor("/tmp1"), NULL, NULL,
937                              reinterpret_cast<void*>(fds[1]), true, -1);
938     handler.set_crash_handler(CrashHandler);
939     DoNullPointerDereference();
940   }
941   close(fds[1]);
942   struct msghdr msg = {0};
943   struct iovec iov;
944   static const unsigned kCrashContextSize =
945       sizeof(ExceptionHandler::CrashContext);
946   char context[kCrashContextSize];
947   char control[kControlMsgSize];
948   iov.iov_base = context;
949   iov.iov_len = kCrashContextSize;
950   msg.msg_iov = &iov;
951   msg.msg_iovlen = 1;
952   msg.msg_control = control;
953   msg.msg_controllen = kControlMsgSize;
954
955   const ssize_t n = HANDLE_EINTR(recvmsg(fds[0], &msg, 0));
956   ASSERT_EQ(static_cast<ssize_t>(kCrashContextSize), n);
957   ASSERT_EQ(kControlMsgSize, msg.msg_controllen);
958   ASSERT_EQ(static_cast<typeof(msg.msg_flags)>(0), msg.msg_flags);
959   ASSERT_EQ(0, close(fds[0]));
960
961   pid_t crashing_pid = -1;
962   int signal_fd = -1;
963   for (struct cmsghdr *hdr = CMSG_FIRSTHDR(&msg); hdr;
964        hdr = CMSG_NXTHDR(&msg, hdr)) {
965     if (hdr->cmsg_level != SOL_SOCKET)
966       continue;
967     if (hdr->cmsg_type == SCM_RIGHTS) {
968       const unsigned len = hdr->cmsg_len -
969           (((uint8_t*)CMSG_DATA(hdr)) - (uint8_t*)hdr);
970       ASSERT_EQ(sizeof(int), len);
971       signal_fd = *(reinterpret_cast<int*>(CMSG_DATA(hdr)));
972     } else if (hdr->cmsg_type == SCM_CREDENTIALS) {
973       const struct ucred *cred =
974           reinterpret_cast<struct ucred*>(CMSG_DATA(hdr));
975       crashing_pid = cred->pid;
976     }
977   }
978
979   ASSERT_NE(crashing_pid, -1);
980   ASSERT_NE(signal_fd, -1);
981
982   AutoTempDir temp_dir;
983   string templ = temp_dir.path() + "/exception-handler-unittest";
984   ASSERT_TRUE(WriteMinidump(templ.c_str(), crashing_pid, context,
985                             kCrashContextSize));
986   static const char b = 0;
987   ASSERT_EQ(1, (HANDLE_EINTR(write(signal_fd, &b, 1))));
988   ASSERT_EQ(0, close(signal_fd));
989
990   ASSERT_NO_FATAL_FAILURE(WaitForProcessToTerminate(child, SIGSEGV));
991
992   struct stat st;
993   ASSERT_EQ(0, stat(templ.c_str(), &st));
994   ASSERT_GT(st.st_size, 0);
995   unlink(templ.c_str());
996 }
997
998 #endif  // !ADDRESS_SANITIZER
999
1000 TEST(ExceptionHandlerTest, WriteMinidumpExceptionStream) {
1001   AutoTempDir temp_dir;
1002   ExceptionHandler handler(MinidumpDescriptor(temp_dir.path()), NULL, NULL,
1003                            NULL, false, -1);
1004   ASSERT_TRUE(handler.WriteMinidump());
1005
1006   string minidump_path = handler.minidump_descriptor().path();
1007
1008   // Read the minidump and check the exception stream.
1009   Minidump minidump(minidump_path);
1010   ASSERT_TRUE(minidump.Read());
1011   MinidumpException* exception = minidump.GetException();
1012   ASSERT_TRUE(exception);
1013   const MDRawExceptionStream* raw = exception->exception();
1014   ASSERT_TRUE(raw);
1015   EXPECT_EQ(MD_EXCEPTION_CODE_LIN_DUMP_REQUESTED,
1016             raw->exception_record.exception_code);
1017 }
1018
1019 TEST(ExceptionHandlerTest, GenerateMultipleDumpsWithFD) {
1020   AutoTempDir temp_dir;
1021   string path;
1022   const int fd = CreateTMPFile(temp_dir.path(), &path);
1023   ExceptionHandler handler(MinidumpDescriptor(fd), NULL, NULL, NULL, false, -1);
1024   ASSERT_TRUE(handler.WriteMinidump());
1025   // Check by the size of the data written to the FD that a minidump was
1026   // generated.
1027   off_t size = lseek(fd, 0, SEEK_CUR);
1028   ASSERT_GT(size, 0);
1029
1030   // Generate another minidump.
1031   ASSERT_TRUE(handler.WriteMinidump());
1032   size = lseek(fd, 0, SEEK_CUR);
1033   ASSERT_GT(size, 0);
1034 }
1035
1036 TEST(ExceptionHandlerTest, GenerateMultipleDumpsWithPath) {
1037   AutoTempDir temp_dir;
1038   ExceptionHandler handler(MinidumpDescriptor(temp_dir.path()), NULL, NULL,
1039                            NULL, false, -1);
1040   ASSERT_TRUE(handler.WriteMinidump());
1041
1042   const MinidumpDescriptor& minidump_1 = handler.minidump_descriptor();
1043   struct stat st;
1044   ASSERT_EQ(0, stat(minidump_1.path(), &st));
1045   ASSERT_GT(st.st_size, 0);
1046   string minidump_1_path(minidump_1.path());
1047   // Check it is a valid minidump.
1048   Minidump minidump1(minidump_1_path);
1049   ASSERT_TRUE(minidump1.Read());
1050   unlink(minidump_1.path());
1051
1052   // Generate another minidump, it should go to a different file.
1053   ASSERT_TRUE(handler.WriteMinidump());
1054   const MinidumpDescriptor& minidump_2 = handler.minidump_descriptor();
1055   ASSERT_EQ(0, stat(minidump_2.path(), &st));
1056   ASSERT_GT(st.st_size, 0);
1057   string minidump_2_path(minidump_2.path());
1058   // Check it is a valid minidump.
1059   Minidump minidump2(minidump_2_path);
1060   ASSERT_TRUE(minidump2.Read());
1061   unlink(minidump_2.path());
1062
1063   // 2 distinct files should be produced.
1064   ASSERT_STRNE(minidump_1_path.c_str(), minidump_2_path.c_str());
1065 }
1066
1067 // Test that an additional memory region can be added to the minidump.
1068 TEST(ExceptionHandlerTest, AdditionalMemory) {
1069   const uint32_t kMemorySize = sysconf(_SC_PAGESIZE);
1070
1071   // Get some heap memory.
1072   uint8_t* memory = new uint8_t[kMemorySize];
1073   const uintptr_t kMemoryAddress = reinterpret_cast<uintptr_t>(memory);
1074   ASSERT_TRUE(memory);
1075
1076   // Stick some data into the memory so the contents can be verified.
1077   for (uint32_t i = 0; i < kMemorySize; ++i) {
1078     memory[i] = i % 255;
1079   }
1080
1081   AutoTempDir temp_dir;
1082   ExceptionHandler handler(
1083       MinidumpDescriptor(temp_dir.path()), NULL, NULL, NULL, true, -1);
1084
1085   // Add the memory region to the list of memory to be included.
1086   handler.RegisterAppMemory(memory, kMemorySize);
1087   handler.WriteMinidump();
1088
1089   const MinidumpDescriptor& minidump_desc = handler.minidump_descriptor();
1090
1091   // Read the minidump. Ensure that the memory region is present
1092   Minidump minidump(minidump_desc.path());
1093   ASSERT_TRUE(minidump.Read());
1094
1095   MinidumpMemoryList* dump_memory_list = minidump.GetMemoryList();
1096   ASSERT_TRUE(dump_memory_list);
1097   const MinidumpMemoryRegion* region =
1098     dump_memory_list->GetMemoryRegionForAddress(kMemoryAddress);
1099   ASSERT_TRUE(region);
1100
1101   EXPECT_EQ(kMemoryAddress, region->GetBase());
1102   EXPECT_EQ(kMemorySize, region->GetSize());
1103
1104   // Verify memory contents.
1105   EXPECT_EQ(0, memcmp(region->GetMemory(), memory, kMemorySize));
1106
1107   delete[] memory;
1108 }
1109
1110 // Test that a memory region that was previously registered
1111 // can be unregistered.
1112 TEST(ExceptionHandlerTest, AdditionalMemoryRemove) {
1113   const uint32_t kMemorySize = sysconf(_SC_PAGESIZE);
1114
1115   // Get some heap memory.
1116   uint8_t* memory = new uint8_t[kMemorySize];
1117   const uintptr_t kMemoryAddress = reinterpret_cast<uintptr_t>(memory);
1118   ASSERT_TRUE(memory);
1119
1120   AutoTempDir temp_dir;
1121   ExceptionHandler handler(
1122       MinidumpDescriptor(temp_dir.path()), NULL, NULL, NULL, true, -1);
1123
1124   // Add the memory region to the list of memory to be included.
1125   handler.RegisterAppMemory(memory, kMemorySize);
1126
1127   // ...and then remove it
1128   handler.UnregisterAppMemory(memory);
1129   handler.WriteMinidump();
1130
1131   const MinidumpDescriptor& minidump_desc = handler.minidump_descriptor();
1132
1133   // Read the minidump. Ensure that the memory region is not present.
1134   Minidump minidump(minidump_desc.path());
1135   ASSERT_TRUE(minidump.Read());
1136
1137   MinidumpMemoryList* dump_memory_list = minidump.GetMemoryList();
1138   ASSERT_TRUE(dump_memory_list);
1139   const MinidumpMemoryRegion* region =
1140     dump_memory_list->GetMemoryRegionForAddress(kMemoryAddress);
1141   EXPECT_FALSE(region);
1142
1143   delete[] memory;
1144 }
1145
1146 static bool SimpleCallback(const MinidumpDescriptor& descriptor,
1147                            void* context,
1148                            bool succeeded) {
1149   string* filename = reinterpret_cast<string*>(context);
1150   *filename = descriptor.path();
1151   return true;
1152 }
1153
1154 TEST(ExceptionHandlerTest, WriteMinidumpForChild) {
1155   int fds[2];
1156   ASSERT_NE(-1, pipe(fds));
1157
1158   const pid_t child = fork();
1159   if (child == 0) {
1160     close(fds[1]);
1161     char b;
1162     HANDLE_EINTR(read(fds[0], &b, sizeof(b)));
1163     close(fds[0]);
1164     syscall(__NR_exit);
1165   }
1166   close(fds[0]);
1167
1168   AutoTempDir temp_dir;
1169   string minidump_filename;
1170   ASSERT_TRUE(
1171     ExceptionHandler::WriteMinidumpForChild(child, child,
1172                                             temp_dir.path(), SimpleCallback,
1173                                             (void*)&minidump_filename));
1174
1175   Minidump minidump(minidump_filename);
1176   ASSERT_TRUE(minidump.Read());
1177   // Check that the crashing thread is the main thread of |child|
1178   MinidumpException* exception = minidump.GetException();
1179   ASSERT_TRUE(exception);
1180   uint32_t thread_id;
1181   ASSERT_TRUE(exception->GetThreadID(&thread_id));
1182   EXPECT_EQ(child, static_cast<int32_t>(thread_id));
1183
1184   const MDRawExceptionStream* raw = exception->exception();
1185   ASSERT_TRUE(raw);
1186   EXPECT_EQ(MD_EXCEPTION_CODE_LIN_DUMP_REQUESTED,
1187             raw->exception_record.exception_code);
1188
1189   close(fds[1]);
1190   unlink(minidump_filename.c_str());
1191 }