summaryrefslogtreecommitdiff
path: root/gwp_asan/tests/harness.h
blob: 3e859358c96bd507ca8dcedd7b97c0f1976f1e5f (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
//===-- 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;
#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_