xref: /openbsd-src/gnu/llvm/compiler-rt/lib/gwp_asan/tests/backtrace.cpp (revision 810390e339a5425391477d5d41c78d7cab2424ac)
13cab2bb3Spatrick //===-- backtrace.cpp -------------------------------------------*- C++ -*-===//
23cab2bb3Spatrick //
33cab2bb3Spatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
43cab2bb3Spatrick // See https://llvm.org/LICENSE.txt for license information.
53cab2bb3Spatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
63cab2bb3Spatrick //
73cab2bb3Spatrick //===----------------------------------------------------------------------===//
83cab2bb3Spatrick 
9*810390e3Srobert #include <regex>
103cab2bb3Spatrick #include <string>
113cab2bb3Spatrick 
12d89ec533Spatrick #include "gwp_asan/common.h"
131f9cb04fSpatrick #include "gwp_asan/crash_handler.h"
143cab2bb3Spatrick #include "gwp_asan/tests/harness.h"
153cab2bb3Spatrick 
TEST_P(BacktraceGuardedPoolAllocatorDeathTest,DoubleFree)16*810390e3Srobert TEST_P(BacktraceGuardedPoolAllocatorDeathTest, DoubleFree) {
171f9cb04fSpatrick   void *Ptr = AllocateMemory(GPA);
181f9cb04fSpatrick   DeallocateMemory(GPA, Ptr);
191f9cb04fSpatrick 
20*810390e3Srobert   std::string DeathRegex = "Double Free.*DeallocateMemory2.*";
21*810390e3Srobert   DeathRegex.append("was deallocated.*DeallocateMemory[^2].*");
22*810390e3Srobert   DeathRegex.append("was allocated.*AllocateMemory");
23*810390e3Srobert   if (!Recoverable) {
241f9cb04fSpatrick     ASSERT_DEATH(DeallocateMemory2(GPA, Ptr), DeathRegex);
25*810390e3Srobert     return;
263cab2bb3Spatrick   }
273cab2bb3Spatrick 
28*810390e3Srobert   // For recoverable, assert that DeallocateMemory2() doesn't crash.
29*810390e3Srobert   DeallocateMemory2(GPA, Ptr);
30*810390e3Srobert   // Fuchsia's zxtest doesn't have an EXPECT_THAT(testing::MatchesRegex(), ...),
31*810390e3Srobert   // so check the regex manually.
32*810390e3Srobert   EXPECT_TRUE(std::regex_search(
33*810390e3Srobert       GetOutputBuffer(),
34*810390e3Srobert       std::basic_regex(DeathRegex, std::regex_constants::extended)))
35*810390e3Srobert       << "Regex \"" << DeathRegex
36*810390e3Srobert       << "\" was not found in input:\n============\n"
37*810390e3Srobert       << GetOutputBuffer() << "\n============";
38*810390e3Srobert }
39*810390e3Srobert 
TEST_P(BacktraceGuardedPoolAllocatorDeathTest,UseAfterFree)40*810390e3Srobert TEST_P(BacktraceGuardedPoolAllocatorDeathTest, UseAfterFree) {
41d89ec533Spatrick #if defined(__linux__) && __ARM_ARCH == 7
42d89ec533Spatrick   // Incomplete backtrace on Armv7 Linux
43d89ec533Spatrick   GTEST_SKIP();
44d89ec533Spatrick #endif
45d89ec533Spatrick 
461f9cb04fSpatrick   void *Ptr = AllocateMemory(GPA);
471f9cb04fSpatrick   DeallocateMemory(GPA, Ptr);
483cab2bb3Spatrick 
49*810390e3Srobert   std::string DeathRegex = "Use After Free.*TouchMemory.*";
50*810390e3Srobert   DeathRegex.append("was deallocated.*DeallocateMemory[^2].*");
51*810390e3Srobert   DeathRegex.append("was allocated.*AllocateMemory");
523cab2bb3Spatrick 
53*810390e3Srobert   if (!Recoverable) {
541f9cb04fSpatrick     ASSERT_DEATH(TouchMemory(Ptr), DeathRegex);
55*810390e3Srobert     return;
561f9cb04fSpatrick   }
571f9cb04fSpatrick 
58*810390e3Srobert   // For recoverable, assert that TouchMemory() doesn't crash.
59*810390e3Srobert   TouchMemory(Ptr);
60*810390e3Srobert   // Fuchsia's zxtest doesn't have an EXPECT_THAT(testing::MatchesRegex(), ...),
61*810390e3Srobert   // so check the regex manually.
62*810390e3Srobert   EXPECT_TRUE(std::regex_search(
63*810390e3Srobert       GetOutputBuffer(),
64*810390e3Srobert       std::basic_regex(DeathRegex, std::regex_constants::extended)))
65*810390e3Srobert       << "Regex \"" << DeathRegex
66*810390e3Srobert       << "\" was not found in input:\n============\n"
67*810390e3Srobert       << GetOutputBuffer() << "\n============";
68*810390e3Srobert   ;
69*810390e3Srobert }
70*810390e3Srobert 
71*810390e3Srobert INSTANTIATE_TEST_SUITE_P(RecoverableSignalDeathTest,
72*810390e3Srobert                          BacktraceGuardedPoolAllocatorDeathTest,
73*810390e3Srobert                          /* Recoverable */ testing::Bool());
74*810390e3Srobert 
TEST(Backtrace,Short)751f9cb04fSpatrick TEST(Backtrace, Short) {
761f9cb04fSpatrick   gwp_asan::AllocationMetadata Meta;
771f9cb04fSpatrick   Meta.AllocationTrace.RecordBacktrace(
781f9cb04fSpatrick       [](uintptr_t *TraceBuffer, size_t /* Size */) -> size_t {
791f9cb04fSpatrick         TraceBuffer[0] = 123u;
801f9cb04fSpatrick         TraceBuffer[1] = 321u;
811f9cb04fSpatrick         return 2u;
821f9cb04fSpatrick       });
831f9cb04fSpatrick   uintptr_t TraceOutput[2] = {};
841f9cb04fSpatrick   EXPECT_EQ(2u, __gwp_asan_get_allocation_trace(&Meta, TraceOutput, 2));
851f9cb04fSpatrick   EXPECT_EQ(TraceOutput[0], 123u);
861f9cb04fSpatrick   EXPECT_EQ(TraceOutput[1], 321u);
871f9cb04fSpatrick }
881f9cb04fSpatrick 
TEST(Backtrace,ExceedsStorableLength)891f9cb04fSpatrick TEST(Backtrace, ExceedsStorableLength) {
901f9cb04fSpatrick   gwp_asan::AllocationMetadata Meta;
911f9cb04fSpatrick   Meta.AllocationTrace.RecordBacktrace(
92d89ec533Spatrick       [](uintptr_t *TraceBuffer, size_t Size) -> size_t {
93d89ec533Spatrick         // Need to inintialise the elements that will be packed.
94d89ec533Spatrick         memset(TraceBuffer, 0u, Size * sizeof(*TraceBuffer));
95d89ec533Spatrick 
96d89ec533Spatrick         // Indicate that there were more frames, and we just didn't have enough
97d89ec533Spatrick         // room to store them.
98d89ec533Spatrick         return Size * 2;
99d89ec533Spatrick       });
100d89ec533Spatrick   // Retrieve a frame from the collected backtrace, make sure it works E2E.
101d89ec533Spatrick   uintptr_t TraceOutput;
102d89ec533Spatrick   EXPECT_EQ(gwp_asan::AllocationMetadata::kMaxTraceLengthToCollect,
103d89ec533Spatrick             __gwp_asan_get_allocation_trace(&Meta, &TraceOutput, 1));
104d89ec533Spatrick }
105d89ec533Spatrick 
TEST(Backtrace,ExceedsRetrievableAllocLength)106d89ec533Spatrick TEST(Backtrace, ExceedsRetrievableAllocLength) {
107d89ec533Spatrick   gwp_asan::AllocationMetadata Meta;
108d89ec533Spatrick   constexpr size_t kNumFramesToStore = 3u;
109d89ec533Spatrick   Meta.AllocationTrace.RecordBacktrace(
110d89ec533Spatrick       [](uintptr_t *TraceBuffer, size_t /* Size */) -> size_t {
111d89ec533Spatrick         memset(TraceBuffer, kNumFramesToStore,
112d89ec533Spatrick                kNumFramesToStore * sizeof(*TraceBuffer));
113d89ec533Spatrick         return kNumFramesToStore;
1141f9cb04fSpatrick       });
1151f9cb04fSpatrick   uintptr_t TraceOutput;
116d89ec533Spatrick   // Ask for one element, get told that there's `kNumFramesToStore` available.
117d89ec533Spatrick   EXPECT_EQ(kNumFramesToStore,
118d89ec533Spatrick             __gwp_asan_get_allocation_trace(&Meta, &TraceOutput, 1));
119d89ec533Spatrick }
120d89ec533Spatrick 
TEST(Backtrace,ExceedsRetrievableDeallocLength)121d89ec533Spatrick TEST(Backtrace, ExceedsRetrievableDeallocLength) {
122d89ec533Spatrick   gwp_asan::AllocationMetadata Meta;
123d89ec533Spatrick   constexpr size_t kNumFramesToStore = 3u;
124d89ec533Spatrick   Meta.DeallocationTrace.RecordBacktrace(
125d89ec533Spatrick       [](uintptr_t *TraceBuffer, size_t /* Size */) -> size_t {
126d89ec533Spatrick         memset(TraceBuffer, kNumFramesToStore,
127d89ec533Spatrick                kNumFramesToStore * sizeof(*TraceBuffer));
128d89ec533Spatrick         return kNumFramesToStore;
129d89ec533Spatrick       });
130d89ec533Spatrick   uintptr_t TraceOutput;
131d89ec533Spatrick   // Ask for one element, get told that there's `kNumFramesToStore` available.
132d89ec533Spatrick   EXPECT_EQ(kNumFramesToStore,
133d89ec533Spatrick             __gwp_asan_get_deallocation_trace(&Meta, &TraceOutput, 1));
1343cab2bb3Spatrick }
135