131 lines · cpp
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-exception6//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 16TEST_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 EXPECT_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 \"" << DeathRegex36 << "\" was not found in input:\n============\n"37 << GetOutputBuffer() << "\n============";38}39 40TEST_P(BacktraceGuardedPoolAllocatorDeathTest, UseAfterFree) {41#if defined(__linux__) && __ARM_ARCH == 742 // Incomplete backtrace on Armv7 Linux43 GTEST_SKIP();44#endif45 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 EXPECT_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 \"" << DeathRegex66 << "\" was not found in input:\n============\n"67 << GetOutputBuffer() << "\n============";68 ;69}70 71TEST(Backtrace, Short) {72 gwp_asan::AllocationMetadata Meta;73 Meta.AllocationTrace.RecordBacktrace(74 [](uintptr_t *TraceBuffer, size_t /* Size */) -> size_t {75 TraceBuffer[0] = 123u;76 TraceBuffer[1] = 321u;77 return 2u;78 });79 uintptr_t TraceOutput[2] = {};80 EXPECT_EQ(2u, __gwp_asan_get_allocation_trace(&Meta, TraceOutput, 2));81 EXPECT_EQ(TraceOutput[0], 123u);82 EXPECT_EQ(TraceOutput[1], 321u);83}84 85TEST(Backtrace, ExceedsStorableLength) {86 gwp_asan::AllocationMetadata Meta;87 Meta.AllocationTrace.RecordBacktrace(88 [](uintptr_t *TraceBuffer, size_t Size) -> size_t {89 // Need to inintialise the elements that will be packed.90 memset(TraceBuffer, 0u, Size * sizeof(*TraceBuffer));91 92 // Indicate that there were more frames, and we just didn't have enough93 // room to store them.94 return Size * 2;95 });96 // Retrieve a frame from the collected backtrace, make sure it works E2E.97 uintptr_t TraceOutput;98 EXPECT_EQ(gwp_asan::AllocationMetadata::kMaxTraceLengthToCollect,99 __gwp_asan_get_allocation_trace(&Meta, &TraceOutput, 1));100}101 102TEST(Backtrace, ExceedsRetrievableAllocLength) {103 gwp_asan::AllocationMetadata Meta;104 constexpr size_t kNumFramesToStore = 3u;105 Meta.AllocationTrace.RecordBacktrace(106 [](uintptr_t *TraceBuffer, size_t /* Size */) -> size_t {107 memset(TraceBuffer, kNumFramesToStore,108 kNumFramesToStore * sizeof(*TraceBuffer));109 return kNumFramesToStore;110 });111 uintptr_t TraceOutput;112 // Ask for one element, get told that there's `kNumFramesToStore` available.113 EXPECT_EQ(kNumFramesToStore,114 __gwp_asan_get_allocation_trace(&Meta, &TraceOutput, 1));115}116 117TEST(Backtrace, ExceedsRetrievableDeallocLength) {118 gwp_asan::AllocationMetadata Meta;119 constexpr size_t kNumFramesToStore = 3u;120 Meta.DeallocationTrace.RecordBacktrace(121 [](uintptr_t *TraceBuffer, size_t /* Size */) -> size_t {122 memset(TraceBuffer, kNumFramesToStore,123 kNumFramesToStore * sizeof(*TraceBuffer));124 return kNumFramesToStore;125 });126 uintptr_t TraceOutput;127 // Ask for one element, get told that there's `kNumFramesToStore` available.128 EXPECT_EQ(kNumFramesToStore,129 __gwp_asan_get_deallocation_trace(&Meta, &TraceOutput, 1));130}131