//===-- asan_oob_test.cc --------------------------------------------------===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// // // This file is a part of AddressSanitizer, an address sanity checker. // //===----------------------------------------------------------------------===// #include <stdio.h> #include <gtest/gtest.h> #define NOINLINE __attribute__((noinline)) typedef uint8_t U1; typedef uint16_t U2; typedef uint32_t U4; typedef uint64_t U8; const size_t kLargeMalloc = 1 << 24; // Make the compiler thinks that something is going on there. inline void break_optimization(void *arg) { #if !defined(_WIN32) || defined(__clang__) __asm__ __volatile__("" : : "r" (arg) : "memory"); #endif } NOINLINE void *malloc_fff(size_t size) { void *res = malloc/**/(size); break_optimization(0); return res;} NOINLINE void *malloc_eee(size_t size) { void *res = malloc_fff(size); break_optimization(0); return res;} NOINLINE void *malloc_ddd(size_t size) { void *res = malloc_eee(size); break_optimization(0); return res;} NOINLINE void *malloc_ccc(size_t size) { void *res = malloc_ddd(size); break_optimization(0); return res;} NOINLINE void *malloc_bbb(size_t size) { void *res = malloc_ccc(size); break_optimization(0); return res;} NOINLINE void *malloc_aaa(size_t size) { void *res = malloc_bbb(size); break_optimization(0); return res;} NOINLINE void free_ccc(void *p) { free(p); break_optimization(0);} NOINLINE void free_bbb(void *p) { free_ccc(p); break_optimization(0);} NOINLINE void free_aaa(void *p) { free_bbb(p); break_optimization(0);} template<typename T> NOINLINE void asan_write(T *a) { *a = 0; } template<typename T> NOINLINE void oob_test(int size, int off) { char *p = (char*)malloc_aaa(size); // fprintf(stderr, "writing %d byte(s) into [%p,%p) with offset %d\n", // sizeof(T), p, p + size, off); asan_write((T*)(p + off)); free_aaa(p); } template<typename T> void OOBTest() { char expected_str[100]; for (int size = sizeof(T); size < 20; size += 5) { for (int i = -5; i < 0; i++) { const char *str = "is located.*%d byte.*to the left"; sprintf(expected_str, str, abs(i)); EXPECT_DEATH(oob_test<T>(size, i), expected_str); } for (int i = 0; i < (int)(size - sizeof(T) + 1); i++) oob_test<T>(size, i); for (int i = size - sizeof(T) + 1; i <= (int)(size + 2 * sizeof(T)); i++) { const char *str = "is located.*%d byte.*to the right"; int off = i >= size ? (i - size) : 0; // we don't catch unaligned partially OOB accesses. if (i % sizeof(T)) continue; sprintf(expected_str, str, off); EXPECT_DEATH(oob_test<T>(size, i), expected_str); } } EXPECT_DEATH(oob_test<T>(kLargeMalloc, -1), "is located.*1 byte.*to the left"); EXPECT_DEATH(oob_test<T>(kLargeMalloc, kLargeMalloc), "is located.*0 byte.*to the right"); } TEST(AddressSanitizer, OOB_char) { OOBTest<U1>(); } TEST(AddressSanitizer, OOB_int) { OOBTest<U4>(); }