xref: /aosp_15_r20/external/google-breakpad/src/client/linux/minidump_writer/minidump_writer_unittest.cc (revision 9712c20fc9bbfbac4935993a2ca0b3958c5adad2)
1 // Copyright 2011 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 <fcntl.h>
34 #include <poll.h>
35 #include <sys/stat.h>
36 #include <sys/syscall.h>
37 #include <sys/types.h>
38 #include <ucontext.h>
39 #include <unistd.h>
40 
41 #include <string>
42 
43 #include "breakpad_googletest_includes.h"
44 #include "client/linux/handler/exception_handler.h"
45 #include "client/linux/minidump_writer/linux_dumper.h"
46 #include "client/linux/minidump_writer/minidump_writer.h"
47 #include "client/linux/minidump_writer/minidump_writer_unittest_utils.h"
48 #include "common/linux/breakpad_getcontext.h"
49 #include "common/linux/eintr_wrapper.h"
50 #include "common/linux/file_id.h"
51 #include "common/linux/ignore_ret.h"
52 #include "common/linux/safe_readlink.h"
53 #include "common/scoped_ptr.h"
54 #include "common/tests/auto_tempdir.h"
55 #include "common/tests/file_utils.h"
56 #include "common/using_std_string.h"
57 #include "google_breakpad/processor/minidump.h"
58 
59 using namespace google_breakpad;
60 using google_breakpad::elf::FileID;
61 using google_breakpad::elf::kDefaultBuildIdSize;
62 
63 namespace {
64 
65 typedef testing::Test MinidumpWriterTest;
66 
67 const char kMDWriterUnitTestFileName[] = "/minidump-writer-unittest";
68 
TEST(MinidumpWriterTest,SetupWithPath)69 TEST(MinidumpWriterTest, SetupWithPath) {
70   int fds[2];
71   ASSERT_NE(-1, pipe(fds));
72 
73   const pid_t child = fork();
74   if (child == 0) {
75     close(fds[1]);
76     char b;
77     IGNORE_RET(HANDLE_EINTR(read(fds[0], &b, sizeof(b))));
78     close(fds[0]);
79     syscall(__NR_exit_group);
80   }
81   close(fds[0]);
82 
83   ExceptionHandler::CrashContext context;
84   memset(&context, 0, sizeof(context));
85 
86   AutoTempDir temp_dir;
87   string templ = temp_dir.path() + kMDWriterUnitTestFileName;
88   // Set a non-zero tid to avoid tripping asserts.
89   context.tid = child;
90   ASSERT_TRUE(WriteMinidump(templ.c_str(), child, &context, sizeof(context)));
91   struct stat st;
92   ASSERT_EQ(0, stat(templ.c_str(), &st));
93   ASSERT_GT(st.st_size, 0);
94 
95   close(fds[1]);
96   IGNORE_EINTR(waitpid(child, nullptr, 0));
97 }
98 
TEST(MinidumpWriterTest,SetupWithFD)99 TEST(MinidumpWriterTest, SetupWithFD) {
100   int fds[2];
101   ASSERT_NE(-1, pipe(fds));
102 
103   const pid_t child = fork();
104   if (child == 0) {
105     close(fds[1]);
106     char b;
107     HANDLE_EINTR(read(fds[0], &b, sizeof(b)));
108     close(fds[0]);
109     syscall(__NR_exit_group);
110   }
111   close(fds[0]);
112 
113   ExceptionHandler::CrashContext context;
114   memset(&context, 0, sizeof(context));
115 
116   AutoTempDir temp_dir;
117   string templ = temp_dir.path() + kMDWriterUnitTestFileName;
118   int fd = open(templ.c_str(), O_CREAT | O_WRONLY, S_IRWXU);
119   // Set a non-zero tid to avoid tripping asserts.
120   context.tid = child;
121   ASSERT_TRUE(WriteMinidump(fd, child, &context, sizeof(context)));
122   struct stat st;
123   ASSERT_EQ(0, stat(templ.c_str(), &st));
124   ASSERT_GT(st.st_size, 0);
125 
126   close(fds[1]);
127   IGNORE_EINTR(waitpid(child, nullptr, 0));
128 }
129 
130 // Test that mapping info can be specified when writing a minidump,
131 // and that it ends up in the module list of the minidump.
TEST(MinidumpWriterTest,MappingInfo)132 TEST(MinidumpWriterTest, MappingInfo) {
133   int fds[2];
134   ASSERT_NE(-1, pipe(fds));
135 
136   // These are defined here so the parent can use them to check the
137   // data from the minidump afterwards.
138   const uint32_t memory_size = sysconf(_SC_PAGESIZE);
139   const char* kMemoryName = "a fake module";
140   const uint8_t kModuleGUID[sizeof(MDGUID)] = {
141     0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77,
142     0x88, 0x99, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF
143   };
144   const string module_identifier = "33221100554477668899AABBCCDDEEFF0";
145 
146   // Get some memory.
147   char* memory =
148     reinterpret_cast<char*>(mmap(NULL,
149                                  memory_size,
150                                  PROT_READ | PROT_WRITE,
151                                  MAP_PRIVATE | MAP_ANON,
152                                  -1,
153                                  0));
154   const uintptr_t kMemoryAddress = reinterpret_cast<uintptr_t>(memory);
155   ASSERT_TRUE(memory);
156 
157   const pid_t child = fork();
158   if (child == 0) {
159     close(fds[1]);
160     char b;
161     IGNORE_RET(HANDLE_EINTR(read(fds[0], &b, sizeof(b))));
162     close(fds[0]);
163     syscall(__NR_exit_group);
164   }
165   close(fds[0]);
166 
167   ExceptionHandler::CrashContext context;
168   memset(&context, 0, sizeof(context));
169   ASSERT_EQ(0, getcontext(&context.context));
170   context.tid = child;
171 
172   AutoTempDir temp_dir;
173   string templ = temp_dir.path() + kMDWriterUnitTestFileName;
174 
175   // Add information about the mapped memory.
176   MappingInfo info;
177   info.start_addr = kMemoryAddress;
178   info.size = memory_size;
179   info.offset = 0;
180   info.exec = false;
181   strcpy(info.name, kMemoryName);
182 
183   MappingList mappings;
184   AppMemoryList memory_list;
185   MappingEntry mapping;
186   mapping.first = info;
187   memcpy(mapping.second, kModuleGUID, sizeof(MDGUID));
188   mappings.push_back(mapping);
189   ASSERT_TRUE(WriteMinidump(templ.c_str(), child, &context, sizeof(context),
190                             mappings, memory_list, false, 0, false));
191 
192   // Read the minidump. Load the module list, and ensure that
193   // the mmap'ed |memory| is listed with the given module name
194   // and debug ID.
195   Minidump minidump(templ);
196   ASSERT_TRUE(minidump.Read());
197 
198   MinidumpModuleList* module_list = minidump.GetModuleList();
199   ASSERT_TRUE(module_list);
200   const MinidumpModule* module =
201     module_list->GetModuleForAddress(kMemoryAddress);
202   ASSERT_TRUE(module);
203 
204   EXPECT_EQ(kMemoryAddress, module->base_address());
205   EXPECT_EQ(memory_size, module->size());
206   EXPECT_EQ(kMemoryName, module->code_file());
207   EXPECT_EQ(module_identifier, module->debug_identifier());
208 
209   uint32_t len;
210   // These streams are expected to be there
211   EXPECT_TRUE(minidump.SeekToStreamType(MD_THREAD_LIST_STREAM, &len));
212   EXPECT_TRUE(minidump.SeekToStreamType(MD_MEMORY_LIST_STREAM, &len));
213   EXPECT_TRUE(minidump.SeekToStreamType(MD_EXCEPTION_STREAM, &len));
214   EXPECT_TRUE(minidump.SeekToStreamType(MD_SYSTEM_INFO_STREAM, &len));
215   EXPECT_TRUE(minidump.SeekToStreamType(MD_LINUX_CPU_INFO, &len));
216   EXPECT_TRUE(minidump.SeekToStreamType(MD_LINUX_PROC_STATUS, &len));
217   EXPECT_TRUE(minidump.SeekToStreamType(MD_LINUX_CMD_LINE, &len));
218   EXPECT_TRUE(minidump.SeekToStreamType(MD_LINUX_ENVIRON, &len));
219   EXPECT_TRUE(minidump.SeekToStreamType(MD_LINUX_AUXV, &len));
220   EXPECT_TRUE(minidump.SeekToStreamType(MD_LINUX_MAPS, &len));
221   EXPECT_TRUE(minidump.SeekToStreamType(MD_LINUX_DSO_DEBUG, &len));
222 
223   close(fds[1]);
224   IGNORE_EINTR(waitpid(child, nullptr, 0));
225 }
226 
227 // Test that minidumping is skipped while writing minidumps if principal mapping
228 // is not referenced.
TEST(MinidumpWriterTest,MinidumpSkippedIfRequested)229 TEST(MinidumpWriterTest, MinidumpSkippedIfRequested) {
230   int fds[2];
231   ASSERT_NE(-1, pipe(fds));
232 
233   const pid_t child = fork();
234   if (child == 0) {
235     close(fds[1]);
236     char b;
237     IGNORE_RET(HANDLE_EINTR(read(fds[0], &b, sizeof(b))));
238     close(fds[0]);
239     syscall(__NR_exit_group);
240   }
241   close(fds[0]);
242 
243   ExceptionHandler::CrashContext context;
244   memset(&context, 0, sizeof(context));
245   ASSERT_EQ(0, getcontext(&context.context));
246   context.tid = child;
247 
248   AutoTempDir temp_dir;
249   string templ = temp_dir.path() + kMDWriterUnitTestFileName;
250 
251   // pass an invalid principal mapping address, which will force
252   // WriteMinidump to not write a minidump.
253   ASSERT_FALSE(WriteMinidump(templ.c_str(), child, &context, sizeof(context),
254                             true, static_cast<uintptr_t>(0x0102030405060708ull),
255                             false));
256   close(fds[1]);
257   IGNORE_EINTR(waitpid(child, nullptr, 0));
258 }
259 
260 // Test that minidumping is skipped while writing minidumps if principal mapping
261 // is not referenced.
TEST(MinidumpWriterTest,MinidumpStacksSkippedIfRequested)262 TEST(MinidumpWriterTest, MinidumpStacksSkippedIfRequested) {
263   int fds[2];
264   ASSERT_NE(-1, pipe(fds));
265 
266   const pid_t child = fork();
267   if (child == 0) {
268     close(fds[1]);
269 
270     // Create a thread that does not return, and only references libc (not the
271     // current executable). This thread should not be captured in the minidump.
272     pthread_t thread;
273     pthread_attr_t thread_attributes;
274     pthread_attr_init(&thread_attributes);
275     pthread_attr_setdetachstate(&thread_attributes, PTHREAD_CREATE_DETACHED);
276     sigset_t sigset;
277     sigemptyset(&sigset);
278     pthread_create(&thread, &thread_attributes,
279                    reinterpret_cast<void* (*)(void*)>(&sigsuspend), &sigset);
280 
281     char b;
282     IGNORE_RET(HANDLE_EINTR(read(fds[0], &b, sizeof(b))));
283     close(fds[0]);
284     syscall(__NR_exit_group);
285   }
286   close(fds[0]);
287 
288   ExceptionHandler::CrashContext context;
289   memset(&context, 0, sizeof(context));
290   ASSERT_EQ(0, getcontext(&context.context));
291   context.tid = child;
292 
293   AutoTempDir temp_dir;
294   string templ = temp_dir.path() + kMDWriterUnitTestFileName;
295 
296   // Pass an invalid principal mapping address, which will force
297   // WriteMinidump to not dump any thread stacks.
298   ASSERT_TRUE(WriteMinidump(
299       templ.c_str(), child, &context, sizeof(context), true,
300       reinterpret_cast<uintptr_t>(google_breakpad::WriteFile), false));
301 
302   // Read the minidump. And ensure that thread memory was dumped only for the
303   // main thread.
304   Minidump minidump(templ);
305   ASSERT_TRUE(minidump.Read());
306 
307   MinidumpThreadList* threads = minidump.GetThreadList();
308   int threads_with_stacks = 0;
309   for (unsigned int i = 0; i < threads->thread_count(); ++i) {
310     MinidumpThread* thread = threads->GetThreadAtIndex(i);
311     if (thread->GetMemory()) {
312       ++threads_with_stacks;
313     }
314   }
315 #if defined(THREAD_SANITIZER) || defined(ADDRESS_SANITIZER)
316   ASSERT_GE(threads_with_stacks, 1);
317 #else
318   ASSERT_EQ(threads_with_stacks, 1);
319 #endif
320   close(fds[1]);
321   IGNORE_EINTR(waitpid(child, nullptr, 0));
322 }
323 
324 // Test that stacks can be sanitized while writing minidumps.
TEST(MinidumpWriterTest,StacksAreSanitizedIfRequested)325 TEST(MinidumpWriterTest, StacksAreSanitizedIfRequested) {
326   int fds[2];
327   ASSERT_NE(-1, pipe(fds));
328 
329   const pid_t child = fork();
330   if (child == 0) {
331     close(fds[1]);
332     char b;
333     IGNORE_RET(HANDLE_EINTR(read(fds[0], &b, sizeof(b))));
334     close(fds[0]);
335     syscall(__NR_exit_group);
336   }
337   close(fds[0]);
338 
339   ExceptionHandler::CrashContext context;
340   memset(&context, 0, sizeof(context));
341   ASSERT_EQ(0, getcontext(&context.context));
342   context.tid = child;
343 
344   AutoTempDir temp_dir;
345   string templ = temp_dir.path() + kMDWriterUnitTestFileName;
346   // pass an invalid principal mapping address, which will force
347   // WriteMinidump to not dump any thread stacks.
348   ASSERT_TRUE(WriteMinidump(templ.c_str(), child, &context, sizeof(context),
349                             false, 0, true));
350 
351   // Read the minidump. And ensure that thread memory contains a defaced value.
352   Minidump minidump(templ);
353   ASSERT_TRUE(minidump.Read());
354 
355   const uintptr_t defaced =
356 #if defined(__LP64__)
357       0x0defaced0defaced;
358 #else
359       0x0defaced;
360 #endif
361   MinidumpThreadList* threads = minidump.GetThreadList();
362   for (unsigned int i = 0; i < threads->thread_count(); ++i) {
363     MinidumpThread* thread = threads->GetThreadAtIndex(i);
364     MinidumpMemoryRegion* mem = thread->GetMemory();
365     ASSERT_TRUE(mem != nullptr);
366     uint32_t sz = mem->GetSize();
367     const uint8_t* data = mem->GetMemory();
368     ASSERT_TRUE(memmem(data, sz, &defaced, sizeof(defaced)) != nullptr);
369   }
370   close(fds[1]);
371   IGNORE_EINTR(waitpid(child, nullptr, 0));
372 }
373 
374 // Test that a binary with a longer-than-usual build id note
375 // makes its way all the way through to the minidump unscathed.
376 // The linux_client_unittest is linked with an explicit --build-id
377 // in Makefile.am.
TEST(MinidumpWriterTest,BuildIDLong)378 TEST(MinidumpWriterTest, BuildIDLong) {
379   int fds[2];
380   ASSERT_NE(-1, pipe(fds));
381 
382   const pid_t child = fork();
383   if (child == 0) {
384     close(fds[1]);
385     char b;
386     IGNORE_RET(HANDLE_EINTR(read(fds[0], &b, sizeof(b))));
387     close(fds[0]);
388     syscall(__NR_exit_group);
389   }
390   close(fds[0]);
391 
392   ExceptionHandler::CrashContext context;
393   memset(&context, 0, sizeof(context));
394   ASSERT_EQ(0, getcontext(&context.context));
395   context.tid = child;
396 
397   AutoTempDir temp_dir;
398   const string dump_path = temp_dir.path() + kMDWriterUnitTestFileName;
399 
400   EXPECT_TRUE(WriteMinidump(dump_path.c_str(),
401                             child, &context, sizeof(context)));
402   close(fds[1]);
403 
404   // Read the minidump. Load the module list, and ensure that
405   // the main module has the correct debug id and code id.
406   Minidump minidump(dump_path);
407   ASSERT_TRUE(minidump.Read());
408 
409   MinidumpModuleList* module_list = minidump.GetModuleList();
410   ASSERT_TRUE(module_list);
411   const MinidumpModule* module = module_list->GetMainModule();
412   ASSERT_TRUE(module);
413   const string module_identifier = "030201000504070608090A0B0C0D0E0F0";
414   // This is passed explicitly to the linker in Makefile.am
415   const string build_id =
416       "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f";
417   EXPECT_EQ(module_identifier, module->debug_identifier());
418   EXPECT_EQ(build_id, module->code_identifier());
419 
420   IGNORE_EINTR(waitpid(child, nullptr, 0));
421 }
422 
423 // Test that mapping info can be specified, and that it overrides
424 // existing mappings that are wholly contained within the specified
425 // range.
TEST(MinidumpWriterTest,MappingInfoContained)426 TEST(MinidumpWriterTest, MappingInfoContained) {
427   int fds[2];
428   ASSERT_NE(-1, pipe(fds));
429 
430   // These are defined here so the parent can use them to check the
431   // data from the minidump afterwards.
432   const int32_t memory_size = sysconf(_SC_PAGESIZE);
433   const char* kMemoryName = "a fake module";
434   const uint8_t kModuleGUID[sizeof(MDGUID)] = {
435     0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77,
436     0x88, 0x99, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF
437   };
438   const string module_identifier = "33221100554477668899AABBCCDDEEFF0";
439 
440   // mmap a file
441   AutoTempDir temp_dir;
442   string tempfile = temp_dir.path() + "/minidump-writer-unittest-temp";
443   int fd = open(tempfile.c_str(), O_RDWR | O_CREAT, 0);
444   ASSERT_NE(-1, fd);
445   unlink(tempfile.c_str());
446   // fill with zeros
447   google_breakpad::scoped_array<char> buffer(new char[memory_size]);
448   memset(buffer.get(), 0, memory_size);
449   ASSERT_EQ(memory_size, write(fd, buffer.get(), memory_size));
450   lseek(fd, 0, SEEK_SET);
451 
452   char* memory =
453     reinterpret_cast<char*>(mmap(NULL,
454                                  memory_size,
455                                  PROT_READ | PROT_WRITE,
456                                  MAP_PRIVATE,
457                                  fd,
458                                  0));
459   const uintptr_t kMemoryAddress = reinterpret_cast<uintptr_t>(memory);
460   ASSERT_TRUE(memory);
461   close(fd);
462 
463   const pid_t child = fork();
464   if (child == 0) {
465     close(fds[1]);
466     char b;
467     IGNORE_RET(HANDLE_EINTR(read(fds[0], &b, sizeof(b))));
468     close(fds[0]);
469     syscall(__NR_exit_group);
470   }
471   close(fds[0]);
472 
473   ExceptionHandler::CrashContext context;
474   memset(&context, 0, sizeof(context));
475   context.tid = 1;
476 
477   string dumpfile = temp_dir.path() + kMDWriterUnitTestFileName;
478 
479   // Add information about the mapped memory. Report it as being larger than
480   // it actually is.
481   MappingInfo info;
482   info.start_addr = kMemoryAddress - memory_size;
483   info.size = memory_size * 3;
484   info.offset = 0;
485   info.exec = false;
486   strcpy(info.name, kMemoryName);
487 
488   MappingList mappings;
489   AppMemoryList memory_list;
490   MappingEntry mapping;
491   mapping.first = info;
492   memcpy(mapping.second, kModuleGUID, sizeof(MDGUID));
493   mappings.push_back(mapping);
494   ASSERT_TRUE(WriteMinidump(dumpfile.c_str(), child, &context, sizeof(context),
495                             mappings, memory_list));
496 
497   // Read the minidump. Load the module list, and ensure that
498   // the mmap'ed |memory| is listed with the given module name
499   // and debug ID.
500   Minidump minidump(dumpfile);
501   ASSERT_TRUE(minidump.Read());
502 
503   MinidumpModuleList* module_list = minidump.GetModuleList();
504   ASSERT_TRUE(module_list);
505   const MinidumpModule* module =
506     module_list->GetModuleForAddress(kMemoryAddress);
507   ASSERT_TRUE(module);
508 
509   EXPECT_EQ(info.start_addr, module->base_address());
510   EXPECT_EQ(info.size, module->size());
511   EXPECT_EQ(kMemoryName, module->code_file());
512   EXPECT_EQ(module_identifier, module->debug_identifier());
513 
514   close(fds[1]);
515   IGNORE_EINTR(waitpid(child, nullptr, 0));
516 }
517 
TEST(MinidumpWriterTest,DeletedBinary)518 TEST(MinidumpWriterTest, DeletedBinary) {
519   const string kNumberOfThreadsArgument = "1";
520   const string helper_path(GetHelperBinary());
521   if (helper_path.empty()) {
522     FAIL() << "Couldn't find helper binary";
523     exit(1);
524   }
525 
526   // Copy binary to a temp file.
527   AutoTempDir temp_dir;
528   string binpath = temp_dir.path() + "/linux-dumper-unittest-helper";
529   ASSERT_TRUE(CopyFile(helper_path, binpath))
530       << "Failed to copy " << helper_path << " to " << binpath;
531   ASSERT_EQ(0, chmod(binpath.c_str(), 0755));
532 
533   int fds[2];
534   ASSERT_NE(-1, pipe(fds));
535 
536   pid_t child_pid = fork();
537   if (child_pid == 0) {
538     // In child process.
539     close(fds[0]);
540 
541     // Pass the pipe fd and the number of threads as arguments.
542     char pipe_fd_string[8];
543     sprintf(pipe_fd_string, "%d", fds[1]);
544     execl(binpath.c_str(),
545           binpath.c_str(),
546           pipe_fd_string,
547           kNumberOfThreadsArgument.c_str(),
548           NULL);
549   }
550   close(fds[1]);
551   // Wait for the child process to signal that it's ready.
552   struct pollfd pfd;
553   memset(&pfd, 0, sizeof(pfd));
554   pfd.fd = fds[0];
555   pfd.events = POLLIN | POLLERR;
556 
557   const int r = HANDLE_EINTR(poll(&pfd, 1, 1000));
558   ASSERT_EQ(1, r);
559   ASSERT_TRUE(pfd.revents & POLLIN);
560   uint8_t junk;
561   const int nr = HANDLE_EINTR(read(fds[0], &junk, sizeof(junk)));
562   ASSERT_EQ(static_cast<ssize_t>(sizeof(junk)), nr);
563   close(fds[0]);
564 
565   // Child is ready now.
566   // Unlink the test binary.
567   unlink(binpath.c_str());
568 
569   ExceptionHandler::CrashContext context;
570   memset(&context, 0, sizeof(context));
571 
572   string templ = temp_dir.path() + kMDWriterUnitTestFileName;
573   // Set a non-zero tid to avoid tripping asserts.
574   context.tid = child_pid;
575   ASSERT_TRUE(WriteMinidump(templ.c_str(), child_pid, &context,
576                             sizeof(context)));
577   kill(child_pid, SIGKILL);
578 
579   struct stat st;
580   ASSERT_EQ(0, stat(templ.c_str(), &st));
581   ASSERT_GT(st.st_size, 0);
582 
583   Minidump minidump(templ);
584   ASSERT_TRUE(minidump.Read());
585 
586   // Check that the main module filename is correct.
587   MinidumpModuleList* module_list = minidump.GetModuleList();
588   ASSERT_TRUE(module_list);
589   const MinidumpModule* module = module_list->GetMainModule();
590   EXPECT_STREQ(binpath.c_str(), module->code_file().c_str());
591   // Check that the file ID is correct.
592   FileID fileid(helper_path.c_str());
593   PageAllocator allocator;
594   wasteful_vector<uint8_t> identifier(&allocator, kDefaultBuildIdSize);
595   EXPECT_TRUE(fileid.ElfFileIdentifier(identifier));
596   string identifier_string = FileID::ConvertIdentifierToUUIDString(identifier);
597   string module_identifier(identifier_string);
598   // Strip out dashes
599   size_t pos;
600   while ((pos = module_identifier.find('-')) != string::npos) {
601     module_identifier.erase(pos, 1);
602   }
603   // And append a zero, because module IDs include an "age" field
604   // which is always zero on Linux.
605   module_identifier += "0";
606   EXPECT_EQ(module_identifier, module->debug_identifier());
607 
608   IGNORE_EINTR(waitpid(child_pid, nullptr, 0));
609 }
610 
611 // Test that an additional memory region can be added to the minidump.
TEST(MinidumpWriterTest,AdditionalMemory)612 TEST(MinidumpWriterTest, AdditionalMemory) {
613   int fds[2];
614   ASSERT_NE(-1, pipe(fds));
615 
616   // These are defined here so the parent can use them to check the
617   // data from the minidump afterwards.
618   const uint32_t kMemorySize = sysconf(_SC_PAGESIZE);
619 
620   // Get some heap memory.
621   uint8_t* memory = new uint8_t[kMemorySize];
622   const uintptr_t kMemoryAddress = reinterpret_cast<uintptr_t>(memory);
623   ASSERT_TRUE(memory);
624 
625   // Stick some data into the memory so the contents can be verified.
626   for (uint32_t i = 0; i < kMemorySize; ++i) {
627     memory[i] = i % 255;
628   }
629 
630   const pid_t child = fork();
631   if (child == 0) {
632     close(fds[1]);
633     char b;
634     HANDLE_EINTR(read(fds[0], &b, sizeof(b)));
635     close(fds[0]);
636     syscall(__NR_exit_group);
637   }
638   close(fds[0]);
639 
640   ExceptionHandler::CrashContext context;
641 
642   // This needs a valid context for minidump writing to work, but getting
643   // a useful one from the child is too much work, so just use one from
644   // the parent since the child is just a forked copy anyway.
645   ASSERT_EQ(0, getcontext(&context.context));
646   context.tid = child;
647 
648   AutoTempDir temp_dir;
649   string templ = temp_dir.path() + kMDWriterUnitTestFileName;
650   unlink(templ.c_str());
651 
652   MappingList mappings;
653   AppMemoryList memory_list;
654 
655   // Add the memory region to the list of memory to be included.
656   AppMemory app_memory;
657   app_memory.ptr = memory;
658   app_memory.length = kMemorySize;
659   memory_list.push_back(app_memory);
660   ASSERT_TRUE(WriteMinidump(templ.c_str(), child, &context, sizeof(context),
661                             mappings, memory_list));
662 
663   // Read the minidump. Ensure that the memory region is present
664   Minidump minidump(templ);
665   ASSERT_TRUE(minidump.Read());
666 
667   MinidumpMemoryList* dump_memory_list = minidump.GetMemoryList();
668   ASSERT_TRUE(dump_memory_list);
669   const MinidumpMemoryRegion* region =
670     dump_memory_list->GetMemoryRegionForAddress(kMemoryAddress);
671   ASSERT_TRUE(region);
672 
673   EXPECT_EQ(kMemoryAddress, region->GetBase());
674   EXPECT_EQ(kMemorySize, region->GetSize());
675 
676   // Verify memory contents.
677   EXPECT_EQ(0, memcmp(region->GetMemory(), memory, kMemorySize));
678 
679   delete[] memory;
680   close(fds[1]);
681   IGNORE_EINTR(waitpid(child, nullptr, 0));
682 }
683 
684 // Test that an invalid thread stack pointer still results in a minidump.
TEST(MinidumpWriterTest,InvalidStackPointer)685 TEST(MinidumpWriterTest, InvalidStackPointer) {
686   int fds[2];
687   ASSERT_NE(-1, pipe(fds));
688 
689   const pid_t child = fork();
690   if (child == 0) {
691     close(fds[1]);
692     char b;
693     HANDLE_EINTR(read(fds[0], &b, sizeof(b)));
694     close(fds[0]);
695     syscall(__NR_exit_group);
696   }
697   close(fds[0]);
698 
699   ExceptionHandler::CrashContext context;
700 
701   // This needs a valid context for minidump writing to work, but getting
702   // a useful one from the child is too much work, so just use one from
703   // the parent since the child is just a forked copy anyway.
704   ASSERT_EQ(0, getcontext(&context.context));
705   context.tid = child;
706 
707   // Fake the child's stack pointer for its crashing thread.  NOTE: This must
708   // be an invalid memory address for the child process (stack or otherwise).
709   // Try 1MB below the current stack.
710   uintptr_t invalid_stack_pointer =
711       reinterpret_cast<uintptr_t>(&context) - 1024*1024;
712 #if defined(__i386)
713   context.context.uc_mcontext.gregs[REG_ESP] = invalid_stack_pointer;
714 #elif defined(__x86_64)
715   context.context.uc_mcontext.gregs[REG_RSP] = invalid_stack_pointer;
716 #elif defined(__ARM_EABI__)
717   context.context.uc_mcontext.arm_sp = invalid_stack_pointer;
718 #elif defined(__aarch64__)
719   context.context.uc_mcontext.sp = invalid_stack_pointer;
720 #elif defined(__mips__)
721   context.context.uc_mcontext.gregs[MD_CONTEXT_MIPS_REG_SP] =
722       invalid_stack_pointer;
723 #elif defined(__riscv)
724   context.context.uc_mcontext.__gregs[MD_CONTEXT_RISCV_REG_SP] =
725       invalid_stack_pointer;
726 #else
727 # error "This code has not been ported to your platform yet."
728 #endif
729 
730   AutoTempDir temp_dir;
731   string templ = temp_dir.path() + kMDWriterUnitTestFileName;
732   // NOTE: In previous versions of Breakpad, WriteMinidump() would fail if
733   // presented with an invalid stack pointer.
734   ASSERT_TRUE(WriteMinidump(templ.c_str(), child, &context, sizeof(context)));
735 
736   // Read the minidump. Ensure that the memory region is present
737   Minidump minidump(templ);
738   ASSERT_TRUE(minidump.Read());
739 
740   // TODO(ted.mielczarek,mkrebs): Enable this part of the test once
741   // https://breakpad.appspot.com/413002/ is committed.
742 #if 0
743   // Make sure there's a thread without a stack.  NOTE: It's okay if
744   // GetThreadList() shows the error: "ERROR: MinidumpThread has a memory
745   // region problem".
746   MinidumpThreadList* dump_thread_list = minidump.GetThreadList();
747   ASSERT_TRUE(dump_thread_list);
748   bool found_empty_stack = false;
749   for (int i = 0; i < dump_thread_list->thread_count(); i++) {
750     MinidumpThread* thread = dump_thread_list->GetThreadAtIndex(i);
751     ASSERT_TRUE(thread->thread() != NULL);
752     // When the stack size is zero bytes, GetMemory() returns NULL.
753     if (thread->GetMemory() == NULL) {
754       found_empty_stack = true;
755       break;
756     }
757   }
758   // NOTE: If you fail this, first make sure that "invalid_stack_pointer"
759   // above is indeed set to an invalid address.
760   ASSERT_TRUE(found_empty_stack);
761 #endif
762 
763   close(fds[1]);
764   IGNORE_EINTR(waitpid(child, nullptr, 0));
765 }
766 
767 // Test that limiting the size of the minidump works.
TEST(MinidumpWriterTest,MinidumpSizeLimit)768 TEST(MinidumpWriterTest, MinidumpSizeLimit) {
769   static const int kNumberOfThreadsInHelperProgram = 40;
770 
771   char number_of_threads_arg[3];
772   sprintf(number_of_threads_arg, "%d", kNumberOfThreadsInHelperProgram);
773 
774   string helper_path(GetHelperBinary());
775   if (helper_path.empty()) {
776     FAIL() << "Couldn't find helper binary";
777     exit(1);
778   }
779 
780   int fds[2];
781   ASSERT_NE(-1, pipe(fds));
782 
783   pid_t child_pid = fork();
784   if (child_pid == 0) {
785     // In child process.
786     close(fds[0]);
787 
788     // Pass the pipe fd and the number of threads as arguments.
789     char pipe_fd_string[8];
790     sprintf(pipe_fd_string, "%d", fds[1]);
791     execl(helper_path.c_str(),
792           helper_path.c_str(),
793           pipe_fd_string,
794           number_of_threads_arg,
795           NULL);
796   }
797   close(fds[1]);
798 
799   // Wait for all child threads to indicate that they have started
800   for (int threads = 0; threads < kNumberOfThreadsInHelperProgram; threads++) {
801     struct pollfd pfd;
802     memset(&pfd, 0, sizeof(pfd));
803     pfd.fd = fds[0];
804     pfd.events = POLLIN | POLLERR;
805 
806     const int r = HANDLE_EINTR(poll(&pfd, 1, 1000));
807     ASSERT_EQ(1, r);
808     ASSERT_TRUE(pfd.revents & POLLIN);
809     uint8_t junk;
810     ASSERT_EQ(read(fds[0], &junk, sizeof(junk)),
811               static_cast<ssize_t>(sizeof(junk)));
812   }
813   close(fds[0]);
814 
815   // There is a race here because we may stop a child thread before
816   // it is actually running the busy loop. Empirically this sleep
817   // is sufficient to avoid the race.
818   usleep(100000);
819 
820   // Child and its threads are ready now.
821 
822 
823   off_t normal_file_size;
824   int total_normal_stack_size = 0;
825   AutoTempDir temp_dir;
826 
827   // First, write a minidump with no size limit.
828   {
829     string normal_dump = temp_dir.path() +
830         "/minidump-writer-unittest.dmp";
831     ASSERT_TRUE(WriteMinidump(normal_dump.c_str(), -1,
832                               child_pid, NULL, 0,
833                               MappingList(), AppMemoryList()));
834     struct stat st;
835     ASSERT_EQ(0, stat(normal_dump.c_str(), &st));
836     ASSERT_GT(st.st_size, 0);
837     normal_file_size = st.st_size;
838 
839     Minidump minidump(normal_dump);
840     ASSERT_TRUE(minidump.Read());
841     MinidumpThreadList* dump_thread_list = minidump.GetThreadList();
842     ASSERT_TRUE(dump_thread_list);
843     for (unsigned int i = 0; i < dump_thread_list->thread_count(); i++) {
844       MinidumpThread* thread = dump_thread_list->GetThreadAtIndex(i);
845       ASSERT_TRUE(thread->thread() != NULL);
846       // When the stack size is zero bytes, GetMemory() returns NULL.
847       MinidumpMemoryRegion* memory = thread->GetMemory();
848       ASSERT_TRUE(memory != NULL);
849       total_normal_stack_size += memory->GetSize();
850     }
851   }
852 
853   // Second, write a minidump with a size limit big enough to not trigger
854   // anything.
855   {
856     // Set size limit arbitrarily 1MB larger than the normal file size -- such
857     // that the limiting code will not kick in.
858     const off_t minidump_size_limit = normal_file_size + 1024*1024;
859 
860     string same_dump = temp_dir.path() +
861         "/minidump-writer-unittest-same.dmp";
862     ASSERT_TRUE(WriteMinidump(same_dump.c_str(), minidump_size_limit,
863                               child_pid, NULL, 0,
864                               MappingList(), AppMemoryList()));
865     struct stat st;
866     ASSERT_EQ(0, stat(same_dump.c_str(), &st));
867     // Make sure limiting wasn't actually triggered.  NOTE: If you fail this,
868     // first make sure that "minidump_size_limit" above is indeed set to a
869     // large enough value -- the limit-checking code in minidump_writer.cc
870     // does just a rough estimate.
871     ASSERT_EQ(normal_file_size, st.st_size);
872   }
873 
874   // Third, write a minidump with a size limit small enough to be triggered.
875   {
876     // Set size limit to some arbitrary amount, such that the limiting code
877     // will kick in.  The equation used to set this value was determined by
878     // simply reversing the size-limit logic a little bit in order to pick a
879     // size we know will trigger it.  The definition of
880     // kLimitAverageThreadStackLength here was copied from class
881     // MinidumpWriter in minidump_writer.cc.
882     static const unsigned kLimitAverageThreadStackLength = 8 * 1024;
883     off_t minidump_size_limit = kNumberOfThreadsInHelperProgram *
884         kLimitAverageThreadStackLength;
885     // If, in reality, each of the threads' stack is *smaller* than
886     // kLimitAverageThreadStackLength, the normal file size could very well be
887     // smaller than the arbitrary limit that was just set.  In that case,
888     // either of these numbers should trigger the size-limiting code, but we
889     // might as well pick the smallest.
890     if (normal_file_size < minidump_size_limit)
891       minidump_size_limit = normal_file_size;
892 
893     string limit_dump = temp_dir.path() +
894         "/minidump-writer-unittest-limit.dmp";
895     ASSERT_TRUE(WriteMinidump(limit_dump.c_str(), minidump_size_limit,
896                               child_pid, NULL, 0,
897                               MappingList(), AppMemoryList()));
898     struct stat st;
899     ASSERT_EQ(0, stat(limit_dump.c_str(), &st));
900     ASSERT_GT(st.st_size, 0);
901     // Make sure the file size is at least smaller than the original.  If this
902     // fails because it's the same size, then the size-limit logic didn't kick
903     // in like it was supposed to.
904     EXPECT_LT(st.st_size, normal_file_size);
905 
906     Minidump minidump(limit_dump);
907     ASSERT_TRUE(minidump.Read());
908     MinidumpThreadList* dump_thread_list = minidump.GetThreadList();
909     ASSERT_TRUE(dump_thread_list);
910     int total_limit_stack_size = 0;
911     for (unsigned int i = 0; i < dump_thread_list->thread_count(); i++) {
912       MinidumpThread* thread = dump_thread_list->GetThreadAtIndex(i);
913       ASSERT_TRUE(thread->thread() != NULL);
914       // When the stack size is zero bytes, GetMemory() returns NULL.
915       MinidumpMemoryRegion* memory = thread->GetMemory();
916       ASSERT_TRUE(memory != NULL);
917       total_limit_stack_size += memory->GetSize();
918     }
919 
920     // Make sure stack size shrunk by at least 1KB per extra thread.  The
921     // definition of kLimitBaseThreadCount here was copied from class
922     // MinidumpWriter in minidump_writer.cc.
923     // Note: The 1KB is arbitrary, and assumes that the thread stacks are big
924     // enough to shrink by that much.  For example, if each thread stack was
925     // originally only 2KB, the current size-limit logic wouldn't actually
926     // shrink them because that's the size to which it tries to shrink.  If
927     // you fail this part of the test due to something like that, the test
928     // logic should probably be improved to account for your situation.
929     const unsigned kLimitBaseThreadCount = 20;
930     const unsigned kMinPerExtraThreadStackReduction = 1024;
931     const int min_expected_reduction = (kNumberOfThreadsInHelperProgram -
932         kLimitBaseThreadCount) * kMinPerExtraThreadStackReduction;
933     EXPECT_LT(total_limit_stack_size,
934               total_normal_stack_size - min_expected_reduction);
935   }
936 
937   // Kill the helper program.
938   kill(child_pid, SIGKILL);
939   IGNORE_EINTR(waitpid(child_pid, nullptr, 0));
940 }
941 
942 }  // namespace
943