summaryrefslogtreecommitdiff
path: root/gwp_asan/tests/harness.h
blob: ae39a443bd0a090f75aaf76922e15a5889d70473 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
//===-- harness.h -----------------------------------------------*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//

#ifndef GWP_ASAN_TESTS_HARNESS_H_
#define GWP_ASAN_TESTS_HARNESS_H_

#include <stdarg.h>

#if defined(__Fuchsia__)
#define ZXTEST_USE_STREAMABLE_MACROS
#include <zxtest/zxtest.h>
namespace testing = zxtest;
// zxtest defines a different ASSERT_DEATH, taking a lambda and an error message
// if death didn't occur, versus gtest taking a statement and a string to search
// for in the dying process. zxtest doesn't define an EXPECT_DEATH, so we use
// that in the tests below (which works as intended for gtest), and we define
// EXPECT_DEATH as a wrapper for zxtest's ASSERT_DEATH. Note that zxtest drops
// the functionality for checking for a particular message in death.
#define EXPECT_DEATH(X, Y) ASSERT_DEATH(([&] { X; }), "")
#else
#include "gtest/gtest.h"
#endif

#include "gwp_asan/guarded_pool_allocator.h"
#include "gwp_asan/optional/backtrace.h"
#include "gwp_asan/optional/printf.h"
#include "gwp_asan/optional/segv_handler.h"
#include "gwp_asan/options.h"

namespace gwp_asan {
namespace test {
// This printf-function getter allows other platforms (e.g. Android) to define
// their own signal-safe Printf function. In LLVM, we use
// `optional/printf_sanitizer_common.cpp` which supplies the __sanitizer::Printf
// for this purpose.
Printf_t getPrintfFunction();

// First call returns true, all the following calls return false.
bool OnlyOnce();

}; // namespace test
}; // namespace gwp_asan

char *AllocateMemory(gwp_asan::GuardedPoolAllocator &GPA);
void DeallocateMemory(gwp_asan::GuardedPoolAllocator &GPA, void *Ptr);
void DeallocateMemory2(gwp_asan::GuardedPoolAllocator &GPA, void *Ptr);
void TouchMemory(void *Ptr);

void CheckOnlyOneGwpAsanCrash(const std::string &OutputBuffer);

class DefaultGuardedPoolAllocator : public ::testing::Test {
public:
  void SetUp() override {
    gwp_asan::options::Options Opts;
    Opts.setDefaults();
    MaxSimultaneousAllocations = Opts.MaxSimultaneousAllocations;

    Opts.InstallForkHandlers = gwp_asan::test::OnlyOnce();
    GPA.init(Opts);
  }

  void TearDown() override { GPA.uninitTestOnly(); }

protected:
  gwp_asan::GuardedPoolAllocator GPA;
  decltype(gwp_asan::options::Options::MaxSimultaneousAllocations)
      MaxSimultaneousAllocations;
};

class CustomGuardedPoolAllocator : public ::testing::Test {
public:
  void
  InitNumSlots(decltype(gwp_asan::options::Options::MaxSimultaneousAllocations)
                   MaxSimultaneousAllocationsArg) {
    gwp_asan::options::Options Opts;
    Opts.setDefaults();

    Opts.MaxSimultaneousAllocations = MaxSimultaneousAllocationsArg;
    MaxSimultaneousAllocations = MaxSimultaneousAllocationsArg;

    Opts.InstallForkHandlers = gwp_asan::test::OnlyOnce();
    GPA.init(Opts);
  }

  void TearDown() override { GPA.uninitTestOnly(); }

protected:
  gwp_asan::GuardedPoolAllocator GPA;
  decltype(gwp_asan::options::Options::MaxSimultaneousAllocations)
      MaxSimultaneousAllocations;
};

class BacktraceGuardedPoolAllocator
    : public ::testing::TestWithParam</* Recoverable */ bool> {
public:
  void SetUp() override {
    gwp_asan::options::Options Opts;
    Opts.setDefaults();

    Opts.Backtrace = gwp_asan::backtrace::getBacktraceFunction();
    Opts.InstallForkHandlers = gwp_asan::test::OnlyOnce();
    GPA.init(Opts);

    // In recoverable mode, capture GWP-ASan logs to an internal buffer so that
    // we can search it in unit tests. For non-recoverable tests, the default
    // buffer is fine, as any tests should be EXPECT_DEATH()'d.
    Recoverable = GetParam();
    gwp_asan::Printf_t PrintfFunction = PrintfToBuffer;
    GetOutputBuffer().clear();
    if (!Recoverable)
      PrintfFunction = gwp_asan::test::getPrintfFunction();

    gwp_asan::segv_handler::installSignalHandlers(
        &GPA, PrintfFunction, gwp_asan::backtrace::getPrintBacktraceFunction(),
        gwp_asan::backtrace::getSegvBacktraceFunction(),
        /* Recoverable */ Recoverable);
  }

  void TearDown() override {
    GPA.uninitTestOnly();
    gwp_asan::segv_handler::uninstallSignalHandlers();
  }

protected:
  static std::string &GetOutputBuffer() {
    static std::string Buffer;
    return Buffer;
  }

  __attribute__((format(printf, 1, 2))) static void
  PrintfToBuffer(const char *Format, ...) {
    va_list AP;
    va_start(AP, Format);
    char Buffer[8192];
    vsnprintf(Buffer, sizeof(Buffer), Format, AP);
    GetOutputBuffer() += Buffer;
    va_end(AP);
  }

  gwp_asan::GuardedPoolAllocator GPA;
  bool Recoverable;
};

// https://github.com/google/googletest/blob/master/docs/advanced.md#death-tests-and-threads
using DefaultGuardedPoolAllocatorDeathTest = DefaultGuardedPoolAllocator;
using CustomGuardedPoolAllocatorDeathTest = CustomGuardedPoolAllocator;
using BacktraceGuardedPoolAllocatorDeathTest = BacktraceGuardedPoolAllocator;

#endif // GWP_ASAN_TESTS_HARNESS_H_