xref: /openbsd-src/gnu/llvm/compiler-rt/lib/gwp_asan/tests/backtrace.cpp (revision 5a38ef86d0b61900239c7913d24a05e7b88a58f0)
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 *
18 AllocateMemory(gwp_asan::GuardedPoolAllocator &GPA) {
19   return GPA.allocate(1);
20 }
21 __attribute((optnone)) void
22 DeallocateMemory(gwp_asan::GuardedPoolAllocator &GPA, void *Ptr) {
23   GPA.deallocate(Ptr);
24 }
25 __attribute((optnone)) void
26 DeallocateMemory2(gwp_asan::GuardedPoolAllocator &GPA, void *Ptr) {
27   GPA.deallocate(Ptr);
28 }
29 __attribute__((optnone)) void TouchMemory(void *Ptr) {
30   *(reinterpret_cast<volatile char *>(Ptr)) = 7;
31 }
32 
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 
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 
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 
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 
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 
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