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