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