1 //===-- backtrace.cpp -------------------------------------------*- C++ -*-===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 
9 #include <regex>
10 #include <string>
11 
12 #include "gwp_asan/common.h"
13 #include "gwp_asan/crash_handler.h"
14 #include "gwp_asan/tests/harness.h"
15 
TEST_P(BacktraceGuardedPoolAllocatorDeathTest,DoubleFree)16 TEST_P(BacktraceGuardedPoolAllocatorDeathTest, DoubleFree) {
17   void *Ptr = AllocateMemory(GPA);
18   DeallocateMemory(GPA, Ptr);
19 
20   std::string DeathRegex = "Double Free.*DeallocateMemory2.*";
21   DeathRegex.append("was deallocated.*DeallocateMemory[^2].*");
22   DeathRegex.append("was allocated.*AllocateMemory");
23   if (!Recoverable) {
24     ASSERT_DEATH(DeallocateMemory2(GPA, Ptr), DeathRegex);
25     return;
26   }
27 
28   // For recoverable, assert that DeallocateMemory2() doesn't crash.
29   DeallocateMemory2(GPA, Ptr);
30   // Fuchsia's zxtest doesn't have an EXPECT_THAT(testing::MatchesRegex(), ...),
31   // so check the regex manually.
32   EXPECT_TRUE(std::regex_search(
33       GetOutputBuffer(),
34       std::basic_regex(DeathRegex, std::regex_constants::extended)))
35       << "Regex \"" << DeathRegex
36       << "\" was not found in input:\n============\n"
37       << GetOutputBuffer() << "\n============";
38 }
39 
TEST_P(BacktraceGuardedPoolAllocatorDeathTest,UseAfterFree)40 TEST_P(BacktraceGuardedPoolAllocatorDeathTest, UseAfterFree) {
41 #if defined(__linux__) && __ARM_ARCH == 7
42   // Incomplete backtrace on Armv7 Linux
43   GTEST_SKIP();
44 #endif
45 
46   void *Ptr = AllocateMemory(GPA);
47   DeallocateMemory(GPA, Ptr);
48 
49   std::string DeathRegex = "Use After Free.*TouchMemory.*";
50   DeathRegex.append("was deallocated.*DeallocateMemory[^2].*");
51   DeathRegex.append("was allocated.*AllocateMemory");
52 
53   if (!Recoverable) {
54     ASSERT_DEATH(TouchMemory(Ptr), DeathRegex);
55     return;
56   }
57 
58   // For recoverable, assert that TouchMemory() doesn't crash.
59   TouchMemory(Ptr);
60   // Fuchsia's zxtest doesn't have an EXPECT_THAT(testing::MatchesRegex(), ...),
61   // so check the regex manually.
62   EXPECT_TRUE(std::regex_search(
63       GetOutputBuffer(),
64       std::basic_regex(DeathRegex, std::regex_constants::extended)))
65       << "Regex \"" << DeathRegex
66       << "\" was not found in input:\n============\n"
67       << GetOutputBuffer() << "\n============";
68   ;
69 }
70 
71 INSTANTIATE_TEST_SUITE_P(RecoverableSignalDeathTest,
72                          BacktraceGuardedPoolAllocatorDeathTest,
73                          /* Recoverable */ testing::Bool());
74 
TEST(Backtrace,Short)75 TEST(Backtrace, Short) {
76   gwp_asan::AllocationMetadata Meta;
77   Meta.AllocationTrace.RecordBacktrace(
78       [](uintptr_t *TraceBuffer, size_t /* Size */) -> size_t {
79         TraceBuffer[0] = 123u;
80         TraceBuffer[1] = 321u;
81         return 2u;
82       });
83   uintptr_t TraceOutput[2] = {};
84   EXPECT_EQ(2u, __gwp_asan_get_allocation_trace(&Meta, TraceOutput, 2));
85   EXPECT_EQ(TraceOutput[0], 123u);
86   EXPECT_EQ(TraceOutput[1], 321u);
87 }
88 
TEST(Backtrace,ExceedsStorableLength)89 TEST(Backtrace, ExceedsStorableLength) {
90   gwp_asan::AllocationMetadata Meta;
91   Meta.AllocationTrace.RecordBacktrace(
92       [](uintptr_t *TraceBuffer, size_t Size) -> size_t {
93         // Need to inintialise the elements that will be packed.
94         memset(TraceBuffer, 0u, Size * sizeof(*TraceBuffer));
95 
96         // Indicate that there were more frames, and we just didn't have enough
97         // room to store them.
98         return Size * 2;
99       });
100   // Retrieve a frame from the collected backtrace, make sure it works E2E.
101   uintptr_t TraceOutput;
102   EXPECT_EQ(gwp_asan::AllocationMetadata::kMaxTraceLengthToCollect,
103             __gwp_asan_get_allocation_trace(&Meta, &TraceOutput, 1));
104 }
105 
TEST(Backtrace,ExceedsRetrievableAllocLength)106 TEST(Backtrace, ExceedsRetrievableAllocLength) {
107   gwp_asan::AllocationMetadata Meta;
108   constexpr size_t kNumFramesToStore = 3u;
109   Meta.AllocationTrace.RecordBacktrace(
110       [](uintptr_t *TraceBuffer, size_t /* Size */) -> size_t {
111         memset(TraceBuffer, kNumFramesToStore,
112                kNumFramesToStore * sizeof(*TraceBuffer));
113         return kNumFramesToStore;
114       });
115   uintptr_t TraceOutput;
116   // Ask for one element, get told that there's `kNumFramesToStore` available.
117   EXPECT_EQ(kNumFramesToStore,
118             __gwp_asan_get_allocation_trace(&Meta, &TraceOutput, 1));
119 }
120 
TEST(Backtrace,ExceedsRetrievableDeallocLength)121 TEST(Backtrace, ExceedsRetrievableDeallocLength) {
122   gwp_asan::AllocationMetadata Meta;
123   constexpr size_t kNumFramesToStore = 3u;
124   Meta.DeallocationTrace.RecordBacktrace(
125       [](uintptr_t *TraceBuffer, size_t /* Size */) -> size_t {
126         memset(TraceBuffer, kNumFramesToStore,
127                kNumFramesToStore * sizeof(*TraceBuffer));
128         return kNumFramesToStore;
129       });
130   uintptr_t TraceOutput;
131   // Ask for one element, get told that there's `kNumFramesToStore` available.
132   EXPECT_EQ(kNumFramesToStore,
133             __gwp_asan_get_deallocation_trace(&Meta, &TraceOutput, 1));
134 }
135