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