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 <poll.h>
31 #include <pthread.h>
32 #include <stdint.h>
33 #include <unistd.h>
34 #include <signal.h>
35 #include <sys/mman.h>
36 #include <sys/socket.h>
37 #include <sys/uio.h>
38 #include <sys/wait.h>
39 #if defined(__mips__)
40 #include <sys/cachectl.h>
41 #endif
42
43 #include <string>
44
45 #include "breakpad_googletest_includes.h"
46 #include "client/linux/handler/exception_handler.h"
47 #include "client/linux/minidump_writer/minidump_writer.h"
48 #include "common/linux/eintr_wrapper.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.
FlushInstructionCache(const char * memory,uint32_t memory_size)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 #if _MIPS_SIM == _ABIO32
84 cacheflush(begin, end, 0);
85 #else
86 syscall(__NR_cacheflush, begin, end, ICACHE);
87 #endif
88 # elif defined(__linux__)
89 // See http://www.linux-mips.org/wiki/Cacheflush_Syscall.
90 cacheflush(const_cast<char*>(memory), memory_size, ICACHE);
91 # else
92 # error "Your operating system is not supported yet"
93 # endif
94 #endif
95 }
96
sigchld_handler(int signo)97 void sigchld_handler(int signo) { }
98
CreateTMPFile(const string & dir,string * path)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:
SetUp()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
TearDown()121 void TearDown() {
122 sigaction(SIGCHLD, &old_action, NULL);
123 }
124
125 struct sigaction old_action;
126 };
127
128
WaitForProcessToTerminate(pid_t process_id,int expected_status)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|.
ReadMinidumpPathFromPipe(int fd,string * 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
TEST(ExceptionHandlerTest,SimpleWithPath)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
TEST(ExceptionHandlerTest,SimpleWithFD)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
DoneCallback(const MinidumpDescriptor & descriptor,void * context,bool succeeded)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.
DoNullPointerDereference()206 static void DoNullPointerDereference() {
207 *p_null = 1;
208 }
209
ChildCrash(bool use_fd)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
TEST(ExceptionHandlerTest,ChildCrashWithPath)253 TEST(ExceptionHandlerTest, ChildCrashWithPath) {
254 ASSERT_NO_FATAL_FAILURE(ChildCrash(false));
255 }
256
TEST(ExceptionHandlerTest,ChildCrashWithFD)257 TEST(ExceptionHandlerTest, ChildCrashWithFD) {
258 ASSERT_NO_FATAL_FAILURE(ChildCrash(true));
259 }
260
261 #if !defined(__ANDROID_API__) || __ANDROID_API__ >= __ANDROID_API_N__
SleepFunction(void * unused)262 static void* SleepFunction(void* unused) {
263 while (true) usleep(1000000);
264 return NULL;
265 }
266
CrashFunction(void * b_ptr)267 static void* CrashFunction(void* b_ptr) {
268 pthread_barrier_t* b = reinterpret_cast<pthread_barrier_t*>(b_ptr);
269 pthread_barrier_wait(b);
270 DoNullPointerDereference();
271 return NULL;
272 }
273
274 // Tests that concurrent crashes do not enter a loop by alternately triggering
275 // the signal handler.
TEST(ExceptionHandlerTest,ParallelChildCrashesDontHang)276 TEST(ExceptionHandlerTest, ParallelChildCrashesDontHang) {
277 AutoTempDir temp_dir;
278 const pid_t child = fork();
279 if (child == 0) {
280 google_breakpad::scoped_ptr<ExceptionHandler> handler(
281 new ExceptionHandler(MinidumpDescriptor(temp_dir.path()), NULL, NULL,
282 NULL, true, -1));
283
284 // We start a number of threads to make sure handling the signal takes
285 // enough time for the second thread to enter the signal handler.
286 int num_sleep_threads = 100;
287 google_breakpad::scoped_array<pthread_t> sleep_threads(
288 new pthread_t[num_sleep_threads]);
289 for (int i = 0; i < num_sleep_threads; ++i) {
290 ASSERT_EQ(0, pthread_create(&sleep_threads[i], NULL, SleepFunction,
291 NULL));
292 }
293
294 int num_crash_threads = 2;
295 google_breakpad::scoped_array<pthread_t> crash_threads(
296 new pthread_t[num_crash_threads]);
297 // Barrier to synchronize crashing both threads at the same time.
298 pthread_barrier_t b;
299 ASSERT_EQ(0, pthread_barrier_init(&b, NULL, num_crash_threads + 1));
300 for (int i = 0; i < num_crash_threads; ++i) {
301 ASSERT_EQ(0, pthread_create(&crash_threads[i], NULL, CrashFunction, &b));
302 }
303 pthread_barrier_wait(&b);
304 for (int i = 0; i < num_crash_threads; ++i) {
305 ASSERT_EQ(0, pthread_join(crash_threads[i], NULL));
306 }
307 }
308
309 // Wait a while until the child should have crashed.
310 usleep(1000000);
311 // Kill the child if it is still running.
312 kill(child, SIGKILL);
313
314 // If the child process terminated by itself, it will have returned SIGSEGV.
315 // If however it got stuck in a loop, it will have been killed by the
316 // SIGKILL.
317 ASSERT_NO_FATAL_FAILURE(WaitForProcessToTerminate(child, SIGSEGV));
318 }
319 #endif // !defined(__ANDROID_API__) || __ANDROID_API__ >= __ANDROID_API_N__
320
DoneCallbackReturnFalse(const MinidumpDescriptor & descriptor,void * context,bool succeeded)321 static bool DoneCallbackReturnFalse(const MinidumpDescriptor& descriptor,
322 void* context,
323 bool succeeded) {
324 return false;
325 }
326
DoneCallbackReturnTrue(const MinidumpDescriptor & descriptor,void * context,bool succeeded)327 static bool DoneCallbackReturnTrue(const MinidumpDescriptor& descriptor,
328 void* context,
329 bool succeeded) {
330 return true;
331 }
332
DoneCallbackRaiseSIGKILL(const MinidumpDescriptor & descriptor,void * context,bool succeeded)333 static bool DoneCallbackRaiseSIGKILL(const MinidumpDescriptor& descriptor,
334 void* context,
335 bool succeeded) {
336 raise(SIGKILL);
337 return true;
338 }
339
FilterCallbackReturnFalse(void * context)340 static bool FilterCallbackReturnFalse(void* context) {
341 return false;
342 }
343
FilterCallbackReturnTrue(void * context)344 static bool FilterCallbackReturnTrue(void* context) {
345 return true;
346 }
347
348 // SIGKILL cannot be blocked and a handler cannot be installed for it. In the
349 // following tests, if the child dies with signal SIGKILL, then the signal was
350 // redelivered to this handler. If the child dies with SIGSEGV then it wasn't.
RaiseSIGKILL(int sig)351 static void RaiseSIGKILL(int sig) {
352 raise(SIGKILL);
353 }
354
InstallRaiseSIGKILL()355 static bool InstallRaiseSIGKILL() {
356 struct sigaction sa;
357 memset(&sa, 0, sizeof(sa));
358 sa.sa_handler = RaiseSIGKILL;
359 return sigaction(SIGSEGV, &sa, NULL) != -1;
360 }
361
CrashWithCallbacks(ExceptionHandler::FilterCallback filter,ExceptionHandler::MinidumpCallback done,string path)362 static void CrashWithCallbacks(ExceptionHandler::FilterCallback filter,
363 ExceptionHandler::MinidumpCallback done,
364 string path) {
365 ExceptionHandler handler(
366 MinidumpDescriptor(path), filter, done, NULL, true, -1);
367 // Crash with the exception handler in scope.
368 DoNullPointerDereference();
369 }
370
TEST(ExceptionHandlerTest,RedeliveryOnFilterCallbackFalse)371 TEST(ExceptionHandlerTest, RedeliveryOnFilterCallbackFalse) {
372 AutoTempDir temp_dir;
373
374 const pid_t child = fork();
375 if (child == 0) {
376 ASSERT_TRUE(InstallRaiseSIGKILL());
377 CrashWithCallbacks(FilterCallbackReturnFalse, NULL, temp_dir.path());
378 }
379
380 ASSERT_NO_FATAL_FAILURE(WaitForProcessToTerminate(child, SIGKILL));
381 }
382
TEST(ExceptionHandlerTest,RedeliveryOnDoneCallbackFalse)383 TEST(ExceptionHandlerTest, RedeliveryOnDoneCallbackFalse) {
384 AutoTempDir temp_dir;
385
386 const pid_t child = fork();
387 if (child == 0) {
388 ASSERT_TRUE(InstallRaiseSIGKILL());
389 CrashWithCallbacks(NULL, DoneCallbackReturnFalse, temp_dir.path());
390 }
391
392 ASSERT_NO_FATAL_FAILURE(WaitForProcessToTerminate(child, SIGKILL));
393 }
394
TEST(ExceptionHandlerTest,NoRedeliveryOnDoneCallbackTrue)395 TEST(ExceptionHandlerTest, NoRedeliveryOnDoneCallbackTrue) {
396 AutoTempDir temp_dir;
397
398 const pid_t child = fork();
399 if (child == 0) {
400 ASSERT_TRUE(InstallRaiseSIGKILL());
401 CrashWithCallbacks(NULL, DoneCallbackReturnTrue, temp_dir.path());
402 }
403
404 ASSERT_NO_FATAL_FAILURE(WaitForProcessToTerminate(child, SIGSEGV));
405 }
406
TEST(ExceptionHandlerTest,NoRedeliveryOnFilterCallbackTrue)407 TEST(ExceptionHandlerTest, NoRedeliveryOnFilterCallbackTrue) {
408 AutoTempDir temp_dir;
409
410 const pid_t child = fork();
411 if (child == 0) {
412 ASSERT_TRUE(InstallRaiseSIGKILL());
413 CrashWithCallbacks(FilterCallbackReturnTrue, NULL, temp_dir.path());
414 }
415
416 ASSERT_NO_FATAL_FAILURE(WaitForProcessToTerminate(child, SIGSEGV));
417 }
418
TEST(ExceptionHandlerTest,RedeliveryToDefaultHandler)419 TEST(ExceptionHandlerTest, RedeliveryToDefaultHandler) {
420 AutoTempDir temp_dir;
421
422 const pid_t child = fork();
423 if (child == 0) {
424 // Custom signal handlers, which may have been installed by a test launcher,
425 // are undesirable in this child.
426 signal(SIGSEGV, SIG_DFL);
427
428 CrashWithCallbacks(FilterCallbackReturnFalse, NULL, temp_dir.path());
429 }
430
431 // As RaiseSIGKILL wasn't installed, the redelivery should just kill the child
432 // with SIGSEGV.
433 ASSERT_NO_FATAL_FAILURE(WaitForProcessToTerminate(child, SIGSEGV));
434 }
435
436 // Check that saving and restoring the signal handler with 'signal'
437 // instead of 'sigaction' doesn't make the Breakpad signal handler
438 // crash. See comments in ExceptionHandler::SignalHandler for full
439 // details.
TEST(ExceptionHandlerTest,RedeliveryOnBadSignalHandlerFlag)440 TEST(ExceptionHandlerTest, RedeliveryOnBadSignalHandlerFlag) {
441 AutoTempDir temp_dir;
442 const pid_t child = fork();
443 if (child == 0) {
444 // Install the RaiseSIGKILL handler for SIGSEGV.
445 ASSERT_TRUE(InstallRaiseSIGKILL());
446
447 // Create a new exception handler, this installs a new SIGSEGV
448 // handler, after saving the old one.
449 ExceptionHandler handler(
450 MinidumpDescriptor(temp_dir.path()), NULL,
451 DoneCallbackReturnFalse, NULL, true, -1);
452
453 // Install the default SIGSEGV handler, saving the current one.
454 // Then re-install the current one with 'signal', this loses the
455 // SA_SIGINFO flag associated with the Breakpad handler.
456 sighandler_t old_handler = signal(SIGSEGV, SIG_DFL);
457 ASSERT_NE(reinterpret_cast<void*>(old_handler),
458 reinterpret_cast<void*>(SIG_ERR));
459 ASSERT_NE(reinterpret_cast<void*>(signal(SIGSEGV, old_handler)),
460 reinterpret_cast<void*>(SIG_ERR));
461
462 // Crash with the exception handler in scope.
463 DoNullPointerDereference();
464 }
465 // SIGKILL means Breakpad's signal handler didn't crash.
466 ASSERT_NO_FATAL_FAILURE(WaitForProcessToTerminate(child, SIGKILL));
467 }
468
TEST(ExceptionHandlerTest,StackedHandlersDeliveredToTop)469 TEST(ExceptionHandlerTest, StackedHandlersDeliveredToTop) {
470 AutoTempDir temp_dir;
471
472 const pid_t child = fork();
473 if (child == 0) {
474 ExceptionHandler bottom(MinidumpDescriptor(temp_dir.path()),
475 NULL,
476 NULL,
477 NULL,
478 true,
479 -1);
480 CrashWithCallbacks(NULL, DoneCallbackRaiseSIGKILL, temp_dir.path());
481 }
482 ASSERT_NO_FATAL_FAILURE(WaitForProcessToTerminate(child, SIGKILL));
483 }
484
TEST(ExceptionHandlerTest,StackedHandlersNotDeliveredToBottom)485 TEST(ExceptionHandlerTest, StackedHandlersNotDeliveredToBottom) {
486 AutoTempDir temp_dir;
487
488 const pid_t child = fork();
489 if (child == 0) {
490 ExceptionHandler bottom(MinidumpDescriptor(temp_dir.path()),
491 NULL,
492 DoneCallbackRaiseSIGKILL,
493 NULL,
494 true,
495 -1);
496 CrashWithCallbacks(NULL, NULL, temp_dir.path());
497 }
498 ASSERT_NO_FATAL_FAILURE(WaitForProcessToTerminate(child, SIGSEGV));
499 }
500
TEST(ExceptionHandlerTest,StackedHandlersFilteredToBottom)501 TEST(ExceptionHandlerTest, StackedHandlersFilteredToBottom) {
502 AutoTempDir temp_dir;
503
504 const pid_t child = fork();
505 if (child == 0) {
506 ExceptionHandler bottom(MinidumpDescriptor(temp_dir.path()),
507 NULL,
508 DoneCallbackRaiseSIGKILL,
509 NULL,
510 true,
511 -1);
512 CrashWithCallbacks(FilterCallbackReturnFalse, NULL, temp_dir.path());
513 }
514 ASSERT_NO_FATAL_FAILURE(WaitForProcessToTerminate(child, SIGKILL));
515 }
516
TEST(ExceptionHandlerTest,StackedHandlersUnhandledToBottom)517 TEST(ExceptionHandlerTest, StackedHandlersUnhandledToBottom) {
518 AutoTempDir temp_dir;
519
520 const pid_t child = fork();
521 if (child == 0) {
522 ExceptionHandler bottom(MinidumpDescriptor(temp_dir.path()),
523 NULL,
524 DoneCallbackRaiseSIGKILL,
525 NULL,
526 true,
527 -1);
528 CrashWithCallbacks(NULL, DoneCallbackReturnFalse, temp_dir.path());
529 }
530 ASSERT_NO_FATAL_FAILURE(WaitForProcessToTerminate(child, SIGKILL));
531 }
532
533 namespace {
534 const int kSimpleFirstChanceReturnStatus = 42;
SimpleFirstChanceHandler(int,siginfo_t *,void *)535 bool SimpleFirstChanceHandler(int, siginfo_t*, void*) {
536 _exit(kSimpleFirstChanceReturnStatus);
537 }
538 }
539
TEST(ExceptionHandlerTest,FirstChanceHandlerRuns)540 TEST(ExceptionHandlerTest, FirstChanceHandlerRuns) {
541 AutoTempDir temp_dir;
542
543 const pid_t child = fork();
544 if (child == 0) {
545 ExceptionHandler handler(
546 MinidumpDescriptor(temp_dir.path()), NULL, NULL, NULL, true, -1);
547 google_breakpad::SetFirstChanceExceptionHandler(SimpleFirstChanceHandler);
548 DoNullPointerDereference();
549 }
550 int status;
551 ASSERT_NE(HANDLE_EINTR(waitpid(child, &status, 0)), -1);
552 ASSERT_TRUE(WIFEXITED(status));
553 ASSERT_EQ(kSimpleFirstChanceReturnStatus, WEXITSTATUS(status));
554 }
555
556 #endif // !ADDRESS_SANITIZER
557
558 const unsigned char kIllegalInstruction[] = {
559 #if defined(__mips__)
560 // mfc2 zero,Impl - usually illegal in userspace.
561 0x48, 0x00, 0x00, 0x48
562 #else
563 // This crashes with SIGILL on x86/x86-64/arm.
564 0xff, 0xff, 0xff, 0xff
565 #endif
566 };
567
568 // Test that memory around the instruction pointer is written
569 // to the dump as a MinidumpMemoryRegion.
TEST(ExceptionHandlerTest,InstructionPointerMemory)570 TEST(ExceptionHandlerTest, InstructionPointerMemory) {
571 AutoTempDir temp_dir;
572 int fds[2];
573 ASSERT_NE(pipe(fds), -1);
574
575 // These are defined here so the parent can use them to check the
576 // data from the minidump afterwards.
577 const uint32_t kMemorySize = 256; // bytes
578 const int kOffset = kMemorySize / 2;
579
580 const pid_t child = fork();
581 if (child == 0) {
582 close(fds[0]);
583 ExceptionHandler handler(MinidumpDescriptor(temp_dir.path()), NULL,
584 DoneCallback, reinterpret_cast<void*>(fds[1]),
585 true, -1);
586 // Get some executable memory.
587 char* memory =
588 reinterpret_cast<char*>(mmap(NULL,
589 kMemorySize,
590 PROT_READ | PROT_WRITE | PROT_EXEC,
591 MAP_PRIVATE | MAP_ANON,
592 -1,
593 0));
594 if (!memory)
595 exit(0);
596
597 // Write some instructions that will crash. Put them in the middle
598 // of the block of memory, because the minidump should contain 128
599 // bytes on either side of the instruction pointer.
600 memcpy(memory + kOffset, kIllegalInstruction, sizeof(kIllegalInstruction));
601 FlushInstructionCache(memory, kMemorySize);
602
603 // Now execute the instructions, which should crash.
604 typedef void (*void_function)(void);
605 void_function memory_function =
606 reinterpret_cast<void_function>(memory + kOffset);
607 memory_function();
608 }
609 close(fds[1]);
610
611 ASSERT_NO_FATAL_FAILURE(WaitForProcessToTerminate(child, SIGILL));
612
613 string minidump_path;
614 ASSERT_NO_FATAL_FAILURE(ReadMinidumpPathFromPipe(fds[0], &minidump_path));
615
616 struct stat st;
617 ASSERT_EQ(0, stat(minidump_path.c_str(), &st));
618 ASSERT_GT(st.st_size, 0);
619
620 // Read the minidump. Locate the exception record and the
621 // memory list, and then ensure that there is a memory region
622 // in the memory list that covers the instruction pointer from
623 // the exception record.
624 Minidump minidump(minidump_path);
625 ASSERT_TRUE(minidump.Read());
626
627 MinidumpException* exception = minidump.GetException();
628 MinidumpMemoryList* memory_list = minidump.GetMemoryList();
629 ASSERT_TRUE(exception);
630 ASSERT_TRUE(memory_list);
631 ASSERT_LT(0U, memory_list->region_count());
632
633 MinidumpContext* context = exception->GetContext();
634 ASSERT_TRUE(context);
635
636 uint64_t instruction_pointer;
637 ASSERT_TRUE(context->GetInstructionPointer(&instruction_pointer));
638
639 MinidumpMemoryRegion* region =
640 memory_list->GetMemoryRegionForAddress(instruction_pointer);
641 ASSERT_TRUE(region);
642
643 EXPECT_EQ(kMemorySize, region->GetSize());
644 const uint8_t* bytes = region->GetMemory();
645 ASSERT_TRUE(bytes);
646
647 uint8_t prefix_bytes[kOffset];
648 uint8_t suffix_bytes[kMemorySize - kOffset - sizeof(kIllegalInstruction)];
649 memset(prefix_bytes, 0, sizeof(prefix_bytes));
650 memset(suffix_bytes, 0, sizeof(suffix_bytes));
651 EXPECT_TRUE(memcmp(bytes, prefix_bytes, sizeof(prefix_bytes)) == 0);
652 EXPECT_TRUE(memcmp(bytes + kOffset, kIllegalInstruction,
653 sizeof(kIllegalInstruction)) == 0);
654 EXPECT_TRUE(memcmp(bytes + kOffset + sizeof(kIllegalInstruction),
655 suffix_bytes, sizeof(suffix_bytes)) == 0);
656
657 unlink(minidump_path.c_str());
658 }
659
660 // Test that the memory region around the instruction pointer is
661 // bounded correctly on the low end.
TEST(ExceptionHandlerTest,InstructionPointerMemoryMinBound)662 TEST(ExceptionHandlerTest, InstructionPointerMemoryMinBound) {
663 AutoTempDir temp_dir;
664 int fds[2];
665 ASSERT_NE(pipe(fds), -1);
666
667 // These are defined here so the parent can use them to check the
668 // data from the minidump afterwards.
669 const uint32_t kMemorySize = 256; // bytes
670 const int kOffset = 0;
671
672 const pid_t child = fork();
673 if (child == 0) {
674 close(fds[0]);
675 ExceptionHandler handler(MinidumpDescriptor(temp_dir.path()), NULL,
676 DoneCallback, reinterpret_cast<void*>(fds[1]),
677 true, -1);
678 // Get some executable memory.
679 char* memory =
680 reinterpret_cast<char*>(mmap(NULL,
681 kMemorySize,
682 PROT_READ | PROT_WRITE | PROT_EXEC,
683 MAP_PRIVATE | MAP_ANON,
684 -1,
685 0));
686 if (!memory)
687 exit(0);
688
689 // Write some instructions that will crash. Put them in the middle
690 // of the block of memory, because the minidump should contain 128
691 // bytes on either side of the instruction pointer.
692 memcpy(memory + kOffset, kIllegalInstruction, sizeof(kIllegalInstruction));
693 FlushInstructionCache(memory, kMemorySize);
694
695 // Now execute the instructions, which should crash.
696 typedef void (*void_function)(void);
697 void_function memory_function =
698 reinterpret_cast<void_function>(memory + kOffset);
699 memory_function();
700 }
701 close(fds[1]);
702
703 ASSERT_NO_FATAL_FAILURE(WaitForProcessToTerminate(child, SIGILL));
704
705 string minidump_path;
706 ASSERT_NO_FATAL_FAILURE(ReadMinidumpPathFromPipe(fds[0], &minidump_path));
707
708 struct stat st;
709 ASSERT_EQ(0, stat(minidump_path.c_str(), &st));
710 ASSERT_GT(st.st_size, 0);
711
712 // Read the minidump. Locate the exception record and the
713 // memory list, and then ensure that there is a memory region
714 // in the memory list that covers the instruction pointer from
715 // the exception record.
716 Minidump minidump(minidump_path);
717 ASSERT_TRUE(minidump.Read());
718
719 MinidumpException* exception = minidump.GetException();
720 MinidumpMemoryList* memory_list = minidump.GetMemoryList();
721 ASSERT_TRUE(exception);
722 ASSERT_TRUE(memory_list);
723 ASSERT_LT(0U, memory_list->region_count());
724
725 MinidumpContext* context = exception->GetContext();
726 ASSERT_TRUE(context);
727
728 uint64_t instruction_pointer;
729 ASSERT_TRUE(context->GetInstructionPointer(&instruction_pointer));
730
731 MinidumpMemoryRegion* region =
732 memory_list->GetMemoryRegionForAddress(instruction_pointer);
733 ASSERT_TRUE(region);
734
735 EXPECT_EQ(kMemorySize / 2, region->GetSize());
736 const uint8_t* bytes = region->GetMemory();
737 ASSERT_TRUE(bytes);
738
739 uint8_t suffix_bytes[kMemorySize / 2 - sizeof(kIllegalInstruction)];
740 memset(suffix_bytes, 0, sizeof(suffix_bytes));
741 EXPECT_TRUE(memcmp(bytes + kOffset, kIllegalInstruction,
742 sizeof(kIllegalInstruction)) == 0);
743 EXPECT_TRUE(memcmp(bytes + kOffset + sizeof(kIllegalInstruction),
744 suffix_bytes, sizeof(suffix_bytes)) == 0);
745 unlink(minidump_path.c_str());
746 }
747
748 // Test that the memory region around the instruction pointer is
749 // bounded correctly on the high end.
TEST(ExceptionHandlerTest,InstructionPointerMemoryMaxBound)750 TEST(ExceptionHandlerTest, InstructionPointerMemoryMaxBound) {
751 AutoTempDir temp_dir;
752 int fds[2];
753 ASSERT_NE(pipe(fds), -1);
754
755 // These are defined here so the parent can use them to check the
756 // data from the minidump afterwards.
757 // Use 4k here because the OS will hand out a single page even
758 // if a smaller size is requested, and this test wants to
759 // test the upper bound of the memory range.
760 const uint32_t kMemorySize = 4096; // bytes
761 const int kOffset = kMemorySize - sizeof(kIllegalInstruction);
762
763 const pid_t child = fork();
764 if (child == 0) {
765 close(fds[0]);
766 ExceptionHandler handler(MinidumpDescriptor(temp_dir.path()), NULL,
767 DoneCallback, reinterpret_cast<void*>(fds[1]),
768 true, -1);
769 // Get some executable memory.
770 char* memory =
771 reinterpret_cast<char*>(mmap(NULL,
772 kMemorySize,
773 PROT_READ | PROT_WRITE | PROT_EXEC,
774 MAP_PRIVATE | MAP_ANON,
775 -1,
776 0));
777 if (!memory)
778 exit(0);
779
780 // Write some instructions that will crash. Put them in the middle
781 // of the block of memory, because the minidump should contain 128
782 // bytes on either side of the instruction pointer.
783 memcpy(memory + kOffset, kIllegalInstruction, sizeof(kIllegalInstruction));
784 FlushInstructionCache(memory, kMemorySize);
785
786 // Now execute the instructions, which should crash.
787 typedef void (*void_function)(void);
788 void_function memory_function =
789 reinterpret_cast<void_function>(memory + kOffset);
790 memory_function();
791 }
792 close(fds[1]);
793
794 ASSERT_NO_FATAL_FAILURE(WaitForProcessToTerminate(child, SIGILL));
795
796 string minidump_path;
797 ASSERT_NO_FATAL_FAILURE(ReadMinidumpPathFromPipe(fds[0], &minidump_path));
798
799 struct stat st;
800 ASSERT_EQ(0, stat(minidump_path.c_str(), &st));
801 ASSERT_GT(st.st_size, 0);
802
803 // Read the minidump. Locate the exception record and the memory list, and
804 // then ensure that there is a memory region in the memory list that covers
805 // the instruction pointer from the exception record.
806 Minidump minidump(minidump_path);
807 ASSERT_TRUE(minidump.Read());
808
809 MinidumpException* exception = minidump.GetException();
810 MinidumpMemoryList* memory_list = minidump.GetMemoryList();
811 ASSERT_TRUE(exception);
812 ASSERT_TRUE(memory_list);
813 ASSERT_LT(0U, memory_list->region_count());
814
815 MinidumpContext* context = exception->GetContext();
816 ASSERT_TRUE(context);
817
818 uint64_t instruction_pointer;
819 ASSERT_TRUE(context->GetInstructionPointer(&instruction_pointer));
820
821 MinidumpMemoryRegion* region =
822 memory_list->GetMemoryRegionForAddress(instruction_pointer);
823 ASSERT_TRUE(region);
824
825 const size_t kPrefixSize = 128; // bytes
826 EXPECT_EQ(kPrefixSize + sizeof(kIllegalInstruction), region->GetSize());
827 const uint8_t* bytes = region->GetMemory();
828 ASSERT_TRUE(bytes);
829
830 uint8_t prefix_bytes[kPrefixSize];
831 memset(prefix_bytes, 0, sizeof(prefix_bytes));
832 EXPECT_TRUE(memcmp(bytes, prefix_bytes, sizeof(prefix_bytes)) == 0);
833 EXPECT_TRUE(memcmp(bytes + kPrefixSize,
834 kIllegalInstruction, sizeof(kIllegalInstruction)) == 0);
835
836 unlink(minidump_path.c_str());
837 }
838
839 #ifndef ADDRESS_SANITIZER
840
841 // Ensure that an extra memory block doesn't get added when the instruction
842 // pointer is not in mapped memory.
TEST(ExceptionHandlerTest,InstructionPointerMemoryNullPointer)843 TEST(ExceptionHandlerTest, InstructionPointerMemoryNullPointer) {
844 AutoTempDir temp_dir;
845 int fds[2];
846 ASSERT_NE(pipe(fds), -1);
847
848 const pid_t child = fork();
849 if (child == 0) {
850 close(fds[0]);
851 ExceptionHandler handler(MinidumpDescriptor(temp_dir.path()), NULL,
852 DoneCallback, reinterpret_cast<void*>(fds[1]),
853 true, -1);
854 // Try calling a NULL pointer.
855 typedef void (*void_function)(void);
856 // Volatile markings are needed to keep Clang from generating invalid
857 // opcodes. See http://crbug.com/498354 for details.
858 volatile void_function memory_function =
859 reinterpret_cast<void_function>(NULL);
860 memory_function();
861 // not reached
862 exit(1);
863 }
864 close(fds[1]);
865
866 ASSERT_NO_FATAL_FAILURE(WaitForProcessToTerminate(child, SIGSEGV));
867
868 string minidump_path;
869 ASSERT_NO_FATAL_FAILURE(ReadMinidumpPathFromPipe(fds[0], &minidump_path));
870
871 struct stat st;
872 ASSERT_EQ(0, stat(minidump_path.c_str(), &st));
873 ASSERT_GT(st.st_size, 0);
874
875 // Read the minidump. Locate the exception record and the
876 // memory list, and then ensure that there is no memory region
877 // in the memory list that covers the instruction pointer from
878 // the exception record.
879 Minidump minidump(minidump_path);
880 ASSERT_TRUE(minidump.Read());
881
882 MinidumpException* exception = minidump.GetException();
883 ASSERT_TRUE(exception);
884
885 MinidumpContext* exception_context = exception->GetContext();
886 ASSERT_TRUE(exception_context);
887
888 uint64_t instruction_pointer;
889 ASSERT_TRUE(exception_context->GetInstructionPointer(&instruction_pointer));
890 EXPECT_EQ(instruction_pointer, 0u);
891
892 MinidumpMemoryList* memory_list = minidump.GetMemoryList();
893 ASSERT_TRUE(memory_list);
894
895 unsigned int region_count = memory_list->region_count();
896 ASSERT_GE(region_count, 1u);
897
898 for (unsigned int region_index = 0;
899 region_index < region_count;
900 ++region_index) {
901 MinidumpMemoryRegion* region =
902 memory_list->GetMemoryRegionAtIndex(region_index);
903 uint64_t region_base = region->GetBase();
904 EXPECT_FALSE(instruction_pointer >= region_base &&
905 instruction_pointer < region_base + region->GetSize());
906 }
907
908 unlink(minidump_path.c_str());
909 }
910
911 #endif // !ADDRESS_SANITIZER
912
913 // Test that anonymous memory maps can be annotated with names and IDs.
TEST(ExceptionHandlerTest,ModuleInfo)914 TEST(ExceptionHandlerTest, ModuleInfo) {
915 // These are defined here so the parent can use them to check the
916 // data from the minidump afterwards.
917 const uint32_t kMemorySize = sysconf(_SC_PAGESIZE);
918 const char* kMemoryName = "a fake module";
919 const uint8_t kModuleGUID[sizeof(MDGUID)] = {
920 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77,
921 0x88, 0x99, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF
922 };
923 const string module_identifier = "33221100554477668899AABBCCDDEEFF0";
924
925 // Get some memory.
926 char* memory =
927 reinterpret_cast<char*>(mmap(NULL,
928 kMemorySize,
929 PROT_READ | PROT_WRITE,
930 MAP_PRIVATE | MAP_ANON,
931 -1,
932 0));
933 const uintptr_t kMemoryAddress = reinterpret_cast<uintptr_t>(memory);
934 ASSERT_TRUE(memory);
935
936 AutoTempDir temp_dir;
937 ExceptionHandler handler(
938 MinidumpDescriptor(temp_dir.path()), NULL, NULL, NULL, true, -1);
939
940 // Add info about the anonymous memory mapping.
941 handler.AddMappingInfo(kMemoryName,
942 kModuleGUID,
943 kMemoryAddress,
944 kMemorySize,
945 0);
946 ASSERT_TRUE(handler.WriteMinidump());
947
948 const MinidumpDescriptor& minidump_desc = handler.minidump_descriptor();
949 // Read the minidump. Load the module list, and ensure that the mmap'ed
950 // |memory| is listed with the given module name and debug ID.
951 Minidump minidump(minidump_desc.path());
952 ASSERT_TRUE(minidump.Read());
953
954 MinidumpModuleList* module_list = minidump.GetModuleList();
955 ASSERT_TRUE(module_list);
956 const MinidumpModule* module =
957 module_list->GetModuleForAddress(kMemoryAddress);
958 ASSERT_TRUE(module);
959
960 EXPECT_EQ(kMemoryAddress, module->base_address());
961 EXPECT_EQ(kMemorySize, module->size());
962 EXPECT_EQ(kMemoryName, module->code_file());
963 EXPECT_EQ(module_identifier, module->debug_identifier());
964
965 unlink(minidump_desc.path());
966 }
967
968 #ifndef ADDRESS_SANITIZER
969
970 static const unsigned kControlMsgSize =
971 CMSG_SPACE(sizeof(int)) + CMSG_SPACE(sizeof(struct ucred));
972
973 static bool
CrashHandler(const void * crash_context,size_t crash_context_size,void * context)974 CrashHandler(const void* crash_context, size_t crash_context_size,
975 void* context) {
976 const int fd = (intptr_t) context;
977 int fds[2];
978 if (pipe(fds) == -1) {
979 // There doesn't seem to be any way to reliably handle
980 // this failure without the parent process hanging
981 // At least make sure that this process doesn't access
982 // unexpected file descriptors
983 fds[0] = -1;
984 fds[1] = -1;
985 }
986 struct kernel_msghdr msg = {0};
987 struct kernel_iovec iov;
988 iov.iov_base = const_cast<void*>(crash_context);
989 iov.iov_len = crash_context_size;
990 msg.msg_iov = &iov;
991 msg.msg_iovlen = 1;
992 char cmsg[kControlMsgSize];
993 memset(cmsg, 0, kControlMsgSize);
994 msg.msg_control = cmsg;
995 msg.msg_controllen = sizeof(cmsg);
996
997 struct cmsghdr *hdr = CMSG_FIRSTHDR(&msg);
998 hdr->cmsg_level = SOL_SOCKET;
999 hdr->cmsg_type = SCM_RIGHTS;
1000 hdr->cmsg_len = CMSG_LEN(sizeof(int));
1001 *((int*) CMSG_DATA(hdr)) = fds[1];
1002 hdr = CMSG_NXTHDR((struct msghdr*) &msg, hdr);
1003 hdr->cmsg_level = SOL_SOCKET;
1004 hdr->cmsg_type = SCM_CREDENTIALS;
1005 hdr->cmsg_len = CMSG_LEN(sizeof(struct ucred));
1006 struct ucred *cred = reinterpret_cast<struct ucred*>(CMSG_DATA(hdr));
1007 cred->uid = getuid();
1008 cred->gid = getgid();
1009 cred->pid = getpid();
1010
1011 ssize_t ret = HANDLE_EINTR(sys_sendmsg(fd, &msg, 0));
1012 sys_close(fds[1]);
1013 if (ret <= 0)
1014 return false;
1015
1016 char b;
1017 IGNORE_RET(HANDLE_EINTR(sys_read(fds[0], &b, 1)));
1018
1019 return true;
1020 }
1021
TEST(ExceptionHandlerTest,ExternalDumper)1022 TEST(ExceptionHandlerTest, ExternalDumper) {
1023 int fds[2];
1024 ASSERT_NE(socketpair(AF_UNIX, SOCK_DGRAM, 0, fds), -1);
1025 static const int on = 1;
1026 setsockopt(fds[0], SOL_SOCKET, SO_PASSCRED, &on, sizeof(on));
1027 setsockopt(fds[1], SOL_SOCKET, SO_PASSCRED, &on, sizeof(on));
1028
1029 const pid_t child = fork();
1030 if (child == 0) {
1031 close(fds[0]);
1032 ExceptionHandler handler(MinidumpDescriptor("/tmp1"), NULL, NULL,
1033 reinterpret_cast<void*>(fds[1]), true, -1);
1034 handler.set_crash_handler(CrashHandler);
1035 DoNullPointerDereference();
1036 }
1037 close(fds[1]);
1038 struct msghdr msg = {0};
1039 struct iovec iov;
1040 static const unsigned kCrashContextSize =
1041 sizeof(ExceptionHandler::CrashContext);
1042 char context[kCrashContextSize];
1043 char control[kControlMsgSize];
1044 iov.iov_base = context;
1045 iov.iov_len = kCrashContextSize;
1046 msg.msg_iov = &iov;
1047 msg.msg_iovlen = 1;
1048 msg.msg_control = control;
1049 msg.msg_controllen = kControlMsgSize;
1050
1051 const ssize_t n = HANDLE_EINTR(recvmsg(fds[0], &msg, 0));
1052 ASSERT_EQ(static_cast<ssize_t>(kCrashContextSize), n);
1053 ASSERT_EQ(kControlMsgSize, msg.msg_controllen);
1054 ASSERT_EQ(static_cast<__typeof__(msg.msg_flags)>(0), msg.msg_flags);
1055 ASSERT_EQ(0, close(fds[0]));
1056
1057 pid_t crashing_pid = -1;
1058 int signal_fd = -1;
1059 for (struct cmsghdr *hdr = CMSG_FIRSTHDR(&msg); hdr;
1060 hdr = CMSG_NXTHDR(&msg, hdr)) {
1061 if (hdr->cmsg_level != SOL_SOCKET)
1062 continue;
1063 if (hdr->cmsg_type == SCM_RIGHTS) {
1064 const unsigned len = hdr->cmsg_len -
1065 (((uint8_t*)CMSG_DATA(hdr)) - (uint8_t*)hdr);
1066 ASSERT_EQ(sizeof(int), len);
1067 signal_fd = *(reinterpret_cast<int*>(CMSG_DATA(hdr)));
1068 } else if (hdr->cmsg_type == SCM_CREDENTIALS) {
1069 const struct ucred *cred =
1070 reinterpret_cast<struct ucred*>(CMSG_DATA(hdr));
1071 crashing_pid = cred->pid;
1072 }
1073 }
1074
1075 ASSERT_NE(crashing_pid, -1);
1076 ASSERT_NE(signal_fd, -1);
1077
1078 AutoTempDir temp_dir;
1079 string templ = temp_dir.path() + "/exception-handler-unittest";
1080 ASSERT_TRUE(WriteMinidump(templ.c_str(), crashing_pid, context,
1081 kCrashContextSize));
1082 static const char b = 0;
1083 ASSERT_EQ(1, (HANDLE_EINTR(write(signal_fd, &b, 1))));
1084 ASSERT_EQ(0, close(signal_fd));
1085
1086 ASSERT_NO_FATAL_FAILURE(WaitForProcessToTerminate(child, SIGSEGV));
1087
1088 struct stat st;
1089 ASSERT_EQ(0, stat(templ.c_str(), &st));
1090 ASSERT_GT(st.st_size, 0);
1091 unlink(templ.c_str());
1092 }
1093
1094 #endif // !ADDRESS_SANITIZER
1095
TEST(ExceptionHandlerTest,WriteMinidumpExceptionStream)1096 TEST(ExceptionHandlerTest, WriteMinidumpExceptionStream) {
1097 AutoTempDir temp_dir;
1098 ExceptionHandler handler(MinidumpDescriptor(temp_dir.path()), NULL, NULL,
1099 NULL, false, -1);
1100 ASSERT_TRUE(handler.WriteMinidump());
1101
1102 string minidump_path = handler.minidump_descriptor().path();
1103
1104 // Read the minidump and check the exception stream.
1105 Minidump minidump(minidump_path);
1106 ASSERT_TRUE(minidump.Read());
1107 MinidumpException* exception = minidump.GetException();
1108 ASSERT_TRUE(exception);
1109 const MDRawExceptionStream* raw = exception->exception();
1110 ASSERT_TRUE(raw);
1111 EXPECT_EQ(MD_EXCEPTION_CODE_LIN_DUMP_REQUESTED,
1112 raw->exception_record.exception_code);
1113 }
1114
TEST(ExceptionHandlerTest,GenerateMultipleDumpsWithFD)1115 TEST(ExceptionHandlerTest, GenerateMultipleDumpsWithFD) {
1116 AutoTempDir temp_dir;
1117 string path;
1118 const int fd = CreateTMPFile(temp_dir.path(), &path);
1119 ExceptionHandler handler(MinidumpDescriptor(fd), NULL, NULL, NULL, false, -1);
1120 ASSERT_TRUE(handler.WriteMinidump());
1121 // Check by the size of the data written to the FD that a minidump was
1122 // generated.
1123 off_t size = lseek(fd, 0, SEEK_CUR);
1124 ASSERT_GT(size, 0);
1125
1126 // Generate another minidump.
1127 ASSERT_TRUE(handler.WriteMinidump());
1128 size = lseek(fd, 0, SEEK_CUR);
1129 ASSERT_GT(size, 0);
1130 }
1131
TEST(ExceptionHandlerTest,GenerateMultipleDumpsWithPath)1132 TEST(ExceptionHandlerTest, GenerateMultipleDumpsWithPath) {
1133 AutoTempDir temp_dir;
1134 ExceptionHandler handler(MinidumpDescriptor(temp_dir.path()), NULL, NULL,
1135 NULL, false, -1);
1136 ASSERT_TRUE(handler.WriteMinidump());
1137
1138 const MinidumpDescriptor& minidump_1 = handler.minidump_descriptor();
1139 struct stat st;
1140 ASSERT_EQ(0, stat(minidump_1.path(), &st));
1141 ASSERT_GT(st.st_size, 0);
1142 string minidump_1_path(minidump_1.path());
1143 // Check it is a valid minidump.
1144 Minidump minidump1(minidump_1_path);
1145 ASSERT_TRUE(minidump1.Read());
1146 unlink(minidump_1.path());
1147
1148 // Generate another minidump, it should go to a different file.
1149 ASSERT_TRUE(handler.WriteMinidump());
1150 const MinidumpDescriptor& minidump_2 = handler.minidump_descriptor();
1151 ASSERT_EQ(0, stat(minidump_2.path(), &st));
1152 ASSERT_GT(st.st_size, 0);
1153 string minidump_2_path(minidump_2.path());
1154 // Check it is a valid minidump.
1155 Minidump minidump2(minidump_2_path);
1156 ASSERT_TRUE(minidump2.Read());
1157 unlink(minidump_2.path());
1158
1159 // 2 distinct files should be produced.
1160 ASSERT_STRNE(minidump_1_path.c_str(), minidump_2_path.c_str());
1161 }
1162
1163 // Test that an additional memory region can be added to the minidump.
TEST(ExceptionHandlerTest,AdditionalMemory)1164 TEST(ExceptionHandlerTest, AdditionalMemory) {
1165 const uint32_t kMemorySize = sysconf(_SC_PAGESIZE);
1166
1167 // Get some heap memory.
1168 uint8_t* memory = new uint8_t[kMemorySize];
1169 const uintptr_t kMemoryAddress = reinterpret_cast<uintptr_t>(memory);
1170 ASSERT_TRUE(memory);
1171
1172 // Stick some data into the memory so the contents can be verified.
1173 for (uint32_t i = 0; i < kMemorySize; ++i) {
1174 memory[i] = i % 255;
1175 }
1176
1177 AutoTempDir temp_dir;
1178 ExceptionHandler handler(
1179 MinidumpDescriptor(temp_dir.path()), NULL, NULL, NULL, true, -1);
1180
1181 // Add the memory region to the list of memory to be included.
1182 handler.RegisterAppMemory(memory, kMemorySize);
1183 handler.WriteMinidump();
1184
1185 const MinidumpDescriptor& minidump_desc = handler.minidump_descriptor();
1186
1187 // Read the minidump. Ensure that the memory region is present
1188 Minidump minidump(minidump_desc.path());
1189 ASSERT_TRUE(minidump.Read());
1190
1191 MinidumpMemoryList* dump_memory_list = minidump.GetMemoryList();
1192 ASSERT_TRUE(dump_memory_list);
1193 const MinidumpMemoryRegion* region =
1194 dump_memory_list->GetMemoryRegionForAddress(kMemoryAddress);
1195 ASSERT_TRUE(region);
1196
1197 EXPECT_EQ(kMemoryAddress, region->GetBase());
1198 EXPECT_EQ(kMemorySize, region->GetSize());
1199
1200 // Verify memory contents.
1201 EXPECT_EQ(0, memcmp(region->GetMemory(), memory, kMemorySize));
1202
1203 delete[] memory;
1204 }
1205
1206 // Test that a memory region that was previously registered
1207 // can be unregistered.
TEST(ExceptionHandlerTest,AdditionalMemoryRemove)1208 TEST(ExceptionHandlerTest, AdditionalMemoryRemove) {
1209 const uint32_t kMemorySize = sysconf(_SC_PAGESIZE);
1210
1211 // Get some heap memory.
1212 uint8_t* memory = new uint8_t[kMemorySize];
1213 const uintptr_t kMemoryAddress = reinterpret_cast<uintptr_t>(memory);
1214 ASSERT_TRUE(memory);
1215
1216 AutoTempDir temp_dir;
1217 ExceptionHandler handler(
1218 MinidumpDescriptor(temp_dir.path()), NULL, NULL, NULL, true, -1);
1219
1220 // Add the memory region to the list of memory to be included.
1221 handler.RegisterAppMemory(memory, kMemorySize);
1222
1223 // ...and then remove it
1224 handler.UnregisterAppMemory(memory);
1225 handler.WriteMinidump();
1226
1227 const MinidumpDescriptor& minidump_desc = handler.minidump_descriptor();
1228
1229 // Read the minidump. Ensure that the memory region is not present.
1230 Minidump minidump(minidump_desc.path());
1231 ASSERT_TRUE(minidump.Read());
1232
1233 MinidumpMemoryList* dump_memory_list = minidump.GetMemoryList();
1234 ASSERT_TRUE(dump_memory_list);
1235 const MinidumpMemoryRegion* region =
1236 dump_memory_list->GetMemoryRegionForAddress(kMemoryAddress);
1237 EXPECT_FALSE(region);
1238
1239 delete[] memory;
1240 }
1241
SimpleCallback(const MinidumpDescriptor & descriptor,void * context,bool succeeded)1242 static bool SimpleCallback(const MinidumpDescriptor& descriptor,
1243 void* context,
1244 bool succeeded) {
1245 string* filename = reinterpret_cast<string*>(context);
1246 *filename = descriptor.path();
1247 return true;
1248 }
1249
TEST(ExceptionHandlerTest,WriteMinidumpForChild)1250 TEST(ExceptionHandlerTest, WriteMinidumpForChild) {
1251 int fds[2];
1252 ASSERT_NE(-1, pipe(fds));
1253
1254 const pid_t child = fork();
1255 if (child == 0) {
1256 close(fds[1]);
1257 char b;
1258 HANDLE_EINTR(read(fds[0], &b, sizeof(b)));
1259 close(fds[0]);
1260 syscall(__NR_exit);
1261 }
1262 close(fds[0]);
1263
1264 AutoTempDir temp_dir;
1265 string minidump_filename;
1266 ASSERT_TRUE(
1267 ExceptionHandler::WriteMinidumpForChild(child, child,
1268 temp_dir.path(), SimpleCallback,
1269 (void*)&minidump_filename));
1270
1271 Minidump minidump(minidump_filename);
1272 ASSERT_TRUE(minidump.Read());
1273 // Check that the crashing thread is the main thread of |child|
1274 MinidumpException* exception = minidump.GetException();
1275 ASSERT_TRUE(exception);
1276 uint32_t thread_id;
1277 ASSERT_TRUE(exception->GetThreadID(&thread_id));
1278 EXPECT_EQ(child, static_cast<int32_t>(thread_id));
1279
1280 const MDRawExceptionStream* raw = exception->exception();
1281 ASSERT_TRUE(raw);
1282 EXPECT_EQ(MD_EXCEPTION_CODE_LIN_DUMP_REQUESTED,
1283 raw->exception_record.exception_code);
1284
1285 close(fds[1]);
1286 unlink(minidump_filename.c_str());
1287 }
1288