xref: /llvm-project/compiler-rt/lib/gwp_asan/tests/backtrace.cpp (revision 43ba32109657b697c6dd31a30563a66dade5f254)
14a1a113aSNico Weber //===-- backtrace.cpp -------------------------------------------*- C++ -*-===//
27339ca27SMitch Phillips //
37339ca27SMitch Phillips // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
47339ca27SMitch Phillips // See https://llvm.org/LICENSE.txt for license information.
57339ca27SMitch Phillips // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
67339ca27SMitch Phillips //
77339ca27SMitch Phillips //===----------------------------------------------------------------------===//
87339ca27SMitch Phillips 
935b5499dSMitch Phillips #include <regex>
107339ca27SMitch Phillips #include <string>
117339ca27SMitch Phillips 
12d19af2f2SMitch Phillips #include "gwp_asan/common.h"
13a4e8d897SMitch Phillips #include "gwp_asan/crash_handler.h"
147339ca27SMitch Phillips #include "gwp_asan/tests/harness.h"
157339ca27SMitch Phillips 
TEST_P(BacktraceGuardedPoolAllocatorDeathTest,DoubleFree)1635b5499dSMitch Phillips TEST_P(BacktraceGuardedPoolAllocatorDeathTest, DoubleFree) {
171216f4c0SMitch Phillips   void *Ptr = AllocateMemory(GPA);
181216f4c0SMitch Phillips   DeallocateMemory(GPA, Ptr);
197339ca27SMitch Phillips 
2035b5499dSMitch Phillips   std::string DeathRegex = "Double Free.*DeallocateMemory2.*";
2135b5499dSMitch Phillips   DeathRegex.append("was deallocated.*DeallocateMemory[^2].*");
2235b5499dSMitch Phillips   DeathRegex.append("was allocated.*AllocateMemory");
2335b5499dSMitch Phillips   if (!Recoverable) {
24*43ba3210SCaslyn Tonelli     EXPECT_DEATH(DeallocateMemory2(GPA, Ptr), DeathRegex);
2535b5499dSMitch Phillips     return;
267339ca27SMitch Phillips   }
277339ca27SMitch Phillips 
2835b5499dSMitch Phillips   // For recoverable, assert that DeallocateMemory2() doesn't crash.
2935b5499dSMitch Phillips   DeallocateMemory2(GPA, Ptr);
3035b5499dSMitch Phillips   // Fuchsia's zxtest doesn't have an EXPECT_THAT(testing::MatchesRegex(), ...),
3135b5499dSMitch Phillips   // so check the regex manually.
3235b5499dSMitch Phillips   EXPECT_TRUE(std::regex_search(
3335b5499dSMitch Phillips       GetOutputBuffer(),
3435b5499dSMitch Phillips       std::basic_regex(DeathRegex, std::regex_constants::extended)))
3535b5499dSMitch Phillips       << "Regex \"" << DeathRegex
3635b5499dSMitch Phillips       << "\" was not found in input:\n============\n"
3735b5499dSMitch Phillips       << GetOutputBuffer() << "\n============";
3835b5499dSMitch Phillips }
3935b5499dSMitch Phillips 
TEST_P(BacktraceGuardedPoolAllocatorDeathTest,UseAfterFree)4035b5499dSMitch Phillips TEST_P(BacktraceGuardedPoolAllocatorDeathTest, UseAfterFree) {
41f58a1f65SAlexander Belyaev #if defined(__linux__) && __ARM_ARCH == 7
423d5c1a81SDavid Spickett   // Incomplete backtrace on Armv7 Linux
433d5c1a81SDavid Spickett   GTEST_SKIP();
443d5c1a81SDavid Spickett #endif
453d5c1a81SDavid Spickett 
461216f4c0SMitch Phillips   void *Ptr = AllocateMemory(GPA);
471216f4c0SMitch Phillips   DeallocateMemory(GPA, Ptr);
487339ca27SMitch Phillips 
4935b5499dSMitch Phillips   std::string DeathRegex = "Use After Free.*TouchMemory.*";
5035b5499dSMitch Phillips   DeathRegex.append("was deallocated.*DeallocateMemory[^2].*");
5135b5499dSMitch Phillips   DeathRegex.append("was allocated.*AllocateMemory");
527339ca27SMitch Phillips 
5335b5499dSMitch Phillips   if (!Recoverable) {
54*43ba3210SCaslyn Tonelli     EXPECT_DEATH(TouchMemory(Ptr), DeathRegex);
5535b5499dSMitch Phillips     return;
567339ca27SMitch Phillips   }
57a4e8d897SMitch Phillips 
5835b5499dSMitch Phillips   // For recoverable, assert that TouchMemory() doesn't crash.
5935b5499dSMitch Phillips   TouchMemory(Ptr);
6035b5499dSMitch Phillips   // Fuchsia's zxtest doesn't have an EXPECT_THAT(testing::MatchesRegex(), ...),
6135b5499dSMitch Phillips   // so check the regex manually.
6235b5499dSMitch Phillips   EXPECT_TRUE(std::regex_search(
6335b5499dSMitch Phillips       GetOutputBuffer(),
6435b5499dSMitch Phillips       std::basic_regex(DeathRegex, std::regex_constants::extended)))
6535b5499dSMitch Phillips       << "Regex \"" << DeathRegex
6635b5499dSMitch Phillips       << "\" was not found in input:\n============\n"
6735b5499dSMitch Phillips       << GetOutputBuffer() << "\n============";
6835b5499dSMitch Phillips   ;
6935b5499dSMitch Phillips }
7035b5499dSMitch Phillips 
TEST(Backtrace,Short)71a4e8d897SMitch Phillips TEST(Backtrace, Short) {
72a4e8d897SMitch Phillips   gwp_asan::AllocationMetadata Meta;
73a4e8d897SMitch Phillips   Meta.AllocationTrace.RecordBacktrace(
74a4e8d897SMitch Phillips       [](uintptr_t *TraceBuffer, size_t /* Size */) -> size_t {
75a4e8d897SMitch Phillips         TraceBuffer[0] = 123u;
76a4e8d897SMitch Phillips         TraceBuffer[1] = 321u;
77a4e8d897SMitch Phillips         return 2u;
78a4e8d897SMitch Phillips       });
79a4e8d897SMitch Phillips   uintptr_t TraceOutput[2] = {};
80a4e8d897SMitch Phillips   EXPECT_EQ(2u, __gwp_asan_get_allocation_trace(&Meta, TraceOutput, 2));
81a4e8d897SMitch Phillips   EXPECT_EQ(TraceOutput[0], 123u);
82a4e8d897SMitch Phillips   EXPECT_EQ(TraceOutput[1], 321u);
83a4e8d897SMitch Phillips }
84a4e8d897SMitch Phillips 
TEST(Backtrace,ExceedsStorableLength)85a4e8d897SMitch Phillips TEST(Backtrace, ExceedsStorableLength) {
86a4e8d897SMitch Phillips   gwp_asan::AllocationMetadata Meta;
87a4e8d897SMitch Phillips   Meta.AllocationTrace.RecordBacktrace(
88d19af2f2SMitch Phillips       [](uintptr_t *TraceBuffer, size_t Size) -> size_t {
89d19af2f2SMitch Phillips         // Need to inintialise the elements that will be packed.
90d19af2f2SMitch Phillips         memset(TraceBuffer, 0u, Size * sizeof(*TraceBuffer));
91d19af2f2SMitch Phillips 
92d19af2f2SMitch Phillips         // Indicate that there were more frames, and we just didn't have enough
93d19af2f2SMitch Phillips         // room to store them.
94d19af2f2SMitch Phillips         return Size * 2;
95d19af2f2SMitch Phillips       });
96d19af2f2SMitch Phillips   // Retrieve a frame from the collected backtrace, make sure it works E2E.
97d19af2f2SMitch Phillips   uintptr_t TraceOutput;
98d19af2f2SMitch Phillips   EXPECT_EQ(gwp_asan::AllocationMetadata::kMaxTraceLengthToCollect,
99d19af2f2SMitch Phillips             __gwp_asan_get_allocation_trace(&Meta, &TraceOutput, 1));
100d19af2f2SMitch Phillips }
101d19af2f2SMitch Phillips 
TEST(Backtrace,ExceedsRetrievableAllocLength)102d19af2f2SMitch Phillips TEST(Backtrace, ExceedsRetrievableAllocLength) {
103d19af2f2SMitch Phillips   gwp_asan::AllocationMetadata Meta;
104d19af2f2SMitch Phillips   constexpr size_t kNumFramesToStore = 3u;
105d19af2f2SMitch Phillips   Meta.AllocationTrace.RecordBacktrace(
106d19af2f2SMitch Phillips       [](uintptr_t *TraceBuffer, size_t /* Size */) -> size_t {
107d19af2f2SMitch Phillips         memset(TraceBuffer, kNumFramesToStore,
108d19af2f2SMitch Phillips                kNumFramesToStore * sizeof(*TraceBuffer));
109d19af2f2SMitch Phillips         return kNumFramesToStore;
110a4e8d897SMitch Phillips       });
111a4e8d897SMitch Phillips   uintptr_t TraceOutput;
112d19af2f2SMitch Phillips   // Ask for one element, get told that there's `kNumFramesToStore` available.
113d19af2f2SMitch Phillips   EXPECT_EQ(kNumFramesToStore,
114d19af2f2SMitch Phillips             __gwp_asan_get_allocation_trace(&Meta, &TraceOutput, 1));
115d19af2f2SMitch Phillips }
116d19af2f2SMitch Phillips 
TEST(Backtrace,ExceedsRetrievableDeallocLength)117d19af2f2SMitch Phillips TEST(Backtrace, ExceedsRetrievableDeallocLength) {
118d19af2f2SMitch Phillips   gwp_asan::AllocationMetadata Meta;
119d19af2f2SMitch Phillips   constexpr size_t kNumFramesToStore = 3u;
120d19af2f2SMitch Phillips   Meta.DeallocationTrace.RecordBacktrace(
121d19af2f2SMitch Phillips       [](uintptr_t *TraceBuffer, size_t /* Size */) -> size_t {
122d19af2f2SMitch Phillips         memset(TraceBuffer, kNumFramesToStore,
123d19af2f2SMitch Phillips                kNumFramesToStore * sizeof(*TraceBuffer));
124d19af2f2SMitch Phillips         return kNumFramesToStore;
125d19af2f2SMitch Phillips       });
126d19af2f2SMitch Phillips   uintptr_t TraceOutput;
127d19af2f2SMitch Phillips   // Ask for one element, get told that there's `kNumFramesToStore` available.
128d19af2f2SMitch Phillips   EXPECT_EQ(kNumFramesToStore,
129d19af2f2SMitch Phillips             __gwp_asan_get_deallocation_trace(&Meta, &TraceOutput, 1));
130a4e8d897SMitch Phillips }
131