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(BacktraceGuardedPoolAllocator, 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(BacktraceGuardedPoolAllocator, UseAfterFree) { 49 void *Ptr = AllocateMemory(GPA); 50 DeallocateMemory(GPA, Ptr); 51 52 std::string DeathRegex = "Use After Free.*"; 53 DeathRegex.append("TouchMemory.*"); 54 55 DeathRegex.append("was deallocated.*"); 56 DeathRegex.append("DeallocateMemory.*"); 57 58 DeathRegex.append("was allocated.*"); 59 DeathRegex.append("AllocateMemory.*"); 60 ASSERT_DEATH(TouchMemory(Ptr), DeathRegex); 61 } 62 63 TEST(Backtrace, Short) { 64 gwp_asan::AllocationMetadata Meta; 65 Meta.AllocationTrace.RecordBacktrace( 66 [](uintptr_t *TraceBuffer, size_t /* Size */) -> size_t { 67 TraceBuffer[0] = 123u; 68 TraceBuffer[1] = 321u; 69 return 2u; 70 }); 71 uintptr_t TraceOutput[2] = {}; 72 EXPECT_EQ(2u, __gwp_asan_get_allocation_trace(&Meta, TraceOutput, 2)); 73 EXPECT_EQ(TraceOutput[0], 123u); 74 EXPECT_EQ(TraceOutput[1], 321u); 75 } 76 77 TEST(Backtrace, ExceedsStorableLength) { 78 gwp_asan::AllocationMetadata Meta; 79 Meta.AllocationTrace.RecordBacktrace( 80 [](uintptr_t *TraceBuffer, size_t Size) -> size_t { 81 // Need to inintialise the elements that will be packed. 82 memset(TraceBuffer, 0u, Size * sizeof(*TraceBuffer)); 83 84 // Indicate that there were more frames, and we just didn't have enough 85 // room to store them. 86 return Size * 2; 87 }); 88 // Retrieve a frame from the collected backtrace, make sure it works E2E. 89 uintptr_t TraceOutput; 90 EXPECT_EQ(gwp_asan::AllocationMetadata::kMaxTraceLengthToCollect, 91 __gwp_asan_get_allocation_trace(&Meta, &TraceOutput, 1)); 92 } 93 94 TEST(Backtrace, ExceedsRetrievableAllocLength) { 95 gwp_asan::AllocationMetadata Meta; 96 constexpr size_t kNumFramesToStore = 3u; 97 Meta.AllocationTrace.RecordBacktrace( 98 [](uintptr_t *TraceBuffer, size_t /* Size */) -> size_t { 99 memset(TraceBuffer, kNumFramesToStore, 100 kNumFramesToStore * sizeof(*TraceBuffer)); 101 return kNumFramesToStore; 102 }); 103 uintptr_t TraceOutput; 104 // Ask for one element, get told that there's `kNumFramesToStore` available. 105 EXPECT_EQ(kNumFramesToStore, 106 __gwp_asan_get_allocation_trace(&Meta, &TraceOutput, 1)); 107 } 108 109 TEST(Backtrace, ExceedsRetrievableDeallocLength) { 110 gwp_asan::AllocationMetadata Meta; 111 constexpr size_t kNumFramesToStore = 3u; 112 Meta.DeallocationTrace.RecordBacktrace( 113 [](uintptr_t *TraceBuffer, size_t /* Size */) -> size_t { 114 memset(TraceBuffer, kNumFramesToStore, 115 kNumFramesToStore * sizeof(*TraceBuffer)); 116 return kNumFramesToStore; 117 }); 118 uintptr_t TraceOutput; 119 // Ask for one element, get told that there's `kNumFramesToStore` available. 120 EXPECT_EQ(kNumFramesToStore, 121 __gwp_asan_get_deallocation_trace(&Meta, &TraceOutput, 1)); 122 } 123