1//===-- asan_oob_test.cpp -------------------------------------------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8//
9// This file is a part of AddressSanitizer, an address sanity checker.
10//
11//===----------------------------------------------------------------------===//
12#include "asan_test_utils.h"
13
14NOINLINE void asan_write_sized_aligned(uint8_t *p, size_t size) {
15 EXPECT_EQ(0U, ((uintptr_t)p % size));
16 if (size == 1) asan_write((uint8_t*)p);
17 else if (size == 2) asan_write((uint16_t*)p);
18 else if (size == 4) asan_write((uint32_t*)p);
19 else if (size == 8) asan_write((uint64_t*)p);
20}
21
22template<typename T>
23NOINLINE void oob_test(int size, int off) {
24 char *p = (char*)malloc_aaa(size);
25 // fprintf(stderr, "writing %d byte(s) into [%p,%p) with offset %d\n",
26 // sizeof(T), p, p + size, off);
27 asan_write((T*)(p + off));
28 free_aaa(p);
29}
30
31static std::string GetLeftOOBMessage(int off) {
32 char str[100];
33 sprintf(s: str, format: "is located.*%d byte.*before", off);
34 return str;
35}
36
37static std::string GetRightOOBMessage(int off) {
38 char str[100];
39#if !defined(_WIN32)
40 // FIXME: Fix PR42868 and remove SEGV match.
41 sprintf(s: str, format: "is located.*%d byte.*after|SEGV", off);
42#else
43 // `|` doesn't work in googletest's regexes on Windows,
44 // see googletest/docs/advanced.md#regular-expression-syntax
45 // But it's not needed on Windows anyways.
46 sprintf(str, "is located.*%d byte.*after", off);
47#endif
48 return str;
49}
50
51template<typename T>
52void OOBTest() {
53 for (int size = sizeof(T); size < 20; size += 5) {
54 for (int i = -5; i < 0; i++)
55 EXPECT_DEATH(oob_test<T>(size, i), GetLeftOOBMessage(-i));
56
57 for (int i = 0; i < (int)(size - sizeof(T) + 1); i++)
58 oob_test<T>(size, i);
59
60 for (int i = size - sizeof(T) + 1; i <= (int)(size + 2 * sizeof(T)); i++) {
61 // we don't catch unaligned partially OOB accesses.
62 if (i % sizeof(T)) continue;
63 int off = i >= size ? (i - size) : 0;
64 EXPECT_DEATH(oob_test<T>(size, i), GetRightOOBMessage(off));
65 }
66 }
67
68 EXPECT_DEATH(oob_test<T>(kLargeMalloc, -1), GetLeftOOBMessage(1));
69 EXPECT_DEATH(oob_test<T>(kLargeMalloc, kLargeMalloc), GetRightOOBMessage(0));
70}
71
72// TODO(glider): the following tests are EXTREMELY slow on Darwin:
73// AddressSanitizer.OOB_char (125503 ms)
74// AddressSanitizer.OOB_int (126890 ms)
75// AddressSanitizer.OOBRightTest (315605 ms)
76// AddressSanitizer.SimpleStackTest (366559 ms)
77
78TEST(AddressSanitizer, OOB_char) {
79 OOBTest<U1>();
80}
81
82TEST(AddressSanitizer, OOB_int) {
83 OOBTest<U4>();
84}
85
86TEST(AddressSanitizer, OOBRightTest) {
87 size_t max_access_size = SANITIZER_WORDSIZE == 64 ? 8 : 4;
88 for (size_t access_size = 1; access_size <= max_access_size;
89 access_size *= 2) {
90 for (size_t alloc_size = 1; alloc_size <= 8; alloc_size++) {
91 for (size_t offset = 0; offset <= 8; offset += access_size) {
92 void *p = malloc(size: alloc_size);
93 // allocated: [p, p + alloc_size)
94 // accessed: [p + offset, p + offset + access_size)
95 uint8_t *addr = (uint8_t*)p + offset;
96 if (offset + access_size <= alloc_size) {
97 asan_write_sized_aligned(p: addr, size: access_size);
98 } else {
99 int outside_bytes = offset > alloc_size ? (offset - alloc_size) : 0;
100 EXPECT_DEATH(asan_write_sized_aligned(addr, access_size),
101 GetRightOOBMessage(outside_bytes));
102 }
103 free(ptr: p);
104 }
105 }
106 }
107}
108
109TEST(AddressSanitizer, LargeOOBRightTest) {
110 size_t large_power_of_two = 1 << 19;
111 for (size_t i = 16; i <= 256; i *= 2) {
112 size_t size = large_power_of_two - i;
113 char *p = Ident(new char[size]);
114 EXPECT_DEATH(p[size] = 0, GetRightOOBMessage(0));
115 delete [] p;
116 }
117}
118
119TEST(AddressSanitizer, DISABLED_DemoOOBLeftLow) {
120 oob_test<U1>(10, -1);
121}
122
123TEST(AddressSanitizer, DISABLED_DemoOOBLeftHigh) {
124 oob_test<U1>(kLargeMalloc, -1);
125}
126
127TEST(AddressSanitizer, DISABLED_DemoOOBRightLow) {
128 oob_test<U1>(10, 10);
129}
130
131TEST(AddressSanitizer, DISABLED_DemoOOBRightHigh) {
132 oob_test<U1>(kLargeMalloc, kLargeMalloc);
133}
134

source code of compiler-rt/lib/asan/tests/asan_oob_test.cpp