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 
asan_write_sized_aligned(uint8_t * p,size_t size)14 NOINLINE 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 
22 template<typename T>
oob_test(int size,int off)23 NOINLINE 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 
GetLeftOOBMessage(int off)31 static std::string GetLeftOOBMessage(int off) {
32   char str[100];
33   sprintf(str, "is located.*%d byte.*to the left", off);
34   return str;
35 }
36 
GetRightOOBMessage(int off)37 static std::string GetRightOOBMessage(int off) {
38   char str[100];
39 #if !defined(_WIN32)
40   // FIXME: Fix PR42868 and remove SEGV match.
41   sprintf(str, "is located.*%d byte.*to the right|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.*to the right", off);
47 #endif
48   return str;
49 }
50 
51 template<typename T>
OOBTest()52 void 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 
TEST(AddressSanitizer,OOB_char)78 TEST(AddressSanitizer, OOB_char) {
79   OOBTest<U1>();
80 }
81 
TEST(AddressSanitizer,OOB_int)82 TEST(AddressSanitizer, OOB_int) {
83   OOBTest<U4>();
84 }
85 
TEST(AddressSanitizer,OOBRightTest)86 TEST(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(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(addr, 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(p);
104       }
105     }
106   }
107 }
108 
TEST(AddressSanitizer,LargeOOBRightTest)109 TEST(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 
TEST(AddressSanitizer,DISABLED_DemoOOBLeftLow)119 TEST(AddressSanitizer, DISABLED_DemoOOBLeftLow) {
120   oob_test<U1>(10, -1);
121 }
122 
TEST(AddressSanitizer,DISABLED_DemoOOBLeftHigh)123 TEST(AddressSanitizer, DISABLED_DemoOOBLeftHigh) {
124   oob_test<U1>(kLargeMalloc, -1);
125 }
126 
TEST(AddressSanitizer,DISABLED_DemoOOBRightLow)127 TEST(AddressSanitizer, DISABLED_DemoOOBRightLow) {
128   oob_test<U1>(10, 10);
129 }
130 
TEST(AddressSanitizer,DISABLED_DemoOOBRightHigh)131 TEST(AddressSanitizer, DISABLED_DemoOOBRightHigh) {
132   oob_test<U1>(kLargeMalloc, kLargeMalloc);
133 }
134