1 /*
2  * Copyright (C) 2015 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include <stdlib.h>
18 #include <sys/mman.h>
19 #include <time.h>
20 
21 #include <memory>
22 #include <string>
23 
24 #include <android-base/file.h>
25 #include <android-base/properties.h>
26 #include <gmock/gmock.h>
27 #include <gtest/gtest.h>
28 
29 #include "libdebuggerd/utility.h"
30 
31 #include "UnwinderMock.h"
32 #include "host_signal_fixup.h"
33 #include "log_fake.h"
34 
35 // Include tombstone.cpp to define log_tag before GWP-ASan includes log.
36 #include "tombstone.cpp"
37 
38 #include "gwp_asan.cpp"
39 
40 using ::testing::MatchesRegex;
41 
42 class TombstoneTest : public ::testing::Test {
43  protected:
SetUp()44   virtual void SetUp() {
45     unwinder_mock_.reset(new UnwinderMock());
46 
47     char tmp_file[256];
48     const char data_template[] = "/data/local/tmp/debuggerd_memory_testXXXXXX";
49     memcpy(tmp_file, data_template, sizeof(data_template));
50     int tombstone_fd = mkstemp(tmp_file);
51     if (tombstone_fd == -1) {
52       const char tmp_template[] = "/tmp/debuggerd_memory_testXXXXXX";
53       memcpy(tmp_file, tmp_template, sizeof(tmp_template));
54       tombstone_fd = mkstemp(tmp_file);
55       if (tombstone_fd == -1) {
56         abort();
57       }
58     }
59     if (unlink(tmp_file) == -1) {
60       abort();
61     }
62 
63     log_.tfd = tombstone_fd;
64     amfd_data_.clear();
65     log_.amfd_data = &amfd_data_;
66     log_.crashed_tid = 12;
67     log_.current_tid = 12;
68     log_.should_retrieve_logcat = false;
69 
70     resetLogs();
71   }
72 
TearDown()73   virtual void TearDown() {
74     if (log_.tfd >= 0) {
75       close(log_.tfd);
76     }
77   }
78 
79   std::unique_ptr<UnwinderMock> unwinder_mock_;
80 
81   log_t log_;
82   std::string amfd_data_;
83 };
84 
TEST_F(TombstoneTest,single_map)85 TEST_F(TombstoneTest, single_map) {
86 #if defined(__LP64__)
87   unwinder_mock_->MockAddMap(0x123456789abcd000UL, 0x123456789abdf000UL, 0, 0, "", 0);
88 #else
89   unwinder_mock_->MockAddMap(0x1234000, 0x1235000, 0, 0, "", 0);
90 #endif
91 
92   dump_all_maps(&log_, unwinder_mock_.get(), 0);
93 
94   std::string tombstone_contents;
95   ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0);
96   ASSERT_TRUE(android::base::ReadFdToString(log_.tfd, &tombstone_contents));
97   const char* expected_dump = \
98 "\nmemory map (1 entry):\n"
99 #if defined(__LP64__)
100 "    12345678'9abcd000-12345678'9abdefff ---         0     12000\n";
101 #else
102 "    01234000-01234fff ---         0      1000\n";
103 #endif
104   ASSERT_STREQ(expected_dump, tombstone_contents.c_str());
105 
106   ASSERT_STREQ("", amfd_data_.c_str());
107 
108   // Verify that the log buf is empty, and no error messages.
109   ASSERT_STREQ("", getFakeLogBuf().c_str());
110   ASSERT_STREQ("", getFakeLogPrint().c_str());
111 }
112 
TEST_F(TombstoneTest,single_map_elf_build_id)113 TEST_F(TombstoneTest, single_map_elf_build_id) {
114   uint64_t build_id_offset;
115 #if defined(__LP64__)
116   build_id_offset = 0x123456789abcd000UL;
117   unwinder_mock_->MockAddMap(build_id_offset, 0x123456789abdf000UL, 0, PROT_READ,
118                              "/system/lib/libfake.so", 0);
119 #else
120   build_id_offset = 0x1234000;
121   unwinder_mock_->MockAddMap(0x1234000, 0x1235000, 0, PROT_READ, "/system/lib/libfake.so", 0);
122 #endif
123 
124   unwinder_mock_->MockSetBuildID(
125       build_id_offset,
126       std::string{static_cast<char>(0xab), static_cast<char>(0xcd), static_cast<char>(0xef),
127                   static_cast<char>(0x12), static_cast<char>(0x34), static_cast<char>(0x56),
128                   static_cast<char>(0x78), static_cast<char>(0x90), static_cast<char>(0xab),
129                   static_cast<char>(0xcd), static_cast<char>(0xef), static_cast<char>(0x12),
130                   static_cast<char>(0x34), static_cast<char>(0x56), static_cast<char>(0x78),
131                   static_cast<char>(0x90)});
132   dump_all_maps(&log_, unwinder_mock_.get(), 0);
133 
134   std::string tombstone_contents;
135   ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0);
136   ASSERT_TRUE(android::base::ReadFdToString(log_.tfd, &tombstone_contents));
137   const char* expected_dump = \
138 "\nmemory map (1 entry):\n"
139 #if defined(__LP64__)
140 "    12345678'9abcd000-12345678'9abdefff r--         0     12000  /system/lib/libfake.so (BuildId: abcdef1234567890abcdef1234567890)\n";
141 #else
142 "    01234000-01234fff r--         0      1000  /system/lib/libfake.so (BuildId: abcdef1234567890abcdef1234567890)\n";
143 #endif
144   ASSERT_STREQ(expected_dump, tombstone_contents.c_str());
145 
146   ASSERT_STREQ("", amfd_data_.c_str());
147 
148   // Verify that the log buf is empty, and no error messages.
149   ASSERT_STREQ("", getFakeLogBuf().c_str());
150   ASSERT_STREQ("", getFakeLogPrint().c_str());
151 }
152 
TEST_F(TombstoneTest,multiple_maps)153 TEST_F(TombstoneTest, multiple_maps) {
154   unwinder_mock_->MockAddMap(0xa234000, 0xa235000, 0, 0, "", 0);
155   unwinder_mock_->MockAddMap(0xa334000, 0xa335000, 0xf000, PROT_READ, "", 0);
156   unwinder_mock_->MockAddMap(0xa434000, 0xa435000, 0x1000, PROT_WRITE, "", 0xd000);
157   unwinder_mock_->MockAddMap(0xa534000, 0xa535000, 0x3000, PROT_EXEC, "", 0x2000);
158   unwinder_mock_->MockAddMap(0xa634000, 0xa635000, 0, PROT_READ | PROT_WRITE | PROT_EXEC,
159                              "/system/lib/fake.so", 0);
160 
161   dump_all_maps(&log_, unwinder_mock_.get(), 0);
162 
163   std::string tombstone_contents;
164   ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0);
165   ASSERT_TRUE(android::base::ReadFdToString(log_.tfd, &tombstone_contents));
166   const char* expected_dump =
167       "\nmemory map (5 entries):\n"
168 #if defined(__LP64__)
169       "    00000000'0a234000-00000000'0a234fff ---         0      1000\n"
170       "    00000000'0a334000-00000000'0a334fff r--      f000      1000\n"
171       "    00000000'0a434000-00000000'0a434fff -w-      1000      1000  (load bias 0xd000)\n"
172       "    00000000'0a534000-00000000'0a534fff --x      3000      1000  (load bias 0x2000)\n"
173       "    00000000'0a634000-00000000'0a634fff rwx         0      1000  /system/lib/fake.so\n";
174 #else
175       "    0a234000-0a234fff ---         0      1000\n"
176       "    0a334000-0a334fff r--      f000      1000\n"
177       "    0a434000-0a434fff -w-      1000      1000  (load bias 0xd000)\n"
178       "    0a534000-0a534fff --x      3000      1000  (load bias 0x2000)\n"
179       "    0a634000-0a634fff rwx         0      1000  /system/lib/fake.so\n";
180 #endif
181   ASSERT_STREQ(expected_dump, tombstone_contents.c_str());
182 
183   ASSERT_STREQ("", amfd_data_.c_str());
184 
185   // Verify that the log buf is empty, and no error messages.
186   ASSERT_STREQ("", getFakeLogBuf().c_str());
187   ASSERT_STREQ("", getFakeLogPrint().c_str());
188 }
189 
TEST_F(TombstoneTest,multiple_maps_fault_address_before)190 TEST_F(TombstoneTest, multiple_maps_fault_address_before) {
191   unwinder_mock_->MockAddMap(0xa434000, 0xa435000, 0x1000, PROT_WRITE, "", 0xd000);
192   unwinder_mock_->MockAddMap(0xa534000, 0xa535000, 0x3000, PROT_EXEC, "", 0x2000);
193   unwinder_mock_->MockAddMap(0xa634000, 0xa635000, 0, PROT_READ | PROT_WRITE | PROT_EXEC,
194                              "/system/lib/fake.so", 0);
195 
196   dump_all_maps(&log_, unwinder_mock_.get(), 0x1000);
197 
198   std::string tombstone_contents;
199   ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0);
200   ASSERT_TRUE(android::base::ReadFdToString(log_.tfd, &tombstone_contents));
201   const char* expected_dump =
202       "\nmemory map (3 entries):\n"
203 #if defined(__LP64__)
204       "--->Fault address falls at 00000000'00001000 before any mapped regions\n"
205       "    00000000'0a434000-00000000'0a434fff -w-      1000      1000  (load bias 0xd000)\n"
206       "    00000000'0a534000-00000000'0a534fff --x      3000      1000  (load bias 0x2000)\n"
207       "    00000000'0a634000-00000000'0a634fff rwx         0      1000  /system/lib/fake.so\n";
208 #else
209       "--->Fault address falls at 00001000 before any mapped regions\n"
210       "    0a434000-0a434fff -w-      1000      1000  (load bias 0xd000)\n"
211       "    0a534000-0a534fff --x      3000      1000  (load bias 0x2000)\n"
212       "    0a634000-0a634fff rwx         0      1000  /system/lib/fake.so\n";
213 #endif
214   ASSERT_STREQ(expected_dump, tombstone_contents.c_str());
215 
216   ASSERT_STREQ("", amfd_data_.c_str());
217 
218   // Verify that the log buf is empty, and no error messages.
219   ASSERT_STREQ("", getFakeLogBuf().c_str());
220   ASSERT_STREQ("", getFakeLogPrint().c_str());
221 }
222 
TEST_F(TombstoneTest,multiple_maps_fault_address_between)223 TEST_F(TombstoneTest, multiple_maps_fault_address_between) {
224   unwinder_mock_->MockAddMap(0xa434000, 0xa435000, 0x1000, PROT_WRITE, "", 0xd000);
225   unwinder_mock_->MockAddMap(0xa534000, 0xa535000, 0x3000, PROT_EXEC, "", 0x2000);
226   unwinder_mock_->MockAddMap(0xa634000, 0xa635000, 0, PROT_READ | PROT_WRITE | PROT_EXEC,
227                              "/system/lib/fake.so", 0);
228 
229   dump_all_maps(&log_, unwinder_mock_.get(), 0xa533000);
230 
231   std::string tombstone_contents;
232   ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0);
233   ASSERT_TRUE(android::base::ReadFdToString(log_.tfd, &tombstone_contents));
234   const char* expected_dump =
235       "\nmemory map (3 entries): (fault address prefixed with --->)\n"
236 #if defined(__LP64__)
237       "    00000000'0a434000-00000000'0a434fff -w-      1000      1000  (load bias 0xd000)\n"
238       "--->Fault address falls at 00000000'0a533000 between mapped regions\n"
239       "    00000000'0a534000-00000000'0a534fff --x      3000      1000  (load bias 0x2000)\n"
240       "    00000000'0a634000-00000000'0a634fff rwx         0      1000  /system/lib/fake.so\n";
241 #else
242       "    0a434000-0a434fff -w-      1000      1000  (load bias 0xd000)\n"
243       "--->Fault address falls at 0a533000 between mapped regions\n"
244       "    0a534000-0a534fff --x      3000      1000  (load bias 0x2000)\n"
245       "    0a634000-0a634fff rwx         0      1000  /system/lib/fake.so\n";
246 #endif
247   ASSERT_STREQ(expected_dump, tombstone_contents.c_str());
248 
249   ASSERT_STREQ("", amfd_data_.c_str());
250 
251   // Verify that the log buf is empty, and no error messages.
252   ASSERT_STREQ("", getFakeLogBuf().c_str());
253   ASSERT_STREQ("", getFakeLogPrint().c_str());
254 }
255 
TEST_F(TombstoneTest,multiple_maps_fault_address_in_map)256 TEST_F(TombstoneTest, multiple_maps_fault_address_in_map) {
257   unwinder_mock_->MockAddMap(0xa434000, 0xa435000, 0x1000, PROT_WRITE, "", 0xd000);
258   unwinder_mock_->MockAddMap(0xa534000, 0xa535000, 0x3000, PROT_EXEC, "", 0x2000);
259   unwinder_mock_->MockAddMap(0xa634000, 0xa635000, 0, PROT_READ | PROT_WRITE | PROT_EXEC,
260                              "/system/lib/fake.so", 0);
261 
262   dump_all_maps(&log_, unwinder_mock_.get(), 0xa534040);
263 
264   std::string tombstone_contents;
265   ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0);
266   ASSERT_TRUE(android::base::ReadFdToString(log_.tfd, &tombstone_contents));
267   const char* expected_dump =
268       "\nmemory map (3 entries): (fault address prefixed with --->)\n"
269 #if defined(__LP64__)
270       "    00000000'0a434000-00000000'0a434fff -w-      1000      1000  (load bias 0xd000)\n"
271       "--->00000000'0a534000-00000000'0a534fff --x      3000      1000  (load bias 0x2000)\n"
272       "    00000000'0a634000-00000000'0a634fff rwx         0      1000  /system/lib/fake.so\n";
273 #else
274       "    0a434000-0a434fff -w-      1000      1000  (load bias 0xd000)\n"
275       "--->0a534000-0a534fff --x      3000      1000  (load bias 0x2000)\n"
276       "    0a634000-0a634fff rwx         0      1000  /system/lib/fake.so\n";
277 #endif
278   ASSERT_STREQ(expected_dump, tombstone_contents.c_str());
279 
280   ASSERT_STREQ("", amfd_data_.c_str());
281 
282   // Verify that the log buf is empty, and no error messages.
283   ASSERT_STREQ("", getFakeLogBuf().c_str());
284   ASSERT_STREQ("", getFakeLogPrint().c_str());
285 }
286 
TEST_F(TombstoneTest,multiple_maps_fault_address_after)287 TEST_F(TombstoneTest, multiple_maps_fault_address_after) {
288   unwinder_mock_->MockAddMap(0xa434000, 0xa435000, 0x1000, PROT_WRITE, "", 0xd000);
289   unwinder_mock_->MockAddMap(0xa534000, 0xa535000, 0x3000, PROT_EXEC, "", 0x2000);
290   unwinder_mock_->MockAddMap(0xa634000, 0xa635000, 0, PROT_READ | PROT_WRITE | PROT_EXEC,
291                              "/system/lib/fake.so", 0);
292 
293 #if defined(__LP64__)
294   uint64_t addr = 0x12345a534040UL;
295 #else
296   uint64_t addr = 0xf534040UL;
297 #endif
298   dump_all_maps(&log_, unwinder_mock_.get(), addr);
299 
300   std::string tombstone_contents;
301   ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0);
302   ASSERT_TRUE(android::base::ReadFdToString(log_.tfd, &tombstone_contents));
303   const char* expected_dump =
304       "\nmemory map (3 entries): (fault address prefixed with --->)\n"
305 #if defined(__LP64__)
306       "    00000000'0a434000-00000000'0a434fff -w-      1000      1000  (load bias 0xd000)\n"
307       "    00000000'0a534000-00000000'0a534fff --x      3000      1000  (load bias 0x2000)\n"
308       "    00000000'0a634000-00000000'0a634fff rwx         0      1000  /system/lib/fake.so\n"
309       "--->Fault address falls at 00001234'5a534040 after any mapped regions\n";
310 #else
311       "    0a434000-0a434fff -w-      1000      1000  (load bias 0xd000)\n"
312       "    0a534000-0a534fff --x      3000      1000  (load bias 0x2000)\n"
313       "    0a634000-0a634fff rwx         0      1000  /system/lib/fake.so\n"
314       "--->Fault address falls at 0f534040 after any mapped regions\n";
315 #endif
316   ASSERT_STREQ(expected_dump, tombstone_contents.c_str());
317 
318   ASSERT_STREQ("", amfd_data_.c_str());
319 
320   // Verify that the log buf is empty, and no error messages.
321   ASSERT_STREQ("", getFakeLogBuf().c_str());
322   ASSERT_STREQ("", getFakeLogPrint().c_str());
323 }
324 
TEST_F(TombstoneTest,dump_log_file_error)325 TEST_F(TombstoneTest, dump_log_file_error) {
326   log_.should_retrieve_logcat = true;
327   dump_log_file(&log_, 123, "/fake/filename", 10);
328 
329   std::string tombstone_contents;
330   ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0);
331   ASSERT_TRUE(android::base::ReadFdToString(log_.tfd, &tombstone_contents));
332   ASSERT_STREQ("", tombstone_contents.c_str());
333 
334   ASSERT_STREQ("", getFakeLogBuf().c_str());
335   ASSERT_STREQ("6 DEBUG Unable to open /fake/filename: Permission denied\n\n",
336                getFakeLogPrint().c_str());
337 
338   ASSERT_STREQ("", amfd_data_.c_str());
339 }
340 
TEST_F(TombstoneTest,dump_header_info)341 TEST_F(TombstoneTest, dump_header_info) {
342   dump_header_info(&log_);
343 
344   std::string expected = android::base::StringPrintf(
345       "Build fingerprint: '%s'\nRevision: '%s'\n",
346       android::base::GetProperty("ro.build.fingerprint", "unknown").c_str(),
347       android::base::GetProperty("ro.revision", "unknown").c_str());
348   expected += android::base::StringPrintf("ABI: '%s'\n", ABI_STRING);
349   ASSERT_STREQ(expected.c_str(), amfd_data_.c_str());
350 }
351 
TEST_F(TombstoneTest,dump_thread_info_uid)352 TEST_F(TombstoneTest, dump_thread_info_uid) {
353   std::vector<std::string> cmdline = {"some_process"};
354   dump_thread_info(
355       &log_,
356       ThreadInfo{
357           .uid = 1, .tid = 3, .thread_name = "some_thread", .pid = 2, .command_line = cmdline});
358   std::string expected = "pid: 2, tid: 3, name: some_thread  >>> some_process <<<\nuid: 1\n";
359   ASSERT_STREQ(expected.c_str(), amfd_data_.c_str());
360 }
361 
362 class GwpAsanCrashDataTest : public GwpAsanCrashData {
363 public:
GwpAsanCrashDataTest(gwp_asan::Error error,const gwp_asan::AllocationMetadata * responsible_allocation)364   GwpAsanCrashDataTest(
365       gwp_asan::Error error,
366       const gwp_asan::AllocationMetadata *responsible_allocation) :
367       GwpAsanCrashData(nullptr, ProcessInfo{}, ThreadInfo{}) {
368     is_gwp_asan_responsible_ = true;
369     error_ = error;
370     responsible_allocation_ = responsible_allocation;
371     error_string_ = gwp_asan::ErrorToString(error_);
372   }
373 
SetCrashAddress(uintptr_t crash_address)374   void SetCrashAddress(uintptr_t crash_address) {
375     crash_address_ = crash_address;
376   }
377 };
378 
TEST_F(TombstoneTest,gwp_asan_cause_uaf_exact)379 TEST_F(TombstoneTest, gwp_asan_cause_uaf_exact) {
380   gwp_asan::AllocationMetadata meta;
381   meta.Addr = 0x1000;
382   meta.RequestedSize = 32;
383 
384   GwpAsanCrashDataTest crash_data(gwp_asan::Error::USE_AFTER_FREE, &meta);
385   crash_data.SetCrashAddress(0x1000);
386 
387   crash_data.DumpCause(&log_);
388   ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0);
389   std::string tombstone_contents;
390   ASSERT_TRUE(android::base::ReadFdToString(log_.tfd, &tombstone_contents));
391   ASSERT_THAT(tombstone_contents, MatchesRegex("Cause: \\[GWP-ASan\\]: Use After Free, 0 bytes "
392                                                "into a 32-byte allocation at 0x[a-fA-F0-9]+\n"));
393 }
394 
TEST_F(TombstoneTest,gwp_asan_cause_double_free)395 TEST_F(TombstoneTest, gwp_asan_cause_double_free) {
396   gwp_asan::AllocationMetadata meta;
397   meta.Addr = 0x1000;
398   meta.RequestedSize = 32;
399 
400   GwpAsanCrashDataTest crash_data(gwp_asan::Error::DOUBLE_FREE, &meta);
401   crash_data.SetCrashAddress(0x1000);
402 
403   crash_data.DumpCause(&log_);
404   ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0);
405   std::string tombstone_contents;
406   ASSERT_TRUE(android::base::ReadFdToString(log_.tfd, &tombstone_contents));
407   ASSERT_THAT(tombstone_contents, MatchesRegex("Cause: \\[GWP-ASan\\]: Double Free, 0 bytes into a "
408                                                "32-byte allocation at 0x[a-fA-F0-9]+\n"));
409 }
410 
TEST_F(TombstoneTest,gwp_asan_cause_overflow)411 TEST_F(TombstoneTest, gwp_asan_cause_overflow) {
412   gwp_asan::AllocationMetadata meta;
413   meta.Addr = 0x1000;
414   meta.RequestedSize = 32;
415 
416   GwpAsanCrashDataTest crash_data(gwp_asan::Error::BUFFER_OVERFLOW, &meta);
417   crash_data.SetCrashAddress(0x1025);
418 
419   crash_data.DumpCause(&log_);
420   ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0);
421   std::string tombstone_contents;
422   ASSERT_TRUE(android::base::ReadFdToString(log_.tfd, &tombstone_contents));
423   ASSERT_THAT(
424       tombstone_contents,
425       MatchesRegex(
426           "Cause: \\[GWP-ASan\\]: Buffer Overflow, 5 bytes right of a 32-byte "
427           "allocation at 0x[a-fA-F0-9]+\n"));
428 }
429 
TEST_F(TombstoneTest,gwp_asan_cause_underflow)430 TEST_F(TombstoneTest, gwp_asan_cause_underflow) {
431   gwp_asan::AllocationMetadata meta;
432   meta.Addr = 0x1000;
433   meta.RequestedSize = 32;
434 
435   GwpAsanCrashDataTest crash_data(gwp_asan::Error::BUFFER_UNDERFLOW, &meta);
436   crash_data.SetCrashAddress(0xffe);
437 
438   crash_data.DumpCause(&log_);
439   ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0);
440   std::string tombstone_contents;
441   ASSERT_TRUE(android::base::ReadFdToString(log_.tfd, &tombstone_contents));
442   ASSERT_THAT(
443       tombstone_contents,
444       MatchesRegex(
445           "Cause: \\[GWP-ASan\\]: Buffer Underflow, 2 bytes left of a 32-byte "
446           "allocation at 0x[a-fA-F0-9]+\n"));
447 }
448 
TEST_F(TombstoneTest,gwp_asan_cause_invalid_free_inside)449 TEST_F(TombstoneTest, gwp_asan_cause_invalid_free_inside) {
450   gwp_asan::AllocationMetadata meta;
451   meta.Addr = 0x1000;
452   meta.RequestedSize = 32;
453 
454   GwpAsanCrashDataTest crash_data(gwp_asan::Error::INVALID_FREE, &meta);
455   crash_data.SetCrashAddress(0x1001);
456 
457   crash_data.DumpCause(&log_);
458   ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0);
459   std::string tombstone_contents;
460   ASSERT_TRUE(android::base::ReadFdToString(log_.tfd, &tombstone_contents));
461   ASSERT_THAT(
462       tombstone_contents,
463       MatchesRegex(
464           "Cause: \\[GWP-ASan\\]: Invalid \\(Wild\\) Free, 1 byte into a 32-byte "
465           "allocation at 0x[a-fA-F0-9]+\n"));
466 }
467 
TEST_F(TombstoneTest,gwp_asan_cause_invalid_free_outside)468 TEST_F(TombstoneTest, gwp_asan_cause_invalid_free_outside) {
469   gwp_asan::AllocationMetadata meta;
470   meta.Addr = 0x1000;
471   meta.RequestedSize = 32;
472 
473   GwpAsanCrashDataTest crash_data(gwp_asan::Error::INVALID_FREE, &meta);
474   crash_data.SetCrashAddress(0x1021);
475 
476   crash_data.DumpCause(&log_);
477   ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0);
478   std::string tombstone_contents;
479   ASSERT_TRUE(android::base::ReadFdToString(log_.tfd, &tombstone_contents));
480   ASSERT_THAT(
481       tombstone_contents,
482       MatchesRegex(
483           "Cause: \\[GWP-ASan\\]: Invalid \\(Wild\\) Free, 33 bytes right of a 32-byte "
484           "allocation at 0x[a-fA-F0-9]+\n"));
485 }
486 
487