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 <string>
10
11 #include "gwp_asan/common.h"
12 #include "gwp_asan/crash_handler.h"
13 #include "gwp_asan/tests/harness.h"
14
15 // Optnone to ensure that the calls to these functions are not optimized away,
16 // as we're looking for them in the backtraces.
17 __attribute((optnone)) void *
AllocateMemory(gwp_asan::GuardedPoolAllocator & GPA)18 AllocateMemory(gwp_asan::GuardedPoolAllocator &GPA) {
19 return GPA.allocate(1);
20 }
21 __attribute((optnone)) void
DeallocateMemory(gwp_asan::GuardedPoolAllocator & GPA,void * Ptr)22 DeallocateMemory(gwp_asan::GuardedPoolAllocator &GPA, void *Ptr) {
23 GPA.deallocate(Ptr);
24 }
25 __attribute((optnone)) void
DeallocateMemory2(gwp_asan::GuardedPoolAllocator & GPA,void * Ptr)26 DeallocateMemory2(gwp_asan::GuardedPoolAllocator &GPA, void *Ptr) {
27 GPA.deallocate(Ptr);
28 }
TouchMemory(void * Ptr)29 __attribute__((optnone)) void TouchMemory(void *Ptr) {
30 *(reinterpret_cast<volatile char *>(Ptr)) = 7;
31 }
32
TEST_F(BacktraceGuardedPoolAllocatorDeathTest,DoubleFree)33 TEST_F(BacktraceGuardedPoolAllocatorDeathTest, DoubleFree) {
34 void *Ptr = AllocateMemory(GPA);
35 DeallocateMemory(GPA, Ptr);
36
37 std::string DeathRegex = "Double Free.*";
38 DeathRegex.append("DeallocateMemory2.*");
39
40 DeathRegex.append("was deallocated.*");
41 DeathRegex.append("DeallocateMemory.*");
42
43 DeathRegex.append("was allocated.*");
44 DeathRegex.append("AllocateMemory.*");
45 ASSERT_DEATH(DeallocateMemory2(GPA, Ptr), DeathRegex);
46 }
47
TEST_F(BacktraceGuardedPoolAllocatorDeathTest,UseAfterFree)48 TEST_F(BacktraceGuardedPoolAllocatorDeathTest, UseAfterFree) {
49 #if defined(__linux__) && __ARM_ARCH == 7
50 // Incomplete backtrace on Armv7 Linux
51 GTEST_SKIP();
52 #endif
53
54 void *Ptr = AllocateMemory(GPA);
55 DeallocateMemory(GPA, Ptr);
56
57 std::string DeathRegex = "Use After Free.*";
58 DeathRegex.append("TouchMemory.*");
59
60 DeathRegex.append("was deallocated.*");
61 DeathRegex.append("DeallocateMemory.*");
62
63 DeathRegex.append("was allocated.*");
64 DeathRegex.append("AllocateMemory.*");
65 ASSERT_DEATH(TouchMemory(Ptr), DeathRegex);
66 }
67
TEST(Backtrace,Short)68 TEST(Backtrace, Short) {
69 gwp_asan::AllocationMetadata Meta;
70 Meta.AllocationTrace.RecordBacktrace(
71 [](uintptr_t *TraceBuffer, size_t /* Size */) -> size_t {
72 TraceBuffer[0] = 123u;
73 TraceBuffer[1] = 321u;
74 return 2u;
75 });
76 uintptr_t TraceOutput[2] = {};
77 EXPECT_EQ(2u, __gwp_asan_get_allocation_trace(&Meta, TraceOutput, 2));
78 EXPECT_EQ(TraceOutput[0], 123u);
79 EXPECT_EQ(TraceOutput[1], 321u);
80 }
81
TEST(Backtrace,ExceedsStorableLength)82 TEST(Backtrace, ExceedsStorableLength) {
83 gwp_asan::AllocationMetadata Meta;
84 Meta.AllocationTrace.RecordBacktrace(
85 [](uintptr_t *TraceBuffer, size_t Size) -> size_t {
86 // Need to inintialise the elements that will be packed.
87 memset(TraceBuffer, 0u, Size * sizeof(*TraceBuffer));
88
89 // Indicate that there were more frames, and we just didn't have enough
90 // room to store them.
91 return Size * 2;
92 });
93 // Retrieve a frame from the collected backtrace, make sure it works E2E.
94 uintptr_t TraceOutput;
95 EXPECT_EQ(gwp_asan::AllocationMetadata::kMaxTraceLengthToCollect,
96 __gwp_asan_get_allocation_trace(&Meta, &TraceOutput, 1));
97 }
98
TEST(Backtrace,ExceedsRetrievableAllocLength)99 TEST(Backtrace, ExceedsRetrievableAllocLength) {
100 gwp_asan::AllocationMetadata Meta;
101 constexpr size_t kNumFramesToStore = 3u;
102 Meta.AllocationTrace.RecordBacktrace(
103 [](uintptr_t *TraceBuffer, size_t /* Size */) -> size_t {
104 memset(TraceBuffer, kNumFramesToStore,
105 kNumFramesToStore * sizeof(*TraceBuffer));
106 return kNumFramesToStore;
107 });
108 uintptr_t TraceOutput;
109 // Ask for one element, get told that there's `kNumFramesToStore` available.
110 EXPECT_EQ(kNumFramesToStore,
111 __gwp_asan_get_allocation_trace(&Meta, &TraceOutput, 1));
112 }
113
TEST(Backtrace,ExceedsRetrievableDeallocLength)114 TEST(Backtrace, ExceedsRetrievableDeallocLength) {
115 gwp_asan::AllocationMetadata Meta;
116 constexpr size_t kNumFramesToStore = 3u;
117 Meta.DeallocationTrace.RecordBacktrace(
118 [](uintptr_t *TraceBuffer, size_t /* Size */) -> size_t {
119 memset(TraceBuffer, kNumFramesToStore,
120 kNumFramesToStore * sizeof(*TraceBuffer));
121 return kNumFramesToStore;
122 });
123 uintptr_t TraceOutput;
124 // Ask for one element, get told that there's `kNumFramesToStore` available.
125 EXPECT_EQ(kNumFramesToStore,
126 __gwp_asan_get_deallocation_trace(&Meta, &TraceOutput, 1));
127 }
128