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