-O2
-Wno-format
-Werror=sign-compare
- -Wno-non-virtual-dtor)
+ -Wno-non-virtual-dtor
+ )
append_list_if(COMPILER_RT_HAS_WVARIADIC_MACROS_FLAG -Wno-variadic-macros ASAN_UNITTEST_COMMON_CFLAGS)
# This will ensure the target linker is used
${COMPILER_RT_ASAN_SHADOW_SCALE_FLAG}
-DASAN_HAS_BLACKLIST=1
-DASAN_HAS_EXCEPTIONS=1
- -DASAN_UAR=0)
+ -DASAN_UAR=0
+ )
if(APPLE)
list(APPEND ASAN_UNITTEST_COMMON_CFLAGS ${DARWIN_osx_CFLAGS})
set(ASAN_NOINST_TEST_SOURCES
${COMPILER_RT_GTEST_SOURCE}
- asan_fake_stack_test.cc
- asan_noinst_test.cc
- asan_test_main.cc)
+ asan_fake_stack_test.cpp
+ asan_noinst_test.cpp
+ asan_test_main.cpp
+ )
set(ASAN_INST_TEST_SOURCES
${COMPILER_RT_GTEST_SOURCE}
- asan_globals_test.cc
- asan_interface_test.cc
- asan_internal_interface_test.cc
- asan_test.cc
- asan_oob_test.cc
- asan_mem_test.cc
- asan_str_test.cc
- asan_test_main.cc)
+ asan_globals_test.cpp
+ asan_interface_test.cpp
+ asan_internal_interface_test.cpp
+ asan_test.cpp
+ asan_oob_test.cpp
+ asan_mem_test.cpp
+ asan_str_test.cpp
+ asan_test_main.cpp
+ )
if(APPLE)
- list(APPEND ASAN_INST_TEST_SOURCES asan_mac_test.cc asan_mac_test_helpers.mm)
+ list(APPEND ASAN_INST_TEST_SOURCES
+ asan_mac_test.cpp
+ asan_mac_test_helpers.mm
+ )
endif()
set(ASAN_BENCHMARKS_SOURCES
${COMPILER_RT_GTEST_SOURCE}
- asan_benchmarks_test.cc)
+ asan_benchmarks_test.cpp
+ )
function(add_asan_tests arch test_runtime)
cmake_parse_arguments(TEST "" "KIND" "CFLAGS" ${ARGN})
+++ /dev/null
-//===-- asan_benchmarks_test.cc ----------------------===//
-//
-// 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
-//
-//===----------------------------------------------------------------------===//
-//
-// This file is a part of AddressSanitizer, an address sanity checker.
-//
-// Some benchmarks for the instrumented code.
-//===----------------------------------------------------------------------===//
-
-#include "asan_test_utils.h"
-
-template<class T>
-__attribute__((noinline))
-static void ManyAccessFunc(T *x, size_t n_elements, size_t n_iter) {
- for (size_t iter = 0; iter < n_iter; iter++) {
- break_optimization(0);
- // hand unroll the loop to stress the reg alloc.
- for (size_t i = 0; i <= n_elements - 16; i += 16) {
- x[i + 0] = i;
- x[i + 1] = i;
- x[i + 2] = i;
- x[i + 3] = i;
- x[i + 4] = i;
- x[i + 5] = i;
- x[i + 6] = i;
- x[i + 7] = i;
- x[i + 8] = i;
- x[i + 9] = i;
- x[i + 10] = i;
- x[i + 11] = i;
- x[i + 12] = i;
- x[i + 13] = i;
- x[i + 14] = i;
- x[i + 15] = i;
- }
- }
-}
-
-TEST(AddressSanitizer, ManyAccessBenchmark) {
- size_t kLen = 1024;
- int *int_array = new int[kLen];
- ManyAccessFunc(int_array, kLen, 1 << 24);
- delete [] int_array;
-}
-
-// access 7 char elements in a 7 byte array (i.e. on the border).
-__attribute__((noinline))
-static void BorderAccessFunc(char *x, size_t n_iter) {
- for (size_t iter = 0; iter < n_iter; iter++) {
- break_optimization(x);
- x[0] = 0;
- x[1] = 0;
- x[2] = 0;
- x[3] = 0;
- x[4] = 0;
- x[5] = 0;
- x[6] = 0;
- }
-}
-
-TEST(AddressSanitizer, BorderAccessBenchmark) {
- char *char_7_array = new char[7];
- BorderAccessFunc(char_7_array, 1 << 30);
- delete [] char_7_array;
-}
-
-static void FunctionWithLargeStack() {
- int stack[1000];
- Ident(stack);
-}
-
-TEST(AddressSanitizer, FakeStackBenchmark) {
- for (int i = 0; i < 10000000; i++)
- Ident(&FunctionWithLargeStack)();
-}
-
-int main(int argc, char **argv) {
- testing::InitGoogleTest(&argc, argv);
- return RUN_ALL_TESTS();
-}
--- /dev/null
+//===-- asan_benchmarks_test.cpp ---------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a part of AddressSanitizer, an address sanity checker.
+//
+// Some benchmarks for the instrumented code.
+//===----------------------------------------------------------------------===//
+
+#include "asan_test_utils.h"
+
+template<class T>
+__attribute__((noinline))
+static void ManyAccessFunc(T *x, size_t n_elements, size_t n_iter) {
+ for (size_t iter = 0; iter < n_iter; iter++) {
+ break_optimization(0);
+ // hand unroll the loop to stress the reg alloc.
+ for (size_t i = 0; i <= n_elements - 16; i += 16) {
+ x[i + 0] = i;
+ x[i + 1] = i;
+ x[i + 2] = i;
+ x[i + 3] = i;
+ x[i + 4] = i;
+ x[i + 5] = i;
+ x[i + 6] = i;
+ x[i + 7] = i;
+ x[i + 8] = i;
+ x[i + 9] = i;
+ x[i + 10] = i;
+ x[i + 11] = i;
+ x[i + 12] = i;
+ x[i + 13] = i;
+ x[i + 14] = i;
+ x[i + 15] = i;
+ }
+ }
+}
+
+TEST(AddressSanitizer, ManyAccessBenchmark) {
+ size_t kLen = 1024;
+ int *int_array = new int[kLen];
+ ManyAccessFunc(int_array, kLen, 1 << 24);
+ delete [] int_array;
+}
+
+// access 7 char elements in a 7 byte array (i.e. on the border).
+__attribute__((noinline))
+static void BorderAccessFunc(char *x, size_t n_iter) {
+ for (size_t iter = 0; iter < n_iter; iter++) {
+ break_optimization(x);
+ x[0] = 0;
+ x[1] = 0;
+ x[2] = 0;
+ x[3] = 0;
+ x[4] = 0;
+ x[5] = 0;
+ x[6] = 0;
+ }
+}
+
+TEST(AddressSanitizer, BorderAccessBenchmark) {
+ char *char_7_array = new char[7];
+ BorderAccessFunc(char_7_array, 1 << 30);
+ delete [] char_7_array;
+}
+
+static void FunctionWithLargeStack() {
+ int stack[1000];
+ Ident(stack);
+}
+
+TEST(AddressSanitizer, FakeStackBenchmark) {
+ for (int i = 0; i < 10000000; i++)
+ Ident(&FunctionWithLargeStack)();
+}
+
+int main(int argc, char **argv) {
+ testing::InitGoogleTest(&argc, argv);
+ return RUN_ALL_TESTS();
+}
+++ /dev/null
-// See http://llvm.org/bugs/show_bug.cgi?id=11468
-#include <stdio.h>
-#include <string>
-
-class Action {
- public:
- Action() {}
- void PrintString(const std::string& msg) const {
- fprintf(stderr, "%s\n", msg.c_str());
- }
- void Throw(const char& arg) const {
- PrintString("PrintString called!"); // this line is important
- throw arg;
- }
-};
-
-int main() {
- const Action a;
- fprintf(stderr, "&a before = %p\n", &a);
- try {
- a.Throw('c');
- } catch(const char&) {
- fprintf(stderr, "&a in catch = %p\n", &a);
- }
- fprintf(stderr, "&a final = %p\n", &a);
- return 0;
-}
--- /dev/null
+// See http://llvm.org/bugs/show_bug.cgi?id=11468
+#include <stdio.h>
+#include <string>
+
+class Action {
+ public:
+ Action() {}
+ void PrintString(const std::string& msg) const {
+ fprintf(stderr, "%s\n", msg.c_str());
+ }
+ void Throw(const char& arg) const {
+ PrintString("PrintString called!"); // this line is important
+ throw arg;
+ }
+};
+
+int main() {
+ const Action a;
+ fprintf(stderr, "&a before = %p\n", &a);
+ try {
+ a.Throw('c');
+ } catch(const char&) {
+ fprintf(stderr, "&a in catch = %p\n", &a);
+ }
+ fprintf(stderr, "&a final = %p\n", &a);
+ return 0;
+}
+++ /dev/null
-//===-- asan_fake_stack_test.cc -------------------------------------------===//
-//
-// 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
-//
-//===----------------------------------------------------------------------===//
-//
-// This file is a part of AddressSanitizer, an address sanity checker.
-//
-// Tests for FakeStack.
-// This test file should be compiled w/o asan instrumentation.
-//===----------------------------------------------------------------------===//
-
-#include "asan_fake_stack.h"
-#include "asan_test_utils.h"
-#include "sanitizer_common/sanitizer_common.h"
-
-#include <assert.h>
-#include <stdlib.h>
-#include <stdio.h>
-
-#include <map>
-
-namespace __asan {
-
-TEST(FakeStack, FlagsSize) {
- EXPECT_EQ(FakeStack::SizeRequiredForFlags(10), 1U << 5);
- EXPECT_EQ(FakeStack::SizeRequiredForFlags(11), 1U << 6);
- EXPECT_EQ(FakeStack::SizeRequiredForFlags(20), 1U << 15);
-}
-
-TEST(FakeStack, RequiredSize) {
- // for (int i = 15; i < 20; i++) {
- // uptr alloc_size = FakeStack::RequiredSize(i);
- // printf("%zdK ==> %zd\n", 1 << (i - 10), alloc_size);
- // }
- EXPECT_EQ(FakeStack::RequiredSize(15), 365568U);
- EXPECT_EQ(FakeStack::RequiredSize(16), 727040U);
- EXPECT_EQ(FakeStack::RequiredSize(17), 1449984U);
- EXPECT_EQ(FakeStack::RequiredSize(18), 2895872U);
- EXPECT_EQ(FakeStack::RequiredSize(19), 5787648U);
-}
-
-TEST(FakeStack, FlagsOffset) {
- for (uptr stack_size_log = 15; stack_size_log <= 20; stack_size_log++) {
- uptr stack_size = 1UL << stack_size_log;
- uptr offset = 0;
- for (uptr class_id = 0; class_id < FakeStack::kNumberOfSizeClasses;
- class_id++) {
- uptr frame_size = FakeStack::BytesInSizeClass(class_id);
- uptr num_flags = stack_size / frame_size;
- EXPECT_EQ(offset, FakeStack::FlagsOffset(stack_size_log, class_id));
- // printf("%zd: %zd => %zd %zd\n", stack_size_log, class_id, offset,
- // FakeStack::FlagsOffset(stack_size_log, class_id));
- offset += num_flags;
- }
- }
-}
-
-#if !defined(_WIN32) // FIXME: Fails due to OOM on Windows.
-TEST(FakeStack, CreateDestroy) {
- for (int i = 0; i < 1000; i++) {
- for (uptr stack_size_log = 20; stack_size_log <= 22; stack_size_log++) {
- FakeStack *fake_stack = FakeStack::Create(stack_size_log);
- fake_stack->Destroy(0);
- }
- }
-}
-#endif
-
-TEST(FakeStack, ModuloNumberOfFrames) {
- EXPECT_EQ(FakeStack::ModuloNumberOfFrames(15, 0, 0), 0U);
- EXPECT_EQ(FakeStack::ModuloNumberOfFrames(15, 0, (1<<15)), 0U);
- EXPECT_EQ(FakeStack::ModuloNumberOfFrames(15, 0, (1<<10)), 0U);
- EXPECT_EQ(FakeStack::ModuloNumberOfFrames(15, 0, (1<<9)), 0U);
- EXPECT_EQ(FakeStack::ModuloNumberOfFrames(15, 0, (1<<8)), 1U<<8);
- EXPECT_EQ(FakeStack::ModuloNumberOfFrames(15, 0, (1<<15) + 1), 1U);
-
- EXPECT_EQ(FakeStack::ModuloNumberOfFrames(15, 1, 0), 0U);
- EXPECT_EQ(FakeStack::ModuloNumberOfFrames(15, 1, 1<<9), 0U);
- EXPECT_EQ(FakeStack::ModuloNumberOfFrames(15, 1, 1<<8), 0U);
- EXPECT_EQ(FakeStack::ModuloNumberOfFrames(15, 1, 1<<7), 1U<<7);
-
- EXPECT_EQ(FakeStack::ModuloNumberOfFrames(15, 5, 0), 0U);
- EXPECT_EQ(FakeStack::ModuloNumberOfFrames(15, 5, 1), 1U);
- EXPECT_EQ(FakeStack::ModuloNumberOfFrames(15, 5, 15), 15U);
- EXPECT_EQ(FakeStack::ModuloNumberOfFrames(15, 5, 16), 0U);
- EXPECT_EQ(FakeStack::ModuloNumberOfFrames(15, 5, 17), 1U);
-}
-
-TEST(FakeStack, GetFrame) {
- const uptr stack_size_log = 20;
- const uptr stack_size = 1 << stack_size_log;
- FakeStack *fs = FakeStack::Create(stack_size_log);
- u8 *base = fs->GetFrame(stack_size_log, 0, 0);
- EXPECT_EQ(base, reinterpret_cast<u8 *>(fs) +
- fs->SizeRequiredForFlags(stack_size_log) + 4096);
- EXPECT_EQ(base + 0*stack_size + 64 * 7, fs->GetFrame(stack_size_log, 0, 7U));
- EXPECT_EQ(base + 1*stack_size + 128 * 3, fs->GetFrame(stack_size_log, 1, 3U));
- EXPECT_EQ(base + 2*stack_size + 256 * 5, fs->GetFrame(stack_size_log, 2, 5U));
- fs->Destroy(0);
-}
-
-TEST(FakeStack, Allocate) {
- const uptr stack_size_log = 19;
- FakeStack *fs = FakeStack::Create(stack_size_log);
- std::map<FakeFrame *, uptr> s;
- for (int iter = 0; iter < 2; iter++) {
- s.clear();
- for (uptr cid = 0; cid < FakeStack::kNumberOfSizeClasses; cid++) {
- uptr n = FakeStack::NumberOfFrames(stack_size_log, cid);
- uptr bytes_in_class = FakeStack::BytesInSizeClass(cid);
- for (uptr j = 0; j < n; j++) {
- FakeFrame *ff = fs->Allocate(stack_size_log, cid, 0);
- uptr x = reinterpret_cast<uptr>(ff);
- EXPECT_TRUE(s.insert(std::make_pair(ff, cid)).second);
- EXPECT_EQ(x, fs->AddrIsInFakeStack(x));
- EXPECT_EQ(x, fs->AddrIsInFakeStack(x + 1));
- EXPECT_EQ(x, fs->AddrIsInFakeStack(x + bytes_in_class - 1));
- EXPECT_NE(x, fs->AddrIsInFakeStack(x + bytes_in_class));
- }
- // We are out of fake stack, so Allocate should return 0.
- EXPECT_EQ(0UL, fs->Allocate(stack_size_log, cid, 0));
- }
- for (std::map<FakeFrame *, uptr>::iterator it = s.begin(); it != s.end();
- ++it) {
- fs->Deallocate(reinterpret_cast<uptr>(it->first), it->second);
- }
- }
- fs->Destroy(0);
-}
-
-static void RecursiveFunction(FakeStack *fs, int depth) {
- uptr class_id = depth / 3;
- FakeFrame *ff = fs->Allocate(fs->stack_size_log(), class_id, 0);
- if (depth) {
- RecursiveFunction(fs, depth - 1);
- RecursiveFunction(fs, depth - 1);
- }
- fs->Deallocate(reinterpret_cast<uptr>(ff), class_id);
-}
-
-TEST(FakeStack, RecursiveStressTest) {
- const uptr stack_size_log = 16;
- FakeStack *fs = FakeStack::Create(stack_size_log);
- RecursiveFunction(fs, 22); // with 26 runs for 2-3 seconds.
- fs->Destroy(0);
-}
-
-} // namespace __asan
--- /dev/null
+//===-- asan_fake_stack_test.cpp ------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a part of AddressSanitizer, an address sanity checker.
+//
+// Tests for FakeStack.
+// This test file should be compiled w/o asan instrumentation.
+//===----------------------------------------------------------------------===//
+
+#include "asan_fake_stack.h"
+#include "asan_test_utils.h"
+#include "sanitizer_common/sanitizer_common.h"
+
+#include <assert.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+#include <map>
+
+namespace __asan {
+
+TEST(FakeStack, FlagsSize) {
+ EXPECT_EQ(FakeStack::SizeRequiredForFlags(10), 1U << 5);
+ EXPECT_EQ(FakeStack::SizeRequiredForFlags(11), 1U << 6);
+ EXPECT_EQ(FakeStack::SizeRequiredForFlags(20), 1U << 15);
+}
+
+TEST(FakeStack, RequiredSize) {
+ // for (int i = 15; i < 20; i++) {
+ // uptr alloc_size = FakeStack::RequiredSize(i);
+ // printf("%zdK ==> %zd\n", 1 << (i - 10), alloc_size);
+ // }
+ EXPECT_EQ(FakeStack::RequiredSize(15), 365568U);
+ EXPECT_EQ(FakeStack::RequiredSize(16), 727040U);
+ EXPECT_EQ(FakeStack::RequiredSize(17), 1449984U);
+ EXPECT_EQ(FakeStack::RequiredSize(18), 2895872U);
+ EXPECT_EQ(FakeStack::RequiredSize(19), 5787648U);
+}
+
+TEST(FakeStack, FlagsOffset) {
+ for (uptr stack_size_log = 15; stack_size_log <= 20; stack_size_log++) {
+ uptr stack_size = 1UL << stack_size_log;
+ uptr offset = 0;
+ for (uptr class_id = 0; class_id < FakeStack::kNumberOfSizeClasses;
+ class_id++) {
+ uptr frame_size = FakeStack::BytesInSizeClass(class_id);
+ uptr num_flags = stack_size / frame_size;
+ EXPECT_EQ(offset, FakeStack::FlagsOffset(stack_size_log, class_id));
+ // printf("%zd: %zd => %zd %zd\n", stack_size_log, class_id, offset,
+ // FakeStack::FlagsOffset(stack_size_log, class_id));
+ offset += num_flags;
+ }
+ }
+}
+
+#if !defined(_WIN32) // FIXME: Fails due to OOM on Windows.
+TEST(FakeStack, CreateDestroy) {
+ for (int i = 0; i < 1000; i++) {
+ for (uptr stack_size_log = 20; stack_size_log <= 22; stack_size_log++) {
+ FakeStack *fake_stack = FakeStack::Create(stack_size_log);
+ fake_stack->Destroy(0);
+ }
+ }
+}
+#endif
+
+TEST(FakeStack, ModuloNumberOfFrames) {
+ EXPECT_EQ(FakeStack::ModuloNumberOfFrames(15, 0, 0), 0U);
+ EXPECT_EQ(FakeStack::ModuloNumberOfFrames(15, 0, (1<<15)), 0U);
+ EXPECT_EQ(FakeStack::ModuloNumberOfFrames(15, 0, (1<<10)), 0U);
+ EXPECT_EQ(FakeStack::ModuloNumberOfFrames(15, 0, (1<<9)), 0U);
+ EXPECT_EQ(FakeStack::ModuloNumberOfFrames(15, 0, (1<<8)), 1U<<8);
+ EXPECT_EQ(FakeStack::ModuloNumberOfFrames(15, 0, (1<<15) + 1), 1U);
+
+ EXPECT_EQ(FakeStack::ModuloNumberOfFrames(15, 1, 0), 0U);
+ EXPECT_EQ(FakeStack::ModuloNumberOfFrames(15, 1, 1<<9), 0U);
+ EXPECT_EQ(FakeStack::ModuloNumberOfFrames(15, 1, 1<<8), 0U);
+ EXPECT_EQ(FakeStack::ModuloNumberOfFrames(15, 1, 1<<7), 1U<<7);
+
+ EXPECT_EQ(FakeStack::ModuloNumberOfFrames(15, 5, 0), 0U);
+ EXPECT_EQ(FakeStack::ModuloNumberOfFrames(15, 5, 1), 1U);
+ EXPECT_EQ(FakeStack::ModuloNumberOfFrames(15, 5, 15), 15U);
+ EXPECT_EQ(FakeStack::ModuloNumberOfFrames(15, 5, 16), 0U);
+ EXPECT_EQ(FakeStack::ModuloNumberOfFrames(15, 5, 17), 1U);
+}
+
+TEST(FakeStack, GetFrame) {
+ const uptr stack_size_log = 20;
+ const uptr stack_size = 1 << stack_size_log;
+ FakeStack *fs = FakeStack::Create(stack_size_log);
+ u8 *base = fs->GetFrame(stack_size_log, 0, 0);
+ EXPECT_EQ(base, reinterpret_cast<u8 *>(fs) +
+ fs->SizeRequiredForFlags(stack_size_log) + 4096);
+ EXPECT_EQ(base + 0*stack_size + 64 * 7, fs->GetFrame(stack_size_log, 0, 7U));
+ EXPECT_EQ(base + 1*stack_size + 128 * 3, fs->GetFrame(stack_size_log, 1, 3U));
+ EXPECT_EQ(base + 2*stack_size + 256 * 5, fs->GetFrame(stack_size_log, 2, 5U));
+ fs->Destroy(0);
+}
+
+TEST(FakeStack, Allocate) {
+ const uptr stack_size_log = 19;
+ FakeStack *fs = FakeStack::Create(stack_size_log);
+ std::map<FakeFrame *, uptr> s;
+ for (int iter = 0; iter < 2; iter++) {
+ s.clear();
+ for (uptr cid = 0; cid < FakeStack::kNumberOfSizeClasses; cid++) {
+ uptr n = FakeStack::NumberOfFrames(stack_size_log, cid);
+ uptr bytes_in_class = FakeStack::BytesInSizeClass(cid);
+ for (uptr j = 0; j < n; j++) {
+ FakeFrame *ff = fs->Allocate(stack_size_log, cid, 0);
+ uptr x = reinterpret_cast<uptr>(ff);
+ EXPECT_TRUE(s.insert(std::make_pair(ff, cid)).second);
+ EXPECT_EQ(x, fs->AddrIsInFakeStack(x));
+ EXPECT_EQ(x, fs->AddrIsInFakeStack(x + 1));
+ EXPECT_EQ(x, fs->AddrIsInFakeStack(x + bytes_in_class - 1));
+ EXPECT_NE(x, fs->AddrIsInFakeStack(x + bytes_in_class));
+ }
+ // We are out of fake stack, so Allocate should return 0.
+ EXPECT_EQ(0UL, fs->Allocate(stack_size_log, cid, 0));
+ }
+ for (std::map<FakeFrame *, uptr>::iterator it = s.begin(); it != s.end();
+ ++it) {
+ fs->Deallocate(reinterpret_cast<uptr>(it->first), it->second);
+ }
+ }
+ fs->Destroy(0);
+}
+
+static void RecursiveFunction(FakeStack *fs, int depth) {
+ uptr class_id = depth / 3;
+ FakeFrame *ff = fs->Allocate(fs->stack_size_log(), class_id, 0);
+ if (depth) {
+ RecursiveFunction(fs, depth - 1);
+ RecursiveFunction(fs, depth - 1);
+ }
+ fs->Deallocate(reinterpret_cast<uptr>(ff), class_id);
+}
+
+TEST(FakeStack, RecursiveStressTest) {
+ const uptr stack_size_log = 16;
+ FakeStack *fs = FakeStack::Create(stack_size_log);
+ RecursiveFunction(fs, 22); // with 26 runs for 2-3 seconds.
+ fs->Destroy(0);
+}
+
+} // namespace __asan
+++ /dev/null
-//===-- asan_globals_test.cc ----------------------------------------------===//
-//
-// 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
-//
-//===----------------------------------------------------------------------===//
-//
-// This file is a part of AddressSanitizer, an address sanity checker.
-//
-// Some globals in a separate file.
-//===----------------------------------------------------------------------===//
-#include "asan_test_utils.h"
-
-char glob1[1];
-char glob2[2];
-char glob3[3];
-char glob4[4];
-char glob5[5];
-char glob6[6];
-char glob7[7];
-char glob8[8];
-char glob9[9];
-char glob10[10];
-char glob11[11];
-char glob12[12];
-char glob13[13];
-char glob14[14];
-char glob15[15];
-char glob16[16];
-char glob17[17];
-char glob1000[1000];
-char glob10000[10000];
-char glob100000[100000];
-
-static char static10[10];
-
-int GlobalsTest(int zero) {
- static char func_static15[15];
- glob5[zero] = 0;
- static10[zero] = 0;
- func_static15[zero] = 0;
- return glob5[1] + func_static15[2];
-}
--- /dev/null
+//===-- asan_globals_test.cpp ---------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a part of AddressSanitizer, an address sanity checker.
+//
+// Some globals in a separate file.
+//===----------------------------------------------------------------------===//
+#include "asan_test_utils.h"
+
+char glob1[1];
+char glob2[2];
+char glob3[3];
+char glob4[4];
+char glob5[5];
+char glob6[6];
+char glob7[7];
+char glob8[8];
+char glob9[9];
+char glob10[10];
+char glob11[11];
+char glob12[12];
+char glob13[13];
+char glob14[14];
+char glob15[15];
+char glob16[16];
+char glob17[17];
+char glob1000[1000];
+char glob10000[10000];
+char glob100000[100000];
+
+static char static10[10];
+
+int GlobalsTest(int zero) {
+ static char func_static15[15];
+ glob5[zero] = 0;
+ static10[zero] = 0;
+ func_static15[zero] = 0;
+ return glob5[1] + func_static15[2];
+}
+++ /dev/null
-//===-- asan_interface_test.cc --------------------------------------------===//
-//
-// 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
-//
-//===----------------------------------------------------------------------===//
-//
-// This file is a part of AddressSanitizer, an address sanity checker.
-//
-//===----------------------------------------------------------------------===//
-#include "asan_test_utils.h"
-#include "sanitizer_common/sanitizer_internal_defs.h"
-#include <sanitizer/allocator_interface.h>
-#include <sanitizer/asan_interface.h>
-#include <vector>
-
-TEST(AddressSanitizerInterface, GetEstimatedAllocatedSize) {
- EXPECT_EQ(0U, __sanitizer_get_estimated_allocated_size(0));
- const size_t sizes[] = { 1, 30, 1<<30 };
- for (size_t i = 0; i < 3; i++) {
- EXPECT_EQ(sizes[i], __sanitizer_get_estimated_allocated_size(sizes[i]));
- }
-}
-
-static const char* kGetAllocatedSizeErrorMsg =
- "attempting to call __sanitizer_get_allocated_size";
-
-TEST(AddressSanitizerInterface, GetAllocatedSizeAndOwnershipTest) {
- const size_t kArraySize = 100;
- char *array = Ident((char*)malloc(kArraySize));
- int *int_ptr = Ident(new int);
-
- // Allocated memory is owned by allocator. Allocated size should be
- // equal to requested size.
- EXPECT_EQ(true, __sanitizer_get_ownership(array));
- EXPECT_EQ(kArraySize, __sanitizer_get_allocated_size(array));
- EXPECT_EQ(true, __sanitizer_get_ownership(int_ptr));
- EXPECT_EQ(sizeof(int), __sanitizer_get_allocated_size(int_ptr));
-
- // We cannot call GetAllocatedSize from the memory we didn't map,
- // and from the interior pointers (not returned by previous malloc).
- void *wild_addr = (void*)0x1;
- EXPECT_FALSE(__sanitizer_get_ownership(wild_addr));
- EXPECT_DEATH(__sanitizer_get_allocated_size(wild_addr),
- kGetAllocatedSizeErrorMsg);
- EXPECT_FALSE(__sanitizer_get_ownership(array + kArraySize / 2));
- EXPECT_DEATH(__sanitizer_get_allocated_size(array + kArraySize / 2),
- kGetAllocatedSizeErrorMsg);
-
- // NULL is not owned, but is a valid argument for
- // __sanitizer_get_allocated_size().
- EXPECT_FALSE(__sanitizer_get_ownership(NULL));
- EXPECT_EQ(0U, __sanitizer_get_allocated_size(NULL));
-
- // When memory is freed, it's not owned, and call to GetAllocatedSize
- // is forbidden.
- free(array);
- EXPECT_FALSE(__sanitizer_get_ownership(array));
- EXPECT_DEATH(__sanitizer_get_allocated_size(array),
- kGetAllocatedSizeErrorMsg);
- delete int_ptr;
-
- void *zero_alloc = Ident(malloc(0));
- if (zero_alloc != 0) {
- // If malloc(0) is not null, this pointer is owned and should have valid
- // allocated size.
- EXPECT_TRUE(__sanitizer_get_ownership(zero_alloc));
- // Allocated size is 0 or 1 depending on the allocator used.
- EXPECT_LT(__sanitizer_get_allocated_size(zero_alloc), 2U);
- }
- free(zero_alloc);
-}
-
-TEST(AddressSanitizerInterface, GetCurrentAllocatedBytesTest) {
- size_t before_malloc, after_malloc, after_free;
- char *array;
- const size_t kMallocSize = 100;
- before_malloc = __sanitizer_get_current_allocated_bytes();
-
- array = Ident((char*)malloc(kMallocSize));
- after_malloc = __sanitizer_get_current_allocated_bytes();
- EXPECT_EQ(before_malloc + kMallocSize, after_malloc);
-
- free(array);
- after_free = __sanitizer_get_current_allocated_bytes();
- EXPECT_EQ(before_malloc, after_free);
-}
-
-TEST(AddressSanitizerInterface, GetHeapSizeTest) {
- // ASan allocator does not keep huge chunks in free list, but unmaps them.
- // The chunk should be greater than the quarantine size,
- // otherwise it will be stuck in quarantine instead of being unmaped.
- static const size_t kLargeMallocSize = (1 << 28) + 1; // 256M
- free(Ident(malloc(kLargeMallocSize))); // Drain quarantine.
- size_t old_heap_size = __sanitizer_get_heap_size();
- for (int i = 0; i < 3; i++) {
- // fprintf(stderr, "allocating %zu bytes:\n", kLargeMallocSize);
- free(Ident(malloc(kLargeMallocSize)));
- EXPECT_EQ(old_heap_size, __sanitizer_get_heap_size());
- }
-}
-
-#if !defined(__NetBSD__)
-static const size_t kManyThreadsMallocSizes[] = {5, 1UL<<10, 1UL<<14, 357};
-static const size_t kManyThreadsIterations = 250;
-static const size_t kManyThreadsNumThreads =
- (SANITIZER_WORDSIZE == 32) ? 40 : 200;
-
-static void *ManyThreadsWithStatsWorker(void *arg) {
- (void)arg;
- for (size_t iter = 0; iter < kManyThreadsIterations; iter++) {
- for (size_t size_index = 0; size_index < 4; size_index++) {
- free(Ident(malloc(kManyThreadsMallocSizes[size_index])));
- }
- }
- // Just one large allocation.
- free(Ident(malloc(1 << 20)));
- return 0;
-}
-
-TEST(AddressSanitizerInterface, ManyThreadsWithStatsStressTest) {
- size_t before_test, after_test, i;
- pthread_t threads[kManyThreadsNumThreads];
- before_test = __sanitizer_get_current_allocated_bytes();
- for (i = 0; i < kManyThreadsNumThreads; i++) {
- PTHREAD_CREATE(&threads[i], 0,
- (void* (*)(void *x))ManyThreadsWithStatsWorker, (void*)i);
- }
- for (i = 0; i < kManyThreadsNumThreads; i++) {
- PTHREAD_JOIN(threads[i], 0);
- }
- after_test = __sanitizer_get_current_allocated_bytes();
- // ASan stats also reflect memory usage of internal ASan RTL structs,
- // so we can't check for equality here.
- EXPECT_LT(after_test, before_test + (1UL<<20));
-}
-#endif
-
-static void DoDoubleFree() {
- int *x = Ident(new int);
- delete Ident(x);
- delete Ident(x);
-}
-
-static void MyDeathCallback() {
- fprintf(stderr, "MyDeathCallback\n");
- fflush(0); // On Windows, stderr doesn't flush on crash.
-}
-
-TEST(AddressSanitizerInterface, DeathCallbackTest) {
- __asan_set_death_callback(MyDeathCallback);
- EXPECT_DEATH(DoDoubleFree(), "MyDeathCallback");
- __asan_set_death_callback(NULL);
-}
-
-#define GOOD_ACCESS(ptr, offset) \
- EXPECT_FALSE(__asan_address_is_poisoned(ptr + offset))
-
-#define BAD_ACCESS(ptr, offset) \
- EXPECT_TRUE(__asan_address_is_poisoned(ptr + offset))
-
-#if !defined(ASAN_SHADOW_SCALE) || ASAN_SHADOW_SCALE == 3
-static const char* kUseAfterPoisonErrorMessage = "use-after-poison";
-
-TEST(AddressSanitizerInterface, SimplePoisonMemoryRegionTest) {
- char *array = Ident((char*)malloc(120));
- // poison array[40..80)
- __asan_poison_memory_region(array + 40, 40);
- GOOD_ACCESS(array, 39);
- GOOD_ACCESS(array, 80);
- BAD_ACCESS(array, 40);
- BAD_ACCESS(array, 60);
- BAD_ACCESS(array, 79);
- char value;
- EXPECT_DEATH(value = Ident(array[40]), kUseAfterPoisonErrorMessage);
- __asan_unpoison_memory_region(array + 40, 40);
- // access previously poisoned memory.
- GOOD_ACCESS(array, 40);
- GOOD_ACCESS(array, 79);
- free(array);
-}
-
-TEST(AddressSanitizerInterface, OverlappingPoisonMemoryRegionTest) {
- char *array = Ident((char*)malloc(120));
- // Poison [0..40) and [80..120)
- __asan_poison_memory_region(array, 40);
- __asan_poison_memory_region(array + 80, 40);
- BAD_ACCESS(array, 20);
- GOOD_ACCESS(array, 60);
- BAD_ACCESS(array, 100);
- // Poison whole array - [0..120)
- __asan_poison_memory_region(array, 120);
- BAD_ACCESS(array, 60);
- // Unpoison [24..96)
- __asan_unpoison_memory_region(array + 24, 72);
- BAD_ACCESS(array, 23);
- GOOD_ACCESS(array, 24);
- GOOD_ACCESS(array, 60);
- GOOD_ACCESS(array, 95);
- BAD_ACCESS(array, 96);
- free(array);
-}
-#endif // !defined(ASAN_SHADOW_SCALE) || ASAN_SHADOW_SCALE == 3
-
-TEST(AddressSanitizerInterface, PushAndPopWithPoisoningTest) {
- // Vector of capacity 20
- char *vec = Ident((char*)malloc(20));
- __asan_poison_memory_region(vec, 20);
- for (size_t i = 0; i < 7; i++) {
- // Simulate push_back.
- __asan_unpoison_memory_region(vec + i, 1);
- GOOD_ACCESS(vec, i);
- BAD_ACCESS(vec, i + 1);
- }
- for (size_t i = 7; i > 0; i--) {
- // Simulate pop_back.
- __asan_poison_memory_region(vec + i - 1, 1);
- BAD_ACCESS(vec, i - 1);
- if (i > 1) GOOD_ACCESS(vec, i - 2);
- }
- free(vec);
-}
-
-#if !defined(ASAN_SHADOW_SCALE) || ASAN_SHADOW_SCALE == 3
-// Make sure that each aligned block of size "2^granularity" doesn't have
-// "true" value before "false" value.
-static void MakeShadowValid(bool *shadow, int length, int granularity) {
- bool can_be_poisoned = true;
- for (int i = length - 1; i >= 0; i--) {
- if (!shadow[i])
- can_be_poisoned = false;
- if (!can_be_poisoned)
- shadow[i] = false;
- if (i % (1 << granularity) == 0) {
- can_be_poisoned = true;
- }
- }
-}
-
-TEST(AddressSanitizerInterface, PoisoningStressTest) {
- const size_t kSize = 24;
- bool expected[kSize];
- char *arr = Ident((char*)malloc(kSize));
- for (size_t l1 = 0; l1 < kSize; l1++) {
- for (size_t s1 = 1; l1 + s1 <= kSize; s1++) {
- for (size_t l2 = 0; l2 < kSize; l2++) {
- for (size_t s2 = 1; l2 + s2 <= kSize; s2++) {
- // Poison [l1, l1+s1), [l2, l2+s2) and check result.
- __asan_unpoison_memory_region(arr, kSize);
- __asan_poison_memory_region(arr + l1, s1);
- __asan_poison_memory_region(arr + l2, s2);
- memset(expected, false, kSize);
- memset(expected + l1, true, s1);
- MakeShadowValid(expected, kSize, /*granularity*/ 3);
- memset(expected + l2, true, s2);
- MakeShadowValid(expected, kSize, /*granularity*/ 3);
- for (size_t i = 0; i < kSize; i++) {
- ASSERT_EQ(expected[i], __asan_address_is_poisoned(arr + i));
- }
- // Unpoison [l1, l1+s1) and [l2, l2+s2) and check result.
- __asan_poison_memory_region(arr, kSize);
- __asan_unpoison_memory_region(arr + l1, s1);
- __asan_unpoison_memory_region(arr + l2, s2);
- memset(expected, true, kSize);
- memset(expected + l1, false, s1);
- MakeShadowValid(expected, kSize, /*granularity*/ 3);
- memset(expected + l2, false, s2);
- MakeShadowValid(expected, kSize, /*granularity*/ 3);
- for (size_t i = 0; i < kSize; i++) {
- ASSERT_EQ(expected[i], __asan_address_is_poisoned(arr + i));
- }
- }
- }
- }
- }
- free(arr);
-}
-#endif // !defined(ASAN_SHADOW_SCALE) || ASAN_SHADOW_SCALE == 3
-
-TEST(AddressSanitizerInterface, GlobalRedzones) {
- GOOD_ACCESS(glob1, 1 - 1);
- GOOD_ACCESS(glob2, 2 - 1);
- GOOD_ACCESS(glob3, 3 - 1);
- GOOD_ACCESS(glob4, 4 - 1);
- GOOD_ACCESS(glob5, 5 - 1);
- GOOD_ACCESS(glob6, 6 - 1);
- GOOD_ACCESS(glob7, 7 - 1);
- GOOD_ACCESS(glob8, 8 - 1);
- GOOD_ACCESS(glob9, 9 - 1);
- GOOD_ACCESS(glob10, 10 - 1);
- GOOD_ACCESS(glob11, 11 - 1);
- GOOD_ACCESS(glob12, 12 - 1);
- GOOD_ACCESS(glob13, 13 - 1);
- GOOD_ACCESS(glob14, 14 - 1);
- GOOD_ACCESS(glob15, 15 - 1);
- GOOD_ACCESS(glob16, 16 - 1);
- GOOD_ACCESS(glob17, 17 - 1);
- GOOD_ACCESS(glob1000, 1000 - 1);
- GOOD_ACCESS(glob10000, 10000 - 1);
- GOOD_ACCESS(glob100000, 100000 - 1);
-
- BAD_ACCESS(glob1, 1);
- BAD_ACCESS(glob2, 2);
- BAD_ACCESS(glob3, 3);
- BAD_ACCESS(glob4, 4);
- BAD_ACCESS(glob5, 5);
- BAD_ACCESS(glob6, 6);
- BAD_ACCESS(glob7, 7);
- BAD_ACCESS(glob8, 8);
- BAD_ACCESS(glob9, 9);
- BAD_ACCESS(glob10, 10);
- BAD_ACCESS(glob11, 11);
- BAD_ACCESS(glob12, 12);
- BAD_ACCESS(glob13, 13);
- BAD_ACCESS(glob14, 14);
- BAD_ACCESS(glob15, 15);
- BAD_ACCESS(glob16, 16);
- BAD_ACCESS(glob17, 17);
- BAD_ACCESS(glob1000, 1000);
- BAD_ACCESS(glob1000, 1100); // Redzone is at least 101 bytes.
- BAD_ACCESS(glob10000, 10000);
- BAD_ACCESS(glob10000, 11000); // Redzone is at least 1001 bytes.
- BAD_ACCESS(glob100000, 100000);
- BAD_ACCESS(glob100000, 110000); // Redzone is at least 10001 bytes.
-}
-
-TEST(AddressSanitizerInterface, PoisonedRegion) {
- size_t rz = 16;
- for (size_t size = 1; size <= 64; size++) {
- char *p = new char[size];
- for (size_t beg = 0; beg < size + rz; beg++) {
- for (size_t end = beg; end < size + rz; end++) {
- void *first_poisoned = __asan_region_is_poisoned(p + beg, end - beg);
- if (beg == end) {
- EXPECT_FALSE(first_poisoned);
- } else if (beg < size && end <= size) {
- EXPECT_FALSE(first_poisoned);
- } else if (beg >= size) {
- EXPECT_EQ(p + beg, first_poisoned);
- } else {
- EXPECT_GT(end, size);
- EXPECT_EQ(p + size, first_poisoned);
- }
- }
- }
- delete [] p;
- }
-}
-
-// This is a performance benchmark for manual runs.
-// asan's memset interceptor calls mem_is_zero for the entire shadow region.
-// the profile should look like this:
-// 89.10% [.] __memset_sse2
-// 10.50% [.] __sanitizer::mem_is_zero
-// I.e. mem_is_zero should consume ~ SHADOW_GRANULARITY less CPU cycles
-// than memset itself.
-TEST(AddressSanitizerInterface, DISABLED_StressLargeMemset) {
- size_t size = 1 << 20;
- char *x = new char[size];
- for (int i = 0; i < 100000; i++)
- Ident(memset)(x, 0, size);
- delete [] x;
-}
-
-// Same here, but we run memset with small sizes.
-TEST(AddressSanitizerInterface, DISABLED_StressSmallMemset) {
- size_t size = 32;
- char *x = new char[size];
- for (int i = 0; i < 100000000; i++)
- Ident(memset)(x, 0, size);
- delete [] x;
-}
-static const char *kInvalidPoisonMessage = "invalid-poison-memory-range";
-static const char *kInvalidUnpoisonMessage = "invalid-unpoison-memory-range";
-
-TEST(AddressSanitizerInterface, DISABLED_InvalidPoisonAndUnpoisonCallsTest) {
- char *array = Ident((char*)malloc(120));
- __asan_unpoison_memory_region(array, 120);
- // Try to unpoison not owned memory
- EXPECT_DEATH(__asan_unpoison_memory_region(array, 121),
- kInvalidUnpoisonMessage);
- EXPECT_DEATH(__asan_unpoison_memory_region(array - 1, 120),
- kInvalidUnpoisonMessage);
-
- __asan_poison_memory_region(array, 120);
- // Try to poison not owned memory.
- EXPECT_DEATH(__asan_poison_memory_region(array, 121), kInvalidPoisonMessage);
- EXPECT_DEATH(__asan_poison_memory_region(array - 1, 120),
- kInvalidPoisonMessage);
- free(array);
-}
-
-TEST(AddressSanitizerInterface, GetOwnershipStressTest) {
- std::vector<char *> pointers;
- std::vector<size_t> sizes;
- const size_t kNumMallocs = 1 << 9;
- for (size_t i = 0; i < kNumMallocs; i++) {
- size_t size = i * 100 + 1;
- pointers.push_back((char*)malloc(size));
- sizes.push_back(size);
- }
- for (size_t i = 0; i < 4000000; i++) {
- EXPECT_FALSE(__sanitizer_get_ownership(&pointers));
- EXPECT_FALSE(__sanitizer_get_ownership((void*)0x1234));
- size_t idx = i % kNumMallocs;
- EXPECT_TRUE(__sanitizer_get_ownership(pointers[idx]));
- EXPECT_EQ(sizes[idx], __sanitizer_get_allocated_size(pointers[idx]));
- }
- for (size_t i = 0, n = pointers.size(); i < n; i++)
- free(pointers[i]);
-}
-
-TEST(AddressSanitizerInterface, HandleNoReturnTest) {
- char array[40];
- __asan_poison_memory_region(array, sizeof(array));
- BAD_ACCESS(array, 20);
- __asan_handle_no_return();
- // It unpoisons the whole thread stack.
- GOOD_ACCESS(array, 20);
-}
--- /dev/null
+//===-- asan_interface_test.cpp -------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a part of AddressSanitizer, an address sanity checker.
+//
+//===----------------------------------------------------------------------===//
+#include "asan_test_utils.h"
+#include "sanitizer_common/sanitizer_internal_defs.h"
+#include <sanitizer/allocator_interface.h>
+#include <sanitizer/asan_interface.h>
+#include <vector>
+
+TEST(AddressSanitizerInterface, GetEstimatedAllocatedSize) {
+ EXPECT_EQ(0U, __sanitizer_get_estimated_allocated_size(0));
+ const size_t sizes[] = { 1, 30, 1<<30 };
+ for (size_t i = 0; i < 3; i++) {
+ EXPECT_EQ(sizes[i], __sanitizer_get_estimated_allocated_size(sizes[i]));
+ }
+}
+
+static const char* kGetAllocatedSizeErrorMsg =
+ "attempting to call __sanitizer_get_allocated_size";
+
+TEST(AddressSanitizerInterface, GetAllocatedSizeAndOwnershipTest) {
+ const size_t kArraySize = 100;
+ char *array = Ident((char*)malloc(kArraySize));
+ int *int_ptr = Ident(new int);
+
+ // Allocated memory is owned by allocator. Allocated size should be
+ // equal to requested size.
+ EXPECT_EQ(true, __sanitizer_get_ownership(array));
+ EXPECT_EQ(kArraySize, __sanitizer_get_allocated_size(array));
+ EXPECT_EQ(true, __sanitizer_get_ownership(int_ptr));
+ EXPECT_EQ(sizeof(int), __sanitizer_get_allocated_size(int_ptr));
+
+ // We cannot call GetAllocatedSize from the memory we didn't map,
+ // and from the interior pointers (not returned by previous malloc).
+ void *wild_addr = (void*)0x1;
+ EXPECT_FALSE(__sanitizer_get_ownership(wild_addr));
+ EXPECT_DEATH(__sanitizer_get_allocated_size(wild_addr),
+ kGetAllocatedSizeErrorMsg);
+ EXPECT_FALSE(__sanitizer_get_ownership(array + kArraySize / 2));
+ EXPECT_DEATH(__sanitizer_get_allocated_size(array + kArraySize / 2),
+ kGetAllocatedSizeErrorMsg);
+
+ // NULL is not owned, but is a valid argument for
+ // __sanitizer_get_allocated_size().
+ EXPECT_FALSE(__sanitizer_get_ownership(NULL));
+ EXPECT_EQ(0U, __sanitizer_get_allocated_size(NULL));
+
+ // When memory is freed, it's not owned, and call to GetAllocatedSize
+ // is forbidden.
+ free(array);
+ EXPECT_FALSE(__sanitizer_get_ownership(array));
+ EXPECT_DEATH(__sanitizer_get_allocated_size(array),
+ kGetAllocatedSizeErrorMsg);
+ delete int_ptr;
+
+ void *zero_alloc = Ident(malloc(0));
+ if (zero_alloc != 0) {
+ // If malloc(0) is not null, this pointer is owned and should have valid
+ // allocated size.
+ EXPECT_TRUE(__sanitizer_get_ownership(zero_alloc));
+ // Allocated size is 0 or 1 depending on the allocator used.
+ EXPECT_LT(__sanitizer_get_allocated_size(zero_alloc), 2U);
+ }
+ free(zero_alloc);
+}
+
+TEST(AddressSanitizerInterface, GetCurrentAllocatedBytesTest) {
+ size_t before_malloc, after_malloc, after_free;
+ char *array;
+ const size_t kMallocSize = 100;
+ before_malloc = __sanitizer_get_current_allocated_bytes();
+
+ array = Ident((char*)malloc(kMallocSize));
+ after_malloc = __sanitizer_get_current_allocated_bytes();
+ EXPECT_EQ(before_malloc + kMallocSize, after_malloc);
+
+ free(array);
+ after_free = __sanitizer_get_current_allocated_bytes();
+ EXPECT_EQ(before_malloc, after_free);
+}
+
+TEST(AddressSanitizerInterface, GetHeapSizeTest) {
+ // ASan allocator does not keep huge chunks in free list, but unmaps them.
+ // The chunk should be greater than the quarantine size,
+ // otherwise it will be stuck in quarantine instead of being unmaped.
+ static const size_t kLargeMallocSize = (1 << 28) + 1; // 256M
+ free(Ident(malloc(kLargeMallocSize))); // Drain quarantine.
+ size_t old_heap_size = __sanitizer_get_heap_size();
+ for (int i = 0; i < 3; i++) {
+ // fprintf(stderr, "allocating %zu bytes:\n", kLargeMallocSize);
+ free(Ident(malloc(kLargeMallocSize)));
+ EXPECT_EQ(old_heap_size, __sanitizer_get_heap_size());
+ }
+}
+
+#if !defined(__NetBSD__)
+static const size_t kManyThreadsMallocSizes[] = {5, 1UL<<10, 1UL<<14, 357};
+static const size_t kManyThreadsIterations = 250;
+static const size_t kManyThreadsNumThreads =
+ (SANITIZER_WORDSIZE == 32) ? 40 : 200;
+
+static void *ManyThreadsWithStatsWorker(void *arg) {
+ (void)arg;
+ for (size_t iter = 0; iter < kManyThreadsIterations; iter++) {
+ for (size_t size_index = 0; size_index < 4; size_index++) {
+ free(Ident(malloc(kManyThreadsMallocSizes[size_index])));
+ }
+ }
+ // Just one large allocation.
+ free(Ident(malloc(1 << 20)));
+ return 0;
+}
+
+TEST(AddressSanitizerInterface, ManyThreadsWithStatsStressTest) {
+ size_t before_test, after_test, i;
+ pthread_t threads[kManyThreadsNumThreads];
+ before_test = __sanitizer_get_current_allocated_bytes();
+ for (i = 0; i < kManyThreadsNumThreads; i++) {
+ PTHREAD_CREATE(&threads[i], 0,
+ (void* (*)(void *x))ManyThreadsWithStatsWorker, (void*)i);
+ }
+ for (i = 0; i < kManyThreadsNumThreads; i++) {
+ PTHREAD_JOIN(threads[i], 0);
+ }
+ after_test = __sanitizer_get_current_allocated_bytes();
+ // ASan stats also reflect memory usage of internal ASan RTL structs,
+ // so we can't check for equality here.
+ EXPECT_LT(after_test, before_test + (1UL<<20));
+}
+#endif
+
+static void DoDoubleFree() {
+ int *x = Ident(new int);
+ delete Ident(x);
+ delete Ident(x);
+}
+
+static void MyDeathCallback() {
+ fprintf(stderr, "MyDeathCallback\n");
+ fflush(0); // On Windows, stderr doesn't flush on crash.
+}
+
+TEST(AddressSanitizerInterface, DeathCallbackTest) {
+ __asan_set_death_callback(MyDeathCallback);
+ EXPECT_DEATH(DoDoubleFree(), "MyDeathCallback");
+ __asan_set_death_callback(NULL);
+}
+
+#define GOOD_ACCESS(ptr, offset) \
+ EXPECT_FALSE(__asan_address_is_poisoned(ptr + offset))
+
+#define BAD_ACCESS(ptr, offset) \
+ EXPECT_TRUE(__asan_address_is_poisoned(ptr + offset))
+
+#if !defined(ASAN_SHADOW_SCALE) || ASAN_SHADOW_SCALE == 3
+static const char* kUseAfterPoisonErrorMessage = "use-after-poison";
+
+TEST(AddressSanitizerInterface, SimplePoisonMemoryRegionTest) {
+ char *array = Ident((char*)malloc(120));
+ // poison array[40..80)
+ __asan_poison_memory_region(array + 40, 40);
+ GOOD_ACCESS(array, 39);
+ GOOD_ACCESS(array, 80);
+ BAD_ACCESS(array, 40);
+ BAD_ACCESS(array, 60);
+ BAD_ACCESS(array, 79);
+ char value;
+ EXPECT_DEATH(value = Ident(array[40]), kUseAfterPoisonErrorMessage);
+ __asan_unpoison_memory_region(array + 40, 40);
+ // access previously poisoned memory.
+ GOOD_ACCESS(array, 40);
+ GOOD_ACCESS(array, 79);
+ free(array);
+}
+
+TEST(AddressSanitizerInterface, OverlappingPoisonMemoryRegionTest) {
+ char *array = Ident((char*)malloc(120));
+ // Poison [0..40) and [80..120)
+ __asan_poison_memory_region(array, 40);
+ __asan_poison_memory_region(array + 80, 40);
+ BAD_ACCESS(array, 20);
+ GOOD_ACCESS(array, 60);
+ BAD_ACCESS(array, 100);
+ // Poison whole array - [0..120)
+ __asan_poison_memory_region(array, 120);
+ BAD_ACCESS(array, 60);
+ // Unpoison [24..96)
+ __asan_unpoison_memory_region(array + 24, 72);
+ BAD_ACCESS(array, 23);
+ GOOD_ACCESS(array, 24);
+ GOOD_ACCESS(array, 60);
+ GOOD_ACCESS(array, 95);
+ BAD_ACCESS(array, 96);
+ free(array);
+}
+#endif // !defined(ASAN_SHADOW_SCALE) || ASAN_SHADOW_SCALE == 3
+
+TEST(AddressSanitizerInterface, PushAndPopWithPoisoningTest) {
+ // Vector of capacity 20
+ char *vec = Ident((char*)malloc(20));
+ __asan_poison_memory_region(vec, 20);
+ for (size_t i = 0; i < 7; i++) {
+ // Simulate push_back.
+ __asan_unpoison_memory_region(vec + i, 1);
+ GOOD_ACCESS(vec, i);
+ BAD_ACCESS(vec, i + 1);
+ }
+ for (size_t i = 7; i > 0; i--) {
+ // Simulate pop_back.
+ __asan_poison_memory_region(vec + i - 1, 1);
+ BAD_ACCESS(vec, i - 1);
+ if (i > 1) GOOD_ACCESS(vec, i - 2);
+ }
+ free(vec);
+}
+
+#if !defined(ASAN_SHADOW_SCALE) || ASAN_SHADOW_SCALE == 3
+// Make sure that each aligned block of size "2^granularity" doesn't have
+// "true" value before "false" value.
+static void MakeShadowValid(bool *shadow, int length, int granularity) {
+ bool can_be_poisoned = true;
+ for (int i = length - 1; i >= 0; i--) {
+ if (!shadow[i])
+ can_be_poisoned = false;
+ if (!can_be_poisoned)
+ shadow[i] = false;
+ if (i % (1 << granularity) == 0) {
+ can_be_poisoned = true;
+ }
+ }
+}
+
+TEST(AddressSanitizerInterface, PoisoningStressTest) {
+ const size_t kSize = 24;
+ bool expected[kSize];
+ char *arr = Ident((char*)malloc(kSize));
+ for (size_t l1 = 0; l1 < kSize; l1++) {
+ for (size_t s1 = 1; l1 + s1 <= kSize; s1++) {
+ for (size_t l2 = 0; l2 < kSize; l2++) {
+ for (size_t s2 = 1; l2 + s2 <= kSize; s2++) {
+ // Poison [l1, l1+s1), [l2, l2+s2) and check result.
+ __asan_unpoison_memory_region(arr, kSize);
+ __asan_poison_memory_region(arr + l1, s1);
+ __asan_poison_memory_region(arr + l2, s2);
+ memset(expected, false, kSize);
+ memset(expected + l1, true, s1);
+ MakeShadowValid(expected, kSize, /*granularity*/ 3);
+ memset(expected + l2, true, s2);
+ MakeShadowValid(expected, kSize, /*granularity*/ 3);
+ for (size_t i = 0; i < kSize; i++) {
+ ASSERT_EQ(expected[i], __asan_address_is_poisoned(arr + i));
+ }
+ // Unpoison [l1, l1+s1) and [l2, l2+s2) and check result.
+ __asan_poison_memory_region(arr, kSize);
+ __asan_unpoison_memory_region(arr + l1, s1);
+ __asan_unpoison_memory_region(arr + l2, s2);
+ memset(expected, true, kSize);
+ memset(expected + l1, false, s1);
+ MakeShadowValid(expected, kSize, /*granularity*/ 3);
+ memset(expected + l2, false, s2);
+ MakeShadowValid(expected, kSize, /*granularity*/ 3);
+ for (size_t i = 0; i < kSize; i++) {
+ ASSERT_EQ(expected[i], __asan_address_is_poisoned(arr + i));
+ }
+ }
+ }
+ }
+ }
+ free(arr);
+}
+#endif // !defined(ASAN_SHADOW_SCALE) || ASAN_SHADOW_SCALE == 3
+
+TEST(AddressSanitizerInterface, GlobalRedzones) {
+ GOOD_ACCESS(glob1, 1 - 1);
+ GOOD_ACCESS(glob2, 2 - 1);
+ GOOD_ACCESS(glob3, 3 - 1);
+ GOOD_ACCESS(glob4, 4 - 1);
+ GOOD_ACCESS(glob5, 5 - 1);
+ GOOD_ACCESS(glob6, 6 - 1);
+ GOOD_ACCESS(glob7, 7 - 1);
+ GOOD_ACCESS(glob8, 8 - 1);
+ GOOD_ACCESS(glob9, 9 - 1);
+ GOOD_ACCESS(glob10, 10 - 1);
+ GOOD_ACCESS(glob11, 11 - 1);
+ GOOD_ACCESS(glob12, 12 - 1);
+ GOOD_ACCESS(glob13, 13 - 1);
+ GOOD_ACCESS(glob14, 14 - 1);
+ GOOD_ACCESS(glob15, 15 - 1);
+ GOOD_ACCESS(glob16, 16 - 1);
+ GOOD_ACCESS(glob17, 17 - 1);
+ GOOD_ACCESS(glob1000, 1000 - 1);
+ GOOD_ACCESS(glob10000, 10000 - 1);
+ GOOD_ACCESS(glob100000, 100000 - 1);
+
+ BAD_ACCESS(glob1, 1);
+ BAD_ACCESS(glob2, 2);
+ BAD_ACCESS(glob3, 3);
+ BAD_ACCESS(glob4, 4);
+ BAD_ACCESS(glob5, 5);
+ BAD_ACCESS(glob6, 6);
+ BAD_ACCESS(glob7, 7);
+ BAD_ACCESS(glob8, 8);
+ BAD_ACCESS(glob9, 9);
+ BAD_ACCESS(glob10, 10);
+ BAD_ACCESS(glob11, 11);
+ BAD_ACCESS(glob12, 12);
+ BAD_ACCESS(glob13, 13);
+ BAD_ACCESS(glob14, 14);
+ BAD_ACCESS(glob15, 15);
+ BAD_ACCESS(glob16, 16);
+ BAD_ACCESS(glob17, 17);
+ BAD_ACCESS(glob1000, 1000);
+ BAD_ACCESS(glob1000, 1100); // Redzone is at least 101 bytes.
+ BAD_ACCESS(glob10000, 10000);
+ BAD_ACCESS(glob10000, 11000); // Redzone is at least 1001 bytes.
+ BAD_ACCESS(glob100000, 100000);
+ BAD_ACCESS(glob100000, 110000); // Redzone is at least 10001 bytes.
+}
+
+TEST(AddressSanitizerInterface, PoisonedRegion) {
+ size_t rz = 16;
+ for (size_t size = 1; size <= 64; size++) {
+ char *p = new char[size];
+ for (size_t beg = 0; beg < size + rz; beg++) {
+ for (size_t end = beg; end < size + rz; end++) {
+ void *first_poisoned = __asan_region_is_poisoned(p + beg, end - beg);
+ if (beg == end) {
+ EXPECT_FALSE(first_poisoned);
+ } else if (beg < size && end <= size) {
+ EXPECT_FALSE(first_poisoned);
+ } else if (beg >= size) {
+ EXPECT_EQ(p + beg, first_poisoned);
+ } else {
+ EXPECT_GT(end, size);
+ EXPECT_EQ(p + size, first_poisoned);
+ }
+ }
+ }
+ delete [] p;
+ }
+}
+
+// This is a performance benchmark for manual runs.
+// asan's memset interceptor calls mem_is_zero for the entire shadow region.
+// the profile should look like this:
+// 89.10% [.] __memset_sse2
+// 10.50% [.] __sanitizer::mem_is_zero
+// I.e. mem_is_zero should consume ~ SHADOW_GRANULARITY less CPU cycles
+// than memset itself.
+TEST(AddressSanitizerInterface, DISABLED_StressLargeMemset) {
+ size_t size = 1 << 20;
+ char *x = new char[size];
+ for (int i = 0; i < 100000; i++)
+ Ident(memset)(x, 0, size);
+ delete [] x;
+}
+
+// Same here, but we run memset with small sizes.
+TEST(AddressSanitizerInterface, DISABLED_StressSmallMemset) {
+ size_t size = 32;
+ char *x = new char[size];
+ for (int i = 0; i < 100000000; i++)
+ Ident(memset)(x, 0, size);
+ delete [] x;
+}
+static const char *kInvalidPoisonMessage = "invalid-poison-memory-range";
+static const char *kInvalidUnpoisonMessage = "invalid-unpoison-memory-range";
+
+TEST(AddressSanitizerInterface, DISABLED_InvalidPoisonAndUnpoisonCallsTest) {
+ char *array = Ident((char*)malloc(120));
+ __asan_unpoison_memory_region(array, 120);
+ // Try to unpoison not owned memory
+ EXPECT_DEATH(__asan_unpoison_memory_region(array, 121),
+ kInvalidUnpoisonMessage);
+ EXPECT_DEATH(__asan_unpoison_memory_region(array - 1, 120),
+ kInvalidUnpoisonMessage);
+
+ __asan_poison_memory_region(array, 120);
+ // Try to poison not owned memory.
+ EXPECT_DEATH(__asan_poison_memory_region(array, 121), kInvalidPoisonMessage);
+ EXPECT_DEATH(__asan_poison_memory_region(array - 1, 120),
+ kInvalidPoisonMessage);
+ free(array);
+}
+
+TEST(AddressSanitizerInterface, GetOwnershipStressTest) {
+ std::vector<char *> pointers;
+ std::vector<size_t> sizes;
+ const size_t kNumMallocs = 1 << 9;
+ for (size_t i = 0; i < kNumMallocs; i++) {
+ size_t size = i * 100 + 1;
+ pointers.push_back((char*)malloc(size));
+ sizes.push_back(size);
+ }
+ for (size_t i = 0; i < 4000000; i++) {
+ EXPECT_FALSE(__sanitizer_get_ownership(&pointers));
+ EXPECT_FALSE(__sanitizer_get_ownership((void*)0x1234));
+ size_t idx = i % kNumMallocs;
+ EXPECT_TRUE(__sanitizer_get_ownership(pointers[idx]));
+ EXPECT_EQ(sizes[idx], __sanitizer_get_allocated_size(pointers[idx]));
+ }
+ for (size_t i = 0, n = pointers.size(); i < n; i++)
+ free(pointers[i]);
+}
+
+TEST(AddressSanitizerInterface, HandleNoReturnTest) {
+ char array[40];
+ __asan_poison_memory_region(array, sizeof(array));
+ BAD_ACCESS(array, 20);
+ __asan_handle_no_return();
+ // It unpoisons the whole thread stack.
+ GOOD_ACCESS(array, 20);
+}
+++ /dev/null
-//===-- asan_internal_interface_test.cc -----------------------------------===//
-//
-// 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
-//
-//===----------------------------------------------------------------------===//
-//
-// This file is a part of AddressSanitizer, an address sanity checker.
-//
-//===----------------------------------------------------------------------===//
-#include "asan_interface_internal.h"
-#include "asan_test_utils.h"
-#include <vector>
-
-TEST(AddressSanitizerInternalInterface, SetShadow) {
- std::vector<char> buffer(17, 0xff);
-
- __asan_set_shadow_00((uptr)buffer.data(), buffer.size());
- EXPECT_EQ(std::vector<char>(buffer.size(), 0x00), buffer);
-
- __asan_set_shadow_f1((uptr)buffer.data(), buffer.size());
- EXPECT_EQ(std::vector<char>(buffer.size(), 0xf1), buffer);
-
- __asan_set_shadow_f2((uptr)buffer.data(), buffer.size());
- EXPECT_EQ(std::vector<char>(buffer.size(), 0xf2), buffer);
-
- __asan_set_shadow_f3((uptr)buffer.data(), buffer.size());
- EXPECT_EQ(std::vector<char>(buffer.size(), 0xf3), buffer);
-
- __asan_set_shadow_f5((uptr)buffer.data(), buffer.size());
- EXPECT_EQ(std::vector<char>(buffer.size(), 0xf5), buffer);
-
- __asan_set_shadow_f8((uptr)buffer.data(), buffer.size());
- EXPECT_EQ(std::vector<char>(buffer.size(), 0xf8), buffer);
-}
--- /dev/null
+//===-- asan_internal_interface_test.cpp ----------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a part of AddressSanitizer, an address sanity checker.
+//
+//===----------------------------------------------------------------------===//
+#include "asan_interface_internal.h"
+#include "asan_test_utils.h"
+#include <vector>
+
+TEST(AddressSanitizerInternalInterface, SetShadow) {
+ std::vector<char> buffer(17, 0xff);
+
+ __asan_set_shadow_00((uptr)buffer.data(), buffer.size());
+ EXPECT_EQ(std::vector<char>(buffer.size(), 0x00), buffer);
+
+ __asan_set_shadow_f1((uptr)buffer.data(), buffer.size());
+ EXPECT_EQ(std::vector<char>(buffer.size(), 0xf1), buffer);
+
+ __asan_set_shadow_f2((uptr)buffer.data(), buffer.size());
+ EXPECT_EQ(std::vector<char>(buffer.size(), 0xf2), buffer);
+
+ __asan_set_shadow_f3((uptr)buffer.data(), buffer.size());
+ EXPECT_EQ(std::vector<char>(buffer.size(), 0xf3), buffer);
+
+ __asan_set_shadow_f5((uptr)buffer.data(), buffer.size());
+ EXPECT_EQ(std::vector<char>(buffer.size(), 0xf5), buffer);
+
+ __asan_set_shadow_f8((uptr)buffer.data(), buffer.size());
+ EXPECT_EQ(std::vector<char>(buffer.size(), 0xf8), buffer);
+}
+++ /dev/null
-//===-- asan_test_mac.cc --------------------------------------------------===//
-//
-// 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
-//
-//===----------------------------------------------------------------------===//
-//
-// This file is a part of AddressSanitizer, an address sanity checker.
-//
-//===----------------------------------------------------------------------===//
-
-#include "asan_test_utils.h"
-
-#include "asan_mac_test.h"
-
-#include <malloc/malloc.h>
-#include <AvailabilityMacros.h> // For MAC_OS_X_VERSION_*
-#include <CoreFoundation/CFString.h>
-
-TEST(AddressSanitizerMac, CFAllocatorDefaultDoubleFree) {
- EXPECT_DEATH(
- CFAllocatorDefaultDoubleFree(NULL),
- "attempting double-free");
-}
-
-void CFAllocator_DoubleFreeOnPthread() {
- pthread_t child;
- PTHREAD_CREATE(&child, NULL, CFAllocatorDefaultDoubleFree, NULL);
- PTHREAD_JOIN(child, NULL); // Shouldn't be reached.
-}
-
-TEST(AddressSanitizerMac, CFAllocatorDefaultDoubleFree_ChildPhread) {
- EXPECT_DEATH(CFAllocator_DoubleFreeOnPthread(), "attempting double-free");
-}
-
-namespace {
-
-void *GLOB;
-
-void *CFAllocatorAllocateToGlob(void *unused) {
- GLOB = CFAllocatorAllocate(NULL, 100, /*hint*/0);
- return NULL;
-}
-
-void *CFAllocatorDeallocateFromGlob(void *unused) {
- char *p = (char*)GLOB;
- p[100] = 'A'; // ASan should report an error here.
- CFAllocatorDeallocate(NULL, GLOB);
- return NULL;
-}
-
-void CFAllocator_PassMemoryToAnotherThread() {
- pthread_t th1, th2;
- PTHREAD_CREATE(&th1, NULL, CFAllocatorAllocateToGlob, NULL);
- PTHREAD_JOIN(th1, NULL);
- PTHREAD_CREATE(&th2, NULL, CFAllocatorDeallocateFromGlob, NULL);
- PTHREAD_JOIN(th2, NULL);
-}
-
-TEST(AddressSanitizerMac, CFAllocator_PassMemoryToAnotherThread) {
- EXPECT_DEATH(CFAllocator_PassMemoryToAnotherThread(),
- "heap-buffer-overflow");
-}
-
-} // namespace
-
-// TODO(glider): figure out whether we still need these tests. Is it correct
-// to intercept the non-default CFAllocators?
-TEST(AddressSanitizerMac, DISABLED_CFAllocatorSystemDefaultDoubleFree) {
- EXPECT_DEATH(
- CFAllocatorSystemDefaultDoubleFree(),
- "attempting double-free");
-}
-
-// We're intercepting malloc, so kCFAllocatorMalloc is routed to ASan.
-TEST(AddressSanitizerMac, CFAllocatorMallocDoubleFree) {
- EXPECT_DEATH(CFAllocatorMallocDoubleFree(), "attempting double-free");
-}
-
-TEST(AddressSanitizerMac, DISABLED_CFAllocatorMallocZoneDoubleFree) {
- EXPECT_DEATH(CFAllocatorMallocZoneDoubleFree(), "attempting double-free");
-}
-
-// For libdispatch tests below we check that ASan got to the shadow byte
-// legend, i.e. managed to print the thread stacks (this almost certainly
-// means that the libdispatch task creation has been intercepted correctly).
-TEST(AddressSanitizerMac, GCDDispatchAsync) {
- // Make sure the whole ASan report is printed, i.e. that we don't die
- // on a CHECK.
- EXPECT_DEATH(TestGCDDispatchAsync(), "Shadow byte legend");
-}
-
-TEST(AddressSanitizerMac, GCDDispatchSync) {
- // Make sure the whole ASan report is printed, i.e. that we don't die
- // on a CHECK.
- EXPECT_DEATH(TestGCDDispatchSync(), "Shadow byte legend");
-}
-
-
-TEST(AddressSanitizerMac, GCDReuseWqthreadsAsync) {
- // Make sure the whole ASan report is printed, i.e. that we don't die
- // on a CHECK.
- EXPECT_DEATH(TestGCDReuseWqthreadsAsync(), "Shadow byte legend");
-}
-
-TEST(AddressSanitizerMac, GCDReuseWqthreadsSync) {
- // Make sure the whole ASan report is printed, i.e. that we don't die
- // on a CHECK.
- EXPECT_DEATH(TestGCDReuseWqthreadsSync(), "Shadow byte legend");
-}
-
-TEST(AddressSanitizerMac, GCDDispatchAfter) {
- // Make sure the whole ASan report is printed, i.e. that we don't die
- // on a CHECK.
- EXPECT_DEATH(TestGCDDispatchAfter(), "Shadow byte legend");
-}
-
-TEST(AddressSanitizerMac, GCDSourceEvent) {
- // Make sure the whole ASan report is printed, i.e. that we don't die
- // on a CHECK.
- EXPECT_DEATH(TestGCDSourceEvent(), "Shadow byte legend");
-}
-
-TEST(AddressSanitizerMac, GCDSourceCancel) {
- // Make sure the whole ASan report is printed, i.e. that we don't die
- // on a CHECK.
- EXPECT_DEATH(TestGCDSourceCancel(), "Shadow byte legend");
-}
-
-TEST(AddressSanitizerMac, GCDGroupAsync) {
- // Make sure the whole ASan report is printed, i.e. that we don't die
- // on a CHECK.
- EXPECT_DEATH(TestGCDGroupAsync(), "Shadow byte legend");
-}
-
-void *MallocIntrospectionLockWorker(void *_) {
- const int kNumPointers = 100;
- int i;
- void *pointers[kNumPointers];
- for (i = 0; i < kNumPointers; i++) {
- pointers[i] = malloc(i + 1);
- }
- for (i = 0; i < kNumPointers; i++) {
- free(pointers[i]);
- }
-
- return NULL;
-}
-
-void *MallocIntrospectionLockForker(void *_) {
- pid_t result = fork();
- if (result == -1) {
- perror("fork");
- }
- assert(result != -1);
- if (result == 0) {
- // Call malloc in the child process to make sure we won't deadlock.
- void *ptr = malloc(42);
- free(ptr);
- exit(0);
- } else {
- // Return in the parent process.
- return NULL;
- }
-}
-
-TEST(AddressSanitizerMac, MallocIntrospectionLock) {
- // Incorrect implementation of force_lock and force_unlock in our malloc zone
- // will cause forked processes to deadlock.
- // TODO(glider): need to detect that none of the child processes deadlocked.
- const int kNumWorkers = 5, kNumIterations = 100;
- int i, iter;
- for (iter = 0; iter < kNumIterations; iter++) {
- pthread_t workers[kNumWorkers], forker;
- for (i = 0; i < kNumWorkers; i++) {
- PTHREAD_CREATE(&workers[i], 0, MallocIntrospectionLockWorker, 0);
- }
- PTHREAD_CREATE(&forker, 0, MallocIntrospectionLockForker, 0);
- for (i = 0; i < kNumWorkers; i++) {
- PTHREAD_JOIN(workers[i], 0);
- }
- PTHREAD_JOIN(forker, 0);
- }
-}
-
-void *TSDAllocWorker(void *test_key) {
- if (test_key) {
- void *mem = malloc(10);
- pthread_setspecific(*(pthread_key_t*)test_key, mem);
- }
- return NULL;
-}
-
-TEST(AddressSanitizerMac, DISABLED_TSDWorkqueueTest) {
- pthread_t th;
- pthread_key_t test_key;
- pthread_key_create(&test_key, CallFreeOnWorkqueue);
- PTHREAD_CREATE(&th, NULL, TSDAllocWorker, &test_key);
- PTHREAD_JOIN(th, NULL);
- pthread_key_delete(test_key);
-}
-
-// Test that CFStringCreateCopy does not copy constant strings.
-TEST(AddressSanitizerMac, CFStringCreateCopy) {
- CFStringRef str = CFSTR("Hello world!\n");
- CFStringRef str2 = CFStringCreateCopy(0, str);
- EXPECT_EQ(str, str2);
-}
-
-TEST(AddressSanitizerMac, NSObjectOOB) {
- // Make sure that our allocators are used for NSObjects.
- EXPECT_DEATH(TestOOBNSObjects(), "heap-buffer-overflow");
-}
-
-// Make sure that correct pointer is passed to free() when deallocating a
-// NSURL object.
-// See https://github.com/google/sanitizers/issues/70.
-TEST(AddressSanitizerMac, NSURLDeallocation) {
- TestNSURLDeallocation();
-}
-
-// See https://github.com/google/sanitizers/issues/109.
-TEST(AddressSanitizerMac, Mstats) {
- malloc_statistics_t stats1, stats2;
- malloc_zone_statistics(/*all zones*/NULL, &stats1);
- const size_t kMallocSize = 100000;
- void *alloc = Ident(malloc(kMallocSize));
- malloc_zone_statistics(/*all zones*/NULL, &stats2);
- EXPECT_GT(stats2.blocks_in_use, stats1.blocks_in_use);
- EXPECT_GE(stats2.size_in_use - stats1.size_in_use, kMallocSize);
- free(alloc);
- // Even the default OSX allocator may not change the stats after free().
-}
-
--- /dev/null
+//===-- asan_test_mac.cpp -------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a part of AddressSanitizer, an address sanity checker.
+//
+//===----------------------------------------------------------------------===//
+
+#include "asan_test_utils.h"
+
+#include "asan_mac_test.h"
+
+#include <malloc/malloc.h>
+#include <AvailabilityMacros.h> // For MAC_OS_X_VERSION_*
+#include <CoreFoundation/CFString.h>
+
+TEST(AddressSanitizerMac, CFAllocatorDefaultDoubleFree) {
+ EXPECT_DEATH(
+ CFAllocatorDefaultDoubleFree(NULL),
+ "attempting double-free");
+}
+
+void CFAllocator_DoubleFreeOnPthread() {
+ pthread_t child;
+ PTHREAD_CREATE(&child, NULL, CFAllocatorDefaultDoubleFree, NULL);
+ PTHREAD_JOIN(child, NULL); // Shouldn't be reached.
+}
+
+TEST(AddressSanitizerMac, CFAllocatorDefaultDoubleFree_ChildPhread) {
+ EXPECT_DEATH(CFAllocator_DoubleFreeOnPthread(), "attempting double-free");
+}
+
+namespace {
+
+void *GLOB;
+
+void *CFAllocatorAllocateToGlob(void *unused) {
+ GLOB = CFAllocatorAllocate(NULL, 100, /*hint*/0);
+ return NULL;
+}
+
+void *CFAllocatorDeallocateFromGlob(void *unused) {
+ char *p = (char*)GLOB;
+ p[100] = 'A'; // ASan should report an error here.
+ CFAllocatorDeallocate(NULL, GLOB);
+ return NULL;
+}
+
+void CFAllocator_PassMemoryToAnotherThread() {
+ pthread_t th1, th2;
+ PTHREAD_CREATE(&th1, NULL, CFAllocatorAllocateToGlob, NULL);
+ PTHREAD_JOIN(th1, NULL);
+ PTHREAD_CREATE(&th2, NULL, CFAllocatorDeallocateFromGlob, NULL);
+ PTHREAD_JOIN(th2, NULL);
+}
+
+TEST(AddressSanitizerMac, CFAllocator_PassMemoryToAnotherThread) {
+ EXPECT_DEATH(CFAllocator_PassMemoryToAnotherThread(),
+ "heap-buffer-overflow");
+}
+
+} // namespace
+
+// TODO(glider): figure out whether we still need these tests. Is it correct
+// to intercept the non-default CFAllocators?
+TEST(AddressSanitizerMac, DISABLED_CFAllocatorSystemDefaultDoubleFree) {
+ EXPECT_DEATH(
+ CFAllocatorSystemDefaultDoubleFree(),
+ "attempting double-free");
+}
+
+// We're intercepting malloc, so kCFAllocatorMalloc is routed to ASan.
+TEST(AddressSanitizerMac, CFAllocatorMallocDoubleFree) {
+ EXPECT_DEATH(CFAllocatorMallocDoubleFree(), "attempting double-free");
+}
+
+TEST(AddressSanitizerMac, DISABLED_CFAllocatorMallocZoneDoubleFree) {
+ EXPECT_DEATH(CFAllocatorMallocZoneDoubleFree(), "attempting double-free");
+}
+
+// For libdispatch tests below we check that ASan got to the shadow byte
+// legend, i.e. managed to print the thread stacks (this almost certainly
+// means that the libdispatch task creation has been intercepted correctly).
+TEST(AddressSanitizerMac, GCDDispatchAsync) {
+ // Make sure the whole ASan report is printed, i.e. that we don't die
+ // on a CHECK.
+ EXPECT_DEATH(TestGCDDispatchAsync(), "Shadow byte legend");
+}
+
+TEST(AddressSanitizerMac, GCDDispatchSync) {
+ // Make sure the whole ASan report is printed, i.e. that we don't die
+ // on a CHECK.
+ EXPECT_DEATH(TestGCDDispatchSync(), "Shadow byte legend");
+}
+
+
+TEST(AddressSanitizerMac, GCDReuseWqthreadsAsync) {
+ // Make sure the whole ASan report is printed, i.e. that we don't die
+ // on a CHECK.
+ EXPECT_DEATH(TestGCDReuseWqthreadsAsync(), "Shadow byte legend");
+}
+
+TEST(AddressSanitizerMac, GCDReuseWqthreadsSync) {
+ // Make sure the whole ASan report is printed, i.e. that we don't die
+ // on a CHECK.
+ EXPECT_DEATH(TestGCDReuseWqthreadsSync(), "Shadow byte legend");
+}
+
+TEST(AddressSanitizerMac, GCDDispatchAfter) {
+ // Make sure the whole ASan report is printed, i.e. that we don't die
+ // on a CHECK.
+ EXPECT_DEATH(TestGCDDispatchAfter(), "Shadow byte legend");
+}
+
+TEST(AddressSanitizerMac, GCDSourceEvent) {
+ // Make sure the whole ASan report is printed, i.e. that we don't die
+ // on a CHECK.
+ EXPECT_DEATH(TestGCDSourceEvent(), "Shadow byte legend");
+}
+
+TEST(AddressSanitizerMac, GCDSourceCancel) {
+ // Make sure the whole ASan report is printed, i.e. that we don't die
+ // on a CHECK.
+ EXPECT_DEATH(TestGCDSourceCancel(), "Shadow byte legend");
+}
+
+TEST(AddressSanitizerMac, GCDGroupAsync) {
+ // Make sure the whole ASan report is printed, i.e. that we don't die
+ // on a CHECK.
+ EXPECT_DEATH(TestGCDGroupAsync(), "Shadow byte legend");
+}
+
+void *MallocIntrospectionLockWorker(void *_) {
+ const int kNumPointers = 100;
+ int i;
+ void *pointers[kNumPointers];
+ for (i = 0; i < kNumPointers; i++) {
+ pointers[i] = malloc(i + 1);
+ }
+ for (i = 0; i < kNumPointers; i++) {
+ free(pointers[i]);
+ }
+
+ return NULL;
+}
+
+void *MallocIntrospectionLockForker(void *_) {
+ pid_t result = fork();
+ if (result == -1) {
+ perror("fork");
+ }
+ assert(result != -1);
+ if (result == 0) {
+ // Call malloc in the child process to make sure we won't deadlock.
+ void *ptr = malloc(42);
+ free(ptr);
+ exit(0);
+ } else {
+ // Return in the parent process.
+ return NULL;
+ }
+}
+
+TEST(AddressSanitizerMac, MallocIntrospectionLock) {
+ // Incorrect implementation of force_lock and force_unlock in our malloc zone
+ // will cause forked processes to deadlock.
+ // TODO(glider): need to detect that none of the child processes deadlocked.
+ const int kNumWorkers = 5, kNumIterations = 100;
+ int i, iter;
+ for (iter = 0; iter < kNumIterations; iter++) {
+ pthread_t workers[kNumWorkers], forker;
+ for (i = 0; i < kNumWorkers; i++) {
+ PTHREAD_CREATE(&workers[i], 0, MallocIntrospectionLockWorker, 0);
+ }
+ PTHREAD_CREATE(&forker, 0, MallocIntrospectionLockForker, 0);
+ for (i = 0; i < kNumWorkers; i++) {
+ PTHREAD_JOIN(workers[i], 0);
+ }
+ PTHREAD_JOIN(forker, 0);
+ }
+}
+
+void *TSDAllocWorker(void *test_key) {
+ if (test_key) {
+ void *mem = malloc(10);
+ pthread_setspecific(*(pthread_key_t*)test_key, mem);
+ }
+ return NULL;
+}
+
+TEST(AddressSanitizerMac, DISABLED_TSDWorkqueueTest) {
+ pthread_t th;
+ pthread_key_t test_key;
+ pthread_key_create(&test_key, CallFreeOnWorkqueue);
+ PTHREAD_CREATE(&th, NULL, TSDAllocWorker, &test_key);
+ PTHREAD_JOIN(th, NULL);
+ pthread_key_delete(test_key);
+}
+
+// Test that CFStringCreateCopy does not copy constant strings.
+TEST(AddressSanitizerMac, CFStringCreateCopy) {
+ CFStringRef str = CFSTR("Hello world!\n");
+ CFStringRef str2 = CFStringCreateCopy(0, str);
+ EXPECT_EQ(str, str2);
+}
+
+TEST(AddressSanitizerMac, NSObjectOOB) {
+ // Make sure that our allocators are used for NSObjects.
+ EXPECT_DEATH(TestOOBNSObjects(), "heap-buffer-overflow");
+}
+
+// Make sure that correct pointer is passed to free() when deallocating a
+// NSURL object.
+// See https://github.com/google/sanitizers/issues/70.
+TEST(AddressSanitizerMac, NSURLDeallocation) {
+ TestNSURLDeallocation();
+}
+
+// See https://github.com/google/sanitizers/issues/109.
+TEST(AddressSanitizerMac, Mstats) {
+ malloc_statistics_t stats1, stats2;
+ malloc_zone_statistics(/*all zones*/NULL, &stats1);
+ const size_t kMallocSize = 100000;
+ void *alloc = Ident(malloc(kMallocSize));
+ malloc_zone_statistics(/*all zones*/NULL, &stats2);
+ EXPECT_GT(stats2.blocks_in_use, stats1.blocks_in_use);
+ EXPECT_GE(stats2.size_in_use - stats1.size_in_use, kMallocSize);
+ free(alloc);
+ // Even the default OSX allocator may not change the stats after free().
+}
+
+++ /dev/null
-//===-- asan_mem_test.cc --------------------------------------------------===//
-//
-// 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
-//
-//===----------------------------------------------------------------------===//
-//
-// This file is a part of AddressSanitizer, an address sanity checker.
-//
-//===----------------------------------------------------------------------===//
-#include <string.h>
-#include "asan_test_utils.h"
-#if defined(_GNU_SOURCE)
-#include <strings.h> // for bcmp
-#endif
-#include <vector>
-
-template<typename T>
-void MemSetOOBTestTemplate(size_t length) {
- if (length == 0) return;
- size_t size = Ident(sizeof(T) * length);
- T *array = Ident((T*)malloc(size));
- int element = Ident(42);
- int zero = Ident(0);
- void *(*MEMSET)(void *s, int c, size_t n) = Ident(memset);
- // memset interval inside array
- MEMSET(array, element, size);
- MEMSET(array, element, size - 1);
- MEMSET(array + length - 1, element, sizeof(T));
- MEMSET(array, element, 1);
-
- // memset 0 bytes
- MEMSET(array - 10, element, zero);
- MEMSET(array - 1, element, zero);
- MEMSET(array, element, zero);
- MEMSET(array + length, 0, zero);
- MEMSET(array + length + 1, 0, zero);
-
- // try to memset bytes to the right of array
- EXPECT_DEATH(MEMSET(array, 0, size + 1),
- RightOOBWriteMessage(0));
- EXPECT_DEATH(MEMSET((char*)(array + length) - 1, element, 6),
- RightOOBWriteMessage(0));
- EXPECT_DEATH(MEMSET(array + 1, element, size + sizeof(T)),
- RightOOBWriteMessage(0));
- // whole interval is to the right
- EXPECT_DEATH(MEMSET(array + length + 1, 0, 10),
- RightOOBWriteMessage(sizeof(T)));
-
- // try to memset bytes to the left of array
- EXPECT_DEATH(MEMSET((char*)array - 1, element, size),
- LeftOOBWriteMessage(1));
- EXPECT_DEATH(MEMSET((char*)array - 5, 0, 6),
- LeftOOBWriteMessage(5));
- if (length >= 100) {
- // Large OOB, we find it only if the redzone is large enough.
- EXPECT_DEATH(memset(array - 5, element, size + 5 * sizeof(T)),
- LeftOOBWriteMessage(5 * sizeof(T)));
- }
- // whole interval is to the left
- EXPECT_DEATH(MEMSET(array - 2, 0, sizeof(T)),
- LeftOOBWriteMessage(2 * sizeof(T)));
-
- // try to memset bytes both to the left & to the right
- EXPECT_DEATH(MEMSET((char*)array - 2, element, size + 4),
- LeftOOBWriteMessage(2));
-
- free(array);
-}
-
-TEST(AddressSanitizer, MemSetOOBTest) {
- MemSetOOBTestTemplate<char>(100);
- MemSetOOBTestTemplate<int>(5);
- MemSetOOBTestTemplate<double>(256);
- // We can test arrays of structres/classes here, but what for?
-}
-
-// Try to allocate two arrays of 'size' bytes that are near each other.
-// Strictly speaking we are not guaranteed to find such two pointers,
-// but given the structure of asan's allocator we will.
-static bool AllocateTwoAdjacentArrays(char **x1, char **x2, size_t size) {
- std::vector<uintptr_t> v;
- bool res = false;
- for (size_t i = 0; i < 1000U && !res; i++) {
- v.push_back(reinterpret_cast<uintptr_t>(new char[size]));
- if (i == 0) continue;
- sort(v.begin(), v.end());
- for (size_t j = 1; j < v.size(); j++) {
- assert(v[j] > v[j-1]);
- if ((size_t)(v[j] - v[j-1]) < size * 2) {
- *x2 = reinterpret_cast<char*>(v[j]);
- *x1 = reinterpret_cast<char*>(v[j-1]);
- res = true;
- break;
- }
- }
- }
-
- for (size_t i = 0; i < v.size(); i++) {
- char *p = reinterpret_cast<char *>(v[i]);
- if (res && p == *x1) continue;
- if (res && p == *x2) continue;
- delete [] p;
- }
- return res;
-}
-
-TEST(AddressSanitizer, LargeOOBInMemset) {
- for (size_t size = 200; size < 100000; size += size / 2) {
- char *x1, *x2;
- if (!Ident(AllocateTwoAdjacentArrays)(&x1, &x2, size))
- continue;
- // fprintf(stderr, " large oob memset: %p %p %zd\n", x1, x2, size);
- // Do a memset on x1 with huge out-of-bound access that will end up in x2.
- EXPECT_DEATH(Ident(memset)(x1, 0, size * 2),
- "is located 0 bytes to the right");
- delete [] x1;
- delete [] x2;
- return;
- }
- assert(0 && "Did not find two adjacent malloc-ed pointers");
-}
-
-// Same test for memcpy and memmove functions
-template <typename T, class M>
-void MemTransferOOBTestTemplate(size_t length) {
- if (length == 0) return;
- size_t size = Ident(sizeof(T) * length);
- T *src = Ident((T*)malloc(size));
- T *dest = Ident((T*)malloc(size));
- int zero = Ident(0);
-
- // valid transfer of bytes between arrays
- M::transfer(dest, src, size);
- M::transfer(dest + 1, src, size - sizeof(T));
- M::transfer(dest, src + length - 1, sizeof(T));
- M::transfer(dest, src, 1);
-
- // transfer zero bytes
- M::transfer(dest - 1, src, 0);
- M::transfer(dest + length, src, zero);
- M::transfer(dest, src - 1, zero);
- M::transfer(dest, src, zero);
-
- // try to change mem to the right of dest
- EXPECT_DEATH(M::transfer(dest + 1, src, size),
- RightOOBWriteMessage(0));
- EXPECT_DEATH(M::transfer((char*)(dest + length) - 1, src, 5),
- RightOOBWriteMessage(0));
-
- // try to change mem to the left of dest
- EXPECT_DEATH(M::transfer(dest - 2, src, size),
- LeftOOBWriteMessage(2 * sizeof(T)));
- EXPECT_DEATH(M::transfer((char*)dest - 3, src, 4),
- LeftOOBWriteMessage(3));
-
- // try to access mem to the right of src
- EXPECT_DEATH(M::transfer(dest, src + 2, size),
- RightOOBReadMessage(0));
- EXPECT_DEATH(M::transfer(dest, (char*)(src + length) - 3, 6),
- RightOOBReadMessage(0));
-
- // try to access mem to the left of src
- EXPECT_DEATH(M::transfer(dest, src - 1, size),
- LeftOOBReadMessage(sizeof(T)));
- EXPECT_DEATH(M::transfer(dest, (char*)src - 6, 7),
- LeftOOBReadMessage(6));
-
- // Generally we don't need to test cases where both accessing src and writing
- // to dest address to poisoned memory.
-
- T *big_src = Ident((T*)malloc(size * 2));
- T *big_dest = Ident((T*)malloc(size * 2));
- // try to change mem to both sides of dest
- EXPECT_DEATH(M::transfer(dest - 1, big_src, size * 2),
- LeftOOBWriteMessage(sizeof(T)));
- // try to access mem to both sides of src
- EXPECT_DEATH(M::transfer(big_dest, src - 2, size * 2),
- LeftOOBReadMessage(2 * sizeof(T)));
-
- free(src);
- free(dest);
- free(big_src);
- free(big_dest);
-}
-
-class MemCpyWrapper {
- public:
- static void* transfer(void *to, const void *from, size_t size) {
- return Ident(memcpy)(to, from, size);
- }
-};
-
-TEST(AddressSanitizer, MemCpyOOBTest) {
- MemTransferOOBTestTemplate<char, MemCpyWrapper>(100);
- MemTransferOOBTestTemplate<int, MemCpyWrapper>(1024);
-}
-
-class MemMoveWrapper {
- public:
- static void* transfer(void *to, const void *from, size_t size) {
- return Ident(memmove)(to, from, size);
- }
-};
-
-TEST(AddressSanitizer, MemMoveOOBTest) {
- MemTransferOOBTestTemplate<char, MemMoveWrapper>(100);
- MemTransferOOBTestTemplate<int, MemMoveWrapper>(1024);
-}
-
-template <int (*cmpfn)(const void *, const void *, size_t)>
-void CmpOOBTestCommon() {
- size_t size = Ident(100);
- char *s1 = MallocAndMemsetString(size);
- char *s2 = MallocAndMemsetString(size);
- // Normal cmpfn calls.
- Ident(cmpfn(s1, s2, size));
- Ident(cmpfn(s1 + size - 1, s2 + size - 1, 1));
- Ident(cmpfn(s1 - 1, s2 - 1, 0));
- // One of arguments points to not allocated memory.
- EXPECT_DEATH(Ident(cmpfn)(s1 - 1, s2, 1), LeftOOBReadMessage(1));
- EXPECT_DEATH(Ident(cmpfn)(s1, s2 - 1, 1), LeftOOBReadMessage(1));
- EXPECT_DEATH(Ident(cmpfn)(s1 + size, s2, 1), RightOOBReadMessage(0));
- EXPECT_DEATH(Ident(cmpfn)(s1, s2 + size, 1), RightOOBReadMessage(0));
- // Hit unallocated memory and die.
- EXPECT_DEATH(Ident(cmpfn)(s1 + 1, s2 + 1, size), RightOOBReadMessage(0));
- EXPECT_DEATH(Ident(cmpfn)(s1 + size - 1, s2, 2), RightOOBReadMessage(0));
- // Zero bytes are not terminators and don't prevent from OOB.
- s1[size - 1] = '\0';
- s2[size - 1] = '\0';
- EXPECT_DEATH(Ident(cmpfn)(s1, s2, size + 1), RightOOBReadMessage(0));
-
- // Even if the buffers differ in the first byte, we still assume that
- // cmpfn may access the whole buffer and thus reporting the overflow here:
- s1[0] = 1;
- s2[0] = 123;
- EXPECT_DEATH(Ident(cmpfn)(s1, s2, size + 1), RightOOBReadMessage(0));
-
- free(s1);
- free(s2);
-}
-
-TEST(AddressSanitizer, MemCmpOOBTest) { CmpOOBTestCommon<memcmp>(); }
-
-TEST(AddressSanitizer, BCmpOOBTest) {
-#if (defined(__linux__) && !defined(__ANDROID__) && defined(_GNU_SOURCE)) || \
- defined(__NetBSD__) || defined(__FreeBSD__) || defined(__OpenBSD__)
- CmpOOBTestCommon<bcmp>();
-#endif
-}
--- /dev/null
+//===-- asan_mem_test.cpp -------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a part of AddressSanitizer, an address sanity checker.
+//
+//===----------------------------------------------------------------------===//
+#include <string.h>
+#include "asan_test_utils.h"
+#if defined(_GNU_SOURCE)
+#include <strings.h> // for bcmp
+#endif
+#include <vector>
+
+template<typename T>
+void MemSetOOBTestTemplate(size_t length) {
+ if (length == 0) return;
+ size_t size = Ident(sizeof(T) * length);
+ T *array = Ident((T*)malloc(size));
+ int element = Ident(42);
+ int zero = Ident(0);
+ void *(*MEMSET)(void *s, int c, size_t n) = Ident(memset);
+ // memset interval inside array
+ MEMSET(array, element, size);
+ MEMSET(array, element, size - 1);
+ MEMSET(array + length - 1, element, sizeof(T));
+ MEMSET(array, element, 1);
+
+ // memset 0 bytes
+ MEMSET(array - 10, element, zero);
+ MEMSET(array - 1, element, zero);
+ MEMSET(array, element, zero);
+ MEMSET(array + length, 0, zero);
+ MEMSET(array + length + 1, 0, zero);
+
+ // try to memset bytes to the right of array
+ EXPECT_DEATH(MEMSET(array, 0, size + 1),
+ RightOOBWriteMessage(0));
+ EXPECT_DEATH(MEMSET((char*)(array + length) - 1, element, 6),
+ RightOOBWriteMessage(0));
+ EXPECT_DEATH(MEMSET(array + 1, element, size + sizeof(T)),
+ RightOOBWriteMessage(0));
+ // whole interval is to the right
+ EXPECT_DEATH(MEMSET(array + length + 1, 0, 10),
+ RightOOBWriteMessage(sizeof(T)));
+
+ // try to memset bytes to the left of array
+ EXPECT_DEATH(MEMSET((char*)array - 1, element, size),
+ LeftOOBWriteMessage(1));
+ EXPECT_DEATH(MEMSET((char*)array - 5, 0, 6),
+ LeftOOBWriteMessage(5));
+ if (length >= 100) {
+ // Large OOB, we find it only if the redzone is large enough.
+ EXPECT_DEATH(memset(array - 5, element, size + 5 * sizeof(T)),
+ LeftOOBWriteMessage(5 * sizeof(T)));
+ }
+ // whole interval is to the left
+ EXPECT_DEATH(MEMSET(array - 2, 0, sizeof(T)),
+ LeftOOBWriteMessage(2 * sizeof(T)));
+
+ // try to memset bytes both to the left & to the right
+ EXPECT_DEATH(MEMSET((char*)array - 2, element, size + 4),
+ LeftOOBWriteMessage(2));
+
+ free(array);
+}
+
+TEST(AddressSanitizer, MemSetOOBTest) {
+ MemSetOOBTestTemplate<char>(100);
+ MemSetOOBTestTemplate<int>(5);
+ MemSetOOBTestTemplate<double>(256);
+ // We can test arrays of structres/classes here, but what for?
+}
+
+// Try to allocate two arrays of 'size' bytes that are near each other.
+// Strictly speaking we are not guaranteed to find such two pointers,
+// but given the structure of asan's allocator we will.
+static bool AllocateTwoAdjacentArrays(char **x1, char **x2, size_t size) {
+ std::vector<uintptr_t> v;
+ bool res = false;
+ for (size_t i = 0; i < 1000U && !res; i++) {
+ v.push_back(reinterpret_cast<uintptr_t>(new char[size]));
+ if (i == 0) continue;
+ sort(v.begin(), v.end());
+ for (size_t j = 1; j < v.size(); j++) {
+ assert(v[j] > v[j-1]);
+ if ((size_t)(v[j] - v[j-1]) < size * 2) {
+ *x2 = reinterpret_cast<char*>(v[j]);
+ *x1 = reinterpret_cast<char*>(v[j-1]);
+ res = true;
+ break;
+ }
+ }
+ }
+
+ for (size_t i = 0; i < v.size(); i++) {
+ char *p = reinterpret_cast<char *>(v[i]);
+ if (res && p == *x1) continue;
+ if (res && p == *x2) continue;
+ delete [] p;
+ }
+ return res;
+}
+
+TEST(AddressSanitizer, LargeOOBInMemset) {
+ for (size_t size = 200; size < 100000; size += size / 2) {
+ char *x1, *x2;
+ if (!Ident(AllocateTwoAdjacentArrays)(&x1, &x2, size))
+ continue;
+ // fprintf(stderr, " large oob memset: %p %p %zd\n", x1, x2, size);
+ // Do a memset on x1 with huge out-of-bound access that will end up in x2.
+ EXPECT_DEATH(Ident(memset)(x1, 0, size * 2),
+ "is located 0 bytes to the right");
+ delete [] x1;
+ delete [] x2;
+ return;
+ }
+ assert(0 && "Did not find two adjacent malloc-ed pointers");
+}
+
+// Same test for memcpy and memmove functions
+template <typename T, class M>
+void MemTransferOOBTestTemplate(size_t length) {
+ if (length == 0) return;
+ size_t size = Ident(sizeof(T) * length);
+ T *src = Ident((T*)malloc(size));
+ T *dest = Ident((T*)malloc(size));
+ int zero = Ident(0);
+
+ // valid transfer of bytes between arrays
+ M::transfer(dest, src, size);
+ M::transfer(dest + 1, src, size - sizeof(T));
+ M::transfer(dest, src + length - 1, sizeof(T));
+ M::transfer(dest, src, 1);
+
+ // transfer zero bytes
+ M::transfer(dest - 1, src, 0);
+ M::transfer(dest + length, src, zero);
+ M::transfer(dest, src - 1, zero);
+ M::transfer(dest, src, zero);
+
+ // try to change mem to the right of dest
+ EXPECT_DEATH(M::transfer(dest + 1, src, size),
+ RightOOBWriteMessage(0));
+ EXPECT_DEATH(M::transfer((char*)(dest + length) - 1, src, 5),
+ RightOOBWriteMessage(0));
+
+ // try to change mem to the left of dest
+ EXPECT_DEATH(M::transfer(dest - 2, src, size),
+ LeftOOBWriteMessage(2 * sizeof(T)));
+ EXPECT_DEATH(M::transfer((char*)dest - 3, src, 4),
+ LeftOOBWriteMessage(3));
+
+ // try to access mem to the right of src
+ EXPECT_DEATH(M::transfer(dest, src + 2, size),
+ RightOOBReadMessage(0));
+ EXPECT_DEATH(M::transfer(dest, (char*)(src + length) - 3, 6),
+ RightOOBReadMessage(0));
+
+ // try to access mem to the left of src
+ EXPECT_DEATH(M::transfer(dest, src - 1, size),
+ LeftOOBReadMessage(sizeof(T)));
+ EXPECT_DEATH(M::transfer(dest, (char*)src - 6, 7),
+ LeftOOBReadMessage(6));
+
+ // Generally we don't need to test cases where both accessing src and writing
+ // to dest address to poisoned memory.
+
+ T *big_src = Ident((T*)malloc(size * 2));
+ T *big_dest = Ident((T*)malloc(size * 2));
+ // try to change mem to both sides of dest
+ EXPECT_DEATH(M::transfer(dest - 1, big_src, size * 2),
+ LeftOOBWriteMessage(sizeof(T)));
+ // try to access mem to both sides of src
+ EXPECT_DEATH(M::transfer(big_dest, src - 2, size * 2),
+ LeftOOBReadMessage(2 * sizeof(T)));
+
+ free(src);
+ free(dest);
+ free(big_src);
+ free(big_dest);
+}
+
+class MemCpyWrapper {
+ public:
+ static void* transfer(void *to, const void *from, size_t size) {
+ return Ident(memcpy)(to, from, size);
+ }
+};
+
+TEST(AddressSanitizer, MemCpyOOBTest) {
+ MemTransferOOBTestTemplate<char, MemCpyWrapper>(100);
+ MemTransferOOBTestTemplate<int, MemCpyWrapper>(1024);
+}
+
+class MemMoveWrapper {
+ public:
+ static void* transfer(void *to, const void *from, size_t size) {
+ return Ident(memmove)(to, from, size);
+ }
+};
+
+TEST(AddressSanitizer, MemMoveOOBTest) {
+ MemTransferOOBTestTemplate<char, MemMoveWrapper>(100);
+ MemTransferOOBTestTemplate<int, MemMoveWrapper>(1024);
+}
+
+template <int (*cmpfn)(const void *, const void *, size_t)>
+void CmpOOBTestCommon() {
+ size_t size = Ident(100);
+ char *s1 = MallocAndMemsetString(size);
+ char *s2 = MallocAndMemsetString(size);
+ // Normal cmpfn calls.
+ Ident(cmpfn(s1, s2, size));
+ Ident(cmpfn(s1 + size - 1, s2 + size - 1, 1));
+ Ident(cmpfn(s1 - 1, s2 - 1, 0));
+ // One of arguments points to not allocated memory.
+ EXPECT_DEATH(Ident(cmpfn)(s1 - 1, s2, 1), LeftOOBReadMessage(1));
+ EXPECT_DEATH(Ident(cmpfn)(s1, s2 - 1, 1), LeftOOBReadMessage(1));
+ EXPECT_DEATH(Ident(cmpfn)(s1 + size, s2, 1), RightOOBReadMessage(0));
+ EXPECT_DEATH(Ident(cmpfn)(s1, s2 + size, 1), RightOOBReadMessage(0));
+ // Hit unallocated memory and die.
+ EXPECT_DEATH(Ident(cmpfn)(s1 + 1, s2 + 1, size), RightOOBReadMessage(0));
+ EXPECT_DEATH(Ident(cmpfn)(s1 + size - 1, s2, 2), RightOOBReadMessage(0));
+ // Zero bytes are not terminators and don't prevent from OOB.
+ s1[size - 1] = '\0';
+ s2[size - 1] = '\0';
+ EXPECT_DEATH(Ident(cmpfn)(s1, s2, size + 1), RightOOBReadMessage(0));
+
+ // Even if the buffers differ in the first byte, we still assume that
+ // cmpfn may access the whole buffer and thus reporting the overflow here:
+ s1[0] = 1;
+ s2[0] = 123;
+ EXPECT_DEATH(Ident(cmpfn)(s1, s2, size + 1), RightOOBReadMessage(0));
+
+ free(s1);
+ free(s2);
+}
+
+TEST(AddressSanitizer, MemCmpOOBTest) { CmpOOBTestCommon<memcmp>(); }
+
+TEST(AddressSanitizer, BCmpOOBTest) {
+#if (defined(__linux__) && !defined(__ANDROID__) && defined(_GNU_SOURCE)) || \
+ defined(__NetBSD__) || defined(__FreeBSD__) || defined(__OpenBSD__)
+ CmpOOBTestCommon<bcmp>();
+#endif
+}
+++ /dev/null
-//===-- asan_noinst_test.cc -----------------------------------------------===//
-//
-// 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
-//
-//===----------------------------------------------------------------------===//
-//
-// This file is a part of AddressSanitizer, an address sanity checker.
-//
-// This test file should be compiled w/o asan instrumentation.
-//===----------------------------------------------------------------------===//
-
-#include "asan_allocator.h"
-#include "asan_internal.h"
-#include "asan_mapping.h"
-#include "asan_test_utils.h"
-#include <sanitizer/allocator_interface.h>
-
-#include <assert.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h> // for memset()
-#include <algorithm>
-#include <vector>
-#include <limits>
-
-using namespace __sanitizer;
-
-// ATTENTION!
-// Please don't call intercepted functions (including malloc() and friends)
-// in this test. The static runtime library is linked explicitly (without
-// -fsanitize=address), thus the interceptors do not work correctly on OS X.
-
-// Make sure __asan_init is called before any test case is run.
-struct AsanInitCaller {
- AsanInitCaller() {
- __asan_init();
- }
-};
-static AsanInitCaller asan_init_caller;
-
-TEST(AddressSanitizer, InternalSimpleDeathTest) {
- EXPECT_DEATH(exit(1), "");
-}
-
-static void MallocStress(size_t n) {
- u32 seed = my_rand();
- BufferedStackTrace stack1;
- stack1.trace_buffer[0] = 0xa123;
- stack1.trace_buffer[1] = 0xa456;
- stack1.size = 2;
-
- BufferedStackTrace stack2;
- stack2.trace_buffer[0] = 0xb123;
- stack2.trace_buffer[1] = 0xb456;
- stack2.size = 2;
-
- BufferedStackTrace stack3;
- stack3.trace_buffer[0] = 0xc123;
- stack3.trace_buffer[1] = 0xc456;
- stack3.size = 2;
-
- std::vector<void *> vec;
- for (size_t i = 0; i < n; i++) {
- if ((i % 3) == 0) {
- if (vec.empty()) continue;
- size_t idx = my_rand_r(&seed) % vec.size();
- void *ptr = vec[idx];
- vec[idx] = vec.back();
- vec.pop_back();
- __asan::asan_free(ptr, &stack1, __asan::FROM_MALLOC);
- } else {
- size_t size = my_rand_r(&seed) % 1000 + 1;
- switch ((my_rand_r(&seed) % 128)) {
- case 0: size += 1024; break;
- case 1: size += 2048; break;
- case 2: size += 4096; break;
- }
- size_t alignment = 1 << (my_rand_r(&seed) % 10 + 1);
- char *ptr = (char*)__asan::asan_memalign(alignment, size,
- &stack2, __asan::FROM_MALLOC);
- EXPECT_EQ(size, __asan::asan_malloc_usable_size(ptr, 0, 0));
- vec.push_back(ptr);
- ptr[0] = 0;
- ptr[size-1] = 0;
- ptr[size/2] = 0;
- }
- }
- for (size_t i = 0; i < vec.size(); i++)
- __asan::asan_free(vec[i], &stack3, __asan::FROM_MALLOC);
-}
-
-
-TEST(AddressSanitizer, NoInstMallocTest) {
- MallocStress(ASAN_LOW_MEMORY ? 300000 : 1000000);
-}
-
-TEST(AddressSanitizer, ThreadedMallocStressTest) {
- const int kNumThreads = 4;
- const int kNumIterations = (ASAN_LOW_MEMORY) ? 10000 : 100000;
- pthread_t t[kNumThreads];
- for (int i = 0; i < kNumThreads; i++) {
- PTHREAD_CREATE(&t[i], 0, (void* (*)(void *x))MallocStress,
- (void*)kNumIterations);
- }
- for (int i = 0; i < kNumThreads; i++) {
- PTHREAD_JOIN(t[i], 0);
- }
-}
-
-static void PrintShadow(const char *tag, uptr ptr, size_t size) {
- fprintf(stderr, "%s shadow: %lx size % 3ld: ", tag, (long)ptr, (long)size);
- uptr prev_shadow = 0;
- for (sptr i = -32; i < (sptr)size + 32; i++) {
- uptr shadow = __asan::MemToShadow(ptr + i);
- if (i == 0 || i == (sptr)size)
- fprintf(stderr, ".");
- if (shadow != prev_shadow) {
- prev_shadow = shadow;
- fprintf(stderr, "%02x", (int)*(u8*)shadow);
- }
- }
- fprintf(stderr, "\n");
-}
-
-TEST(AddressSanitizer, DISABLED_InternalPrintShadow) {
- for (size_t size = 1; size <= 513; size++) {
- char *ptr = new char[size];
- PrintShadow("m", (uptr)ptr, size);
- delete [] ptr;
- PrintShadow("f", (uptr)ptr, size);
- }
-}
-
-TEST(AddressSanitizer, QuarantineTest) {
- BufferedStackTrace stack;
- stack.trace_buffer[0] = 0x890;
- stack.size = 1;
-
- const int size = 1024;
- void *p = __asan::asan_malloc(size, &stack);
- __asan::asan_free(p, &stack, __asan::FROM_MALLOC);
- size_t i;
- size_t max_i = 1 << 30;
- for (i = 0; i < max_i; i++) {
- void *p1 = __asan::asan_malloc(size, &stack);
- __asan::asan_free(p1, &stack, __asan::FROM_MALLOC);
- if (p1 == p) break;
- }
- EXPECT_GE(i, 10000U);
- EXPECT_LT(i, max_i);
-}
-
-#if !defined(__NetBSD__)
-void *ThreadedQuarantineTestWorker(void *unused) {
- (void)unused;
- u32 seed = my_rand();
- BufferedStackTrace stack;
- stack.trace_buffer[0] = 0x890;
- stack.size = 1;
-
- for (size_t i = 0; i < 1000; i++) {
- void *p = __asan::asan_malloc(1 + (my_rand_r(&seed) % 4000), &stack);
- __asan::asan_free(p, &stack, __asan::FROM_MALLOC);
- }
- return NULL;
-}
-
-// Check that the thread local allocators are flushed when threads are
-// destroyed.
-TEST(AddressSanitizer, ThreadedQuarantineTest) {
- // Run the routine once to warm up ASAN internal structures to get more
- // predictable incremental memory changes.
- pthread_t t;
- PTHREAD_CREATE(&t, NULL, ThreadedQuarantineTestWorker, 0);
- PTHREAD_JOIN(t, 0);
-
- const int n_threads = 3000;
- size_t mmaped1 = __sanitizer_get_heap_size();
- for (int i = 0; i < n_threads; i++) {
- pthread_t t;
- PTHREAD_CREATE(&t, NULL, ThreadedQuarantineTestWorker, 0);
- PTHREAD_JOIN(t, 0);
- size_t mmaped2 = __sanitizer_get_heap_size();
- // Figure out why this much memory is required.
- EXPECT_LT(mmaped2 - mmaped1, 320U * (1 << 20));
- }
-}
-#endif
-
-void *ThreadedOneSizeMallocStress(void *unused) {
- (void)unused;
- BufferedStackTrace stack;
- stack.trace_buffer[0] = 0x890;
- stack.size = 1;
- const size_t kNumMallocs = 1000;
- for (int iter = 0; iter < 1000; iter++) {
- void *p[kNumMallocs];
- for (size_t i = 0; i < kNumMallocs; i++) {
- p[i] = __asan::asan_malloc(32, &stack);
- }
- for (size_t i = 0; i < kNumMallocs; i++) {
- __asan::asan_free(p[i], &stack, __asan::FROM_MALLOC);
- }
- }
- return NULL;
-}
-
-TEST(AddressSanitizer, ThreadedOneSizeMallocStressTest) {
- const int kNumThreads = 4;
- pthread_t t[kNumThreads];
- for (int i = 0; i < kNumThreads; i++) {
- PTHREAD_CREATE(&t[i], 0, ThreadedOneSizeMallocStress, 0);
- }
- for (int i = 0; i < kNumThreads; i++) {
- PTHREAD_JOIN(t[i], 0);
- }
-}
-
-TEST(AddressSanitizer, ShadowRegionIsPoisonedTest) {
- using __asan::kHighMemEnd;
- // Check that __asan_region_is_poisoned works for shadow regions.
- uptr ptr = kLowShadowBeg + 200;
- EXPECT_EQ(ptr, __asan_region_is_poisoned(ptr, 100));
- ptr = kShadowGapBeg + 200;
- EXPECT_EQ(ptr, __asan_region_is_poisoned(ptr, 100));
- ptr = kHighShadowBeg + 200;
- EXPECT_EQ(ptr, __asan_region_is_poisoned(ptr, 100));
-}
-
-// Test __asan_load1 & friends.
-TEST(AddressSanitizer, LoadStoreCallbacks) {
- typedef void (*CB)(uptr p);
- CB cb[2][5] = {
- {
- __asan_load1, __asan_load2, __asan_load4, __asan_load8, __asan_load16,
- }, {
- __asan_store1, __asan_store2, __asan_store4, __asan_store8,
- __asan_store16,
- }
- };
-
- uptr buggy_ptr;
-
- __asan_test_only_reported_buggy_pointer = &buggy_ptr;
- BufferedStackTrace stack;
- stack.trace_buffer[0] = 0x890;
- stack.size = 1;
-
- for (uptr len = 16; len <= 32; len++) {
- char *ptr = (char*) __asan::asan_malloc(len, &stack);
- uptr p = reinterpret_cast<uptr>(ptr);
- for (uptr is_write = 0; is_write <= 1; is_write++) {
- for (uptr size_log = 0; size_log <= 4; size_log++) {
- uptr size = 1 << size_log;
- CB call = cb[is_write][size_log];
- // Iterate only size-aligned offsets.
- for (uptr offset = 0; offset <= len; offset += size) {
- buggy_ptr = 0;
- call(p + offset);
- if (offset + size <= len)
- EXPECT_EQ(buggy_ptr, 0U);
- else
- EXPECT_EQ(buggy_ptr, p + offset);
- }
- }
- }
- __asan::asan_free(ptr, &stack, __asan::FROM_MALLOC);
- }
- __asan_test_only_reported_buggy_pointer = 0;
-}
--- /dev/null
+//===-- asan_noinst_test.cpp ----------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a part of AddressSanitizer, an address sanity checker.
+//
+// This test file should be compiled w/o asan instrumentation.
+//===----------------------------------------------------------------------===//
+
+#include "asan_allocator.h"
+#include "asan_internal.h"
+#include "asan_mapping.h"
+#include "asan_test_utils.h"
+#include <sanitizer/allocator_interface.h>
+
+#include <assert.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h> // for memset()
+#include <algorithm>
+#include <vector>
+#include <limits>
+
+using namespace __sanitizer;
+
+// ATTENTION!
+// Please don't call intercepted functions (including malloc() and friends)
+// in this test. The static runtime library is linked explicitly (without
+// -fsanitize=address), thus the interceptors do not work correctly on OS X.
+
+// Make sure __asan_init is called before any test case is run.
+struct AsanInitCaller {
+ AsanInitCaller() {
+ __asan_init();
+ }
+};
+static AsanInitCaller asan_init_caller;
+
+TEST(AddressSanitizer, InternalSimpleDeathTest) {
+ EXPECT_DEATH(exit(1), "");
+}
+
+static void MallocStress(size_t n) {
+ u32 seed = my_rand();
+ BufferedStackTrace stack1;
+ stack1.trace_buffer[0] = 0xa123;
+ stack1.trace_buffer[1] = 0xa456;
+ stack1.size = 2;
+
+ BufferedStackTrace stack2;
+ stack2.trace_buffer[0] = 0xb123;
+ stack2.trace_buffer[1] = 0xb456;
+ stack2.size = 2;
+
+ BufferedStackTrace stack3;
+ stack3.trace_buffer[0] = 0xc123;
+ stack3.trace_buffer[1] = 0xc456;
+ stack3.size = 2;
+
+ std::vector<void *> vec;
+ for (size_t i = 0; i < n; i++) {
+ if ((i % 3) == 0) {
+ if (vec.empty()) continue;
+ size_t idx = my_rand_r(&seed) % vec.size();
+ void *ptr = vec[idx];
+ vec[idx] = vec.back();
+ vec.pop_back();
+ __asan::asan_free(ptr, &stack1, __asan::FROM_MALLOC);
+ } else {
+ size_t size = my_rand_r(&seed) % 1000 + 1;
+ switch ((my_rand_r(&seed) % 128)) {
+ case 0: size += 1024; break;
+ case 1: size += 2048; break;
+ case 2: size += 4096; break;
+ }
+ size_t alignment = 1 << (my_rand_r(&seed) % 10 + 1);
+ char *ptr = (char*)__asan::asan_memalign(alignment, size,
+ &stack2, __asan::FROM_MALLOC);
+ EXPECT_EQ(size, __asan::asan_malloc_usable_size(ptr, 0, 0));
+ vec.push_back(ptr);
+ ptr[0] = 0;
+ ptr[size-1] = 0;
+ ptr[size/2] = 0;
+ }
+ }
+ for (size_t i = 0; i < vec.size(); i++)
+ __asan::asan_free(vec[i], &stack3, __asan::FROM_MALLOC);
+}
+
+
+TEST(AddressSanitizer, NoInstMallocTest) {
+ MallocStress(ASAN_LOW_MEMORY ? 300000 : 1000000);
+}
+
+TEST(AddressSanitizer, ThreadedMallocStressTest) {
+ const int kNumThreads = 4;
+ const int kNumIterations = (ASAN_LOW_MEMORY) ? 10000 : 100000;
+ pthread_t t[kNumThreads];
+ for (int i = 0; i < kNumThreads; i++) {
+ PTHREAD_CREATE(&t[i], 0, (void* (*)(void *x))MallocStress,
+ (void*)kNumIterations);
+ }
+ for (int i = 0; i < kNumThreads; i++) {
+ PTHREAD_JOIN(t[i], 0);
+ }
+}
+
+static void PrintShadow(const char *tag, uptr ptr, size_t size) {
+ fprintf(stderr, "%s shadow: %lx size % 3ld: ", tag, (long)ptr, (long)size);
+ uptr prev_shadow = 0;
+ for (sptr i = -32; i < (sptr)size + 32; i++) {
+ uptr shadow = __asan::MemToShadow(ptr + i);
+ if (i == 0 || i == (sptr)size)
+ fprintf(stderr, ".");
+ if (shadow != prev_shadow) {
+ prev_shadow = shadow;
+ fprintf(stderr, "%02x", (int)*(u8*)shadow);
+ }
+ }
+ fprintf(stderr, "\n");
+}
+
+TEST(AddressSanitizer, DISABLED_InternalPrintShadow) {
+ for (size_t size = 1; size <= 513; size++) {
+ char *ptr = new char[size];
+ PrintShadow("m", (uptr)ptr, size);
+ delete [] ptr;
+ PrintShadow("f", (uptr)ptr, size);
+ }
+}
+
+TEST(AddressSanitizer, QuarantineTest) {
+ BufferedStackTrace stack;
+ stack.trace_buffer[0] = 0x890;
+ stack.size = 1;
+
+ const int size = 1024;
+ void *p = __asan::asan_malloc(size, &stack);
+ __asan::asan_free(p, &stack, __asan::FROM_MALLOC);
+ size_t i;
+ size_t max_i = 1 << 30;
+ for (i = 0; i < max_i; i++) {
+ void *p1 = __asan::asan_malloc(size, &stack);
+ __asan::asan_free(p1, &stack, __asan::FROM_MALLOC);
+ if (p1 == p) break;
+ }
+ EXPECT_GE(i, 10000U);
+ EXPECT_LT(i, max_i);
+}
+
+#if !defined(__NetBSD__)
+void *ThreadedQuarantineTestWorker(void *unused) {
+ (void)unused;
+ u32 seed = my_rand();
+ BufferedStackTrace stack;
+ stack.trace_buffer[0] = 0x890;
+ stack.size = 1;
+
+ for (size_t i = 0; i < 1000; i++) {
+ void *p = __asan::asan_malloc(1 + (my_rand_r(&seed) % 4000), &stack);
+ __asan::asan_free(p, &stack, __asan::FROM_MALLOC);
+ }
+ return NULL;
+}
+
+// Check that the thread local allocators are flushed when threads are
+// destroyed.
+TEST(AddressSanitizer, ThreadedQuarantineTest) {
+ // Run the routine once to warm up ASAN internal structures to get more
+ // predictable incremental memory changes.
+ pthread_t t;
+ PTHREAD_CREATE(&t, NULL, ThreadedQuarantineTestWorker, 0);
+ PTHREAD_JOIN(t, 0);
+
+ const int n_threads = 3000;
+ size_t mmaped1 = __sanitizer_get_heap_size();
+ for (int i = 0; i < n_threads; i++) {
+ pthread_t t;
+ PTHREAD_CREATE(&t, NULL, ThreadedQuarantineTestWorker, 0);
+ PTHREAD_JOIN(t, 0);
+ size_t mmaped2 = __sanitizer_get_heap_size();
+ // Figure out why this much memory is required.
+ EXPECT_LT(mmaped2 - mmaped1, 320U * (1 << 20));
+ }
+}
+#endif
+
+void *ThreadedOneSizeMallocStress(void *unused) {
+ (void)unused;
+ BufferedStackTrace stack;
+ stack.trace_buffer[0] = 0x890;
+ stack.size = 1;
+ const size_t kNumMallocs = 1000;
+ for (int iter = 0; iter < 1000; iter++) {
+ void *p[kNumMallocs];
+ for (size_t i = 0; i < kNumMallocs; i++) {
+ p[i] = __asan::asan_malloc(32, &stack);
+ }
+ for (size_t i = 0; i < kNumMallocs; i++) {
+ __asan::asan_free(p[i], &stack, __asan::FROM_MALLOC);
+ }
+ }
+ return NULL;
+}
+
+TEST(AddressSanitizer, ThreadedOneSizeMallocStressTest) {
+ const int kNumThreads = 4;
+ pthread_t t[kNumThreads];
+ for (int i = 0; i < kNumThreads; i++) {
+ PTHREAD_CREATE(&t[i], 0, ThreadedOneSizeMallocStress, 0);
+ }
+ for (int i = 0; i < kNumThreads; i++) {
+ PTHREAD_JOIN(t[i], 0);
+ }
+}
+
+TEST(AddressSanitizer, ShadowRegionIsPoisonedTest) {
+ using __asan::kHighMemEnd;
+ // Check that __asan_region_is_poisoned works for shadow regions.
+ uptr ptr = kLowShadowBeg + 200;
+ EXPECT_EQ(ptr, __asan_region_is_poisoned(ptr, 100));
+ ptr = kShadowGapBeg + 200;
+ EXPECT_EQ(ptr, __asan_region_is_poisoned(ptr, 100));
+ ptr = kHighShadowBeg + 200;
+ EXPECT_EQ(ptr, __asan_region_is_poisoned(ptr, 100));
+}
+
+// Test __asan_load1 & friends.
+TEST(AddressSanitizer, LoadStoreCallbacks) {
+ typedef void (*CB)(uptr p);
+ CB cb[2][5] = {
+ {
+ __asan_load1, __asan_load2, __asan_load4, __asan_load8, __asan_load16,
+ }, {
+ __asan_store1, __asan_store2, __asan_store4, __asan_store8,
+ __asan_store16,
+ }
+ };
+
+ uptr buggy_ptr;
+
+ __asan_test_only_reported_buggy_pointer = &buggy_ptr;
+ BufferedStackTrace stack;
+ stack.trace_buffer[0] = 0x890;
+ stack.size = 1;
+
+ for (uptr len = 16; len <= 32; len++) {
+ char *ptr = (char*) __asan::asan_malloc(len, &stack);
+ uptr p = reinterpret_cast<uptr>(ptr);
+ for (uptr is_write = 0; is_write <= 1; is_write++) {
+ for (uptr size_log = 0; size_log <= 4; size_log++) {
+ uptr size = 1 << size_log;
+ CB call = cb[is_write][size_log];
+ // Iterate only size-aligned offsets.
+ for (uptr offset = 0; offset <= len; offset += size) {
+ buggy_ptr = 0;
+ call(p + offset);
+ if (offset + size <= len)
+ EXPECT_EQ(buggy_ptr, 0U);
+ else
+ EXPECT_EQ(buggy_ptr, p + offset);
+ }
+ }
+ }
+ __asan::asan_free(ptr, &stack, __asan::FROM_MALLOC);
+ }
+ __asan_test_only_reported_buggy_pointer = 0;
+}
+++ /dev/null
-//===-- asan_oob_test.cc --------------------------------------------------===//
-//
-// 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
-//
-//===----------------------------------------------------------------------===//
-//
-// This file is a part of AddressSanitizer, an address sanity checker.
-//
-//===----------------------------------------------------------------------===//
-#include "asan_test_utils.h"
-
-NOINLINE void asan_write_sized_aligned(uint8_t *p, size_t size) {
- EXPECT_EQ(0U, ((uintptr_t)p % size));
- if (size == 1) asan_write((uint8_t*)p);
- else if (size == 2) asan_write((uint16_t*)p);
- else if (size == 4) asan_write((uint32_t*)p);
- else if (size == 8) asan_write((uint64_t*)p);
-}
-
-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");
-}
-
-// TODO(glider): the following tests are EXTREMELY slow on Darwin:
-// AddressSanitizer.OOB_char (125503 ms)
-// AddressSanitizer.OOB_int (126890 ms)
-// AddressSanitizer.OOBRightTest (315605 ms)
-// AddressSanitizer.SimpleStackTest (366559 ms)
-
-TEST(AddressSanitizer, OOB_char) {
- OOBTest<U1>();
-}
-
-TEST(AddressSanitizer, OOB_int) {
- OOBTest<U4>();
-}
-
-TEST(AddressSanitizer, OOBRightTest) {
- size_t max_access_size = SANITIZER_WORDSIZE == 64 ? 8 : 4;
- for (size_t access_size = 1; access_size <= max_access_size;
- access_size *= 2) {
- for (size_t alloc_size = 1; alloc_size <= 8; alloc_size++) {
- for (size_t offset = 0; offset <= 8; offset += access_size) {
- void *p = malloc(alloc_size);
- // allocated: [p, p + alloc_size)
- // accessed: [p + offset, p + offset + access_size)
- uint8_t *addr = (uint8_t*)p + offset;
- if (offset + access_size <= alloc_size) {
- asan_write_sized_aligned(addr, access_size);
- } else {
- int outside_bytes = offset > alloc_size ? (offset - alloc_size) : 0;
- const char *str =
- "is located.%d *byte.*to the right";
- char expected_str[100];
- sprintf(expected_str, str, outside_bytes);
- EXPECT_DEATH(asan_write_sized_aligned(addr, access_size),
- expected_str);
- }
- free(p);
- }
- }
- }
-}
-
-TEST(AddressSanitizer, LargeOOBRightTest) {
- size_t large_power_of_two = 1 << 19;
- for (size_t i = 16; i <= 256; i *= 2) {
- size_t size = large_power_of_two - i;
- char *p = Ident(new char[size]);
- EXPECT_DEATH(p[size] = 0, "is located 0 bytes to the right");
- delete [] p;
- }
-}
-
-TEST(AddressSanitizer, DISABLED_DemoOOBLeftLow) {
- oob_test<U1>(10, -1);
-}
-
-TEST(AddressSanitizer, DISABLED_DemoOOBLeftHigh) {
- oob_test<U1>(kLargeMalloc, -1);
-}
-
-TEST(AddressSanitizer, DISABLED_DemoOOBRightLow) {
- oob_test<U1>(10, 10);
-}
-
-TEST(AddressSanitizer, DISABLED_DemoOOBRightHigh) {
- oob_test<U1>(kLargeMalloc, kLargeMalloc);
-}
--- /dev/null
+//===-- asan_oob_test.cpp -------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a part of AddressSanitizer, an address sanity checker.
+//
+//===----------------------------------------------------------------------===//
+#include "asan_test_utils.h"
+
+NOINLINE void asan_write_sized_aligned(uint8_t *p, size_t size) {
+ EXPECT_EQ(0U, ((uintptr_t)p % size));
+ if (size == 1) asan_write((uint8_t*)p);
+ else if (size == 2) asan_write((uint16_t*)p);
+ else if (size == 4) asan_write((uint32_t*)p);
+ else if (size == 8) asan_write((uint64_t*)p);
+}
+
+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");
+}
+
+// TODO(glider): the following tests are EXTREMELY slow on Darwin:
+// AddressSanitizer.OOB_char (125503 ms)
+// AddressSanitizer.OOB_int (126890 ms)
+// AddressSanitizer.OOBRightTest (315605 ms)
+// AddressSanitizer.SimpleStackTest (366559 ms)
+
+TEST(AddressSanitizer, OOB_char) {
+ OOBTest<U1>();
+}
+
+TEST(AddressSanitizer, OOB_int) {
+ OOBTest<U4>();
+}
+
+TEST(AddressSanitizer, OOBRightTest) {
+ size_t max_access_size = SANITIZER_WORDSIZE == 64 ? 8 : 4;
+ for (size_t access_size = 1; access_size <= max_access_size;
+ access_size *= 2) {
+ for (size_t alloc_size = 1; alloc_size <= 8; alloc_size++) {
+ for (size_t offset = 0; offset <= 8; offset += access_size) {
+ void *p = malloc(alloc_size);
+ // allocated: [p, p + alloc_size)
+ // accessed: [p + offset, p + offset + access_size)
+ uint8_t *addr = (uint8_t*)p + offset;
+ if (offset + access_size <= alloc_size) {
+ asan_write_sized_aligned(addr, access_size);
+ } else {
+ int outside_bytes = offset > alloc_size ? (offset - alloc_size) : 0;
+ const char *str =
+ "is located.%d *byte.*to the right";
+ char expected_str[100];
+ sprintf(expected_str, str, outside_bytes);
+ EXPECT_DEATH(asan_write_sized_aligned(addr, access_size),
+ expected_str);
+ }
+ free(p);
+ }
+ }
+ }
+}
+
+TEST(AddressSanitizer, LargeOOBRightTest) {
+ size_t large_power_of_two = 1 << 19;
+ for (size_t i = 16; i <= 256; i *= 2) {
+ size_t size = large_power_of_two - i;
+ char *p = Ident(new char[size]);
+ EXPECT_DEATH(p[size] = 0, "is located 0 bytes to the right");
+ delete [] p;
+ }
+}
+
+TEST(AddressSanitizer, DISABLED_DemoOOBLeftLow) {
+ oob_test<U1>(10, -1);
+}
+
+TEST(AddressSanitizer, DISABLED_DemoOOBLeftHigh) {
+ oob_test<U1>(kLargeMalloc, -1);
+}
+
+TEST(AddressSanitizer, DISABLED_DemoOOBRightLow) {
+ oob_test<U1>(10, 10);
+}
+
+TEST(AddressSanitizer, DISABLED_DemoOOBRightHigh) {
+ oob_test<U1>(kLargeMalloc, kLargeMalloc);
+}
+++ /dev/null
-#include <pthread.h>
-#include <stdlib.h>
-#include <stdio.h>
-
-const int N = 1000;
-void *x[N];
-
-void *Thread1(void *unused) {
- for (int i = 0; i < N; i++) {
- fprintf(stderr, "%s %d\n", __func__, i);
- free(x[i]);
- }
- return NULL;
-}
-
-void *Thread2(void *unused) {
- for (int i = 0; i < N; i++) {
- fprintf(stderr, "%s %d\n", __func__, i);
- free(x[i]);
- }
- return NULL;
-}
-
-int main() {
- for (int i = 0; i < N; i++)
- x[i] = malloc(128);
- pthread_t t[2];
- pthread_create(&t[0], 0, Thread1, 0);
- pthread_create(&t[1], 0, Thread2, 0);
- pthread_join(t[0], 0);
- pthread_join(t[1], 0);
-}
--- /dev/null
+#include <pthread.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+const int N = 1000;
+void *x[N];
+
+void *Thread1(void *unused) {
+ for (int i = 0; i < N; i++) {
+ fprintf(stderr, "%s %d\n", __func__, i);
+ free(x[i]);
+ }
+ return NULL;
+}
+
+void *Thread2(void *unused) {
+ for (int i = 0; i < N; i++) {
+ fprintf(stderr, "%s %d\n", __func__, i);
+ free(x[i]);
+ }
+ return NULL;
+}
+
+int main() {
+ for (int i = 0; i < N; i++)
+ x[i] = malloc(128);
+ pthread_t t[2];
+ pthread_create(&t[0], 0, Thread1, 0);
+ pthread_create(&t[1], 0, Thread2, 0);
+ pthread_join(t[0], 0);
+ pthread_join(t[1], 0);
+}
+++ /dev/null
-//=-- asan_str_test.cc ----------------------------------------------------===//
-//
-// 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
-//
-//===----------------------------------------------------------------------===//
-//
-// This file is a part of AddressSanitizer, an address sanity checker.
-//
-//===----------------------------------------------------------------------===//
-#include "asan_test_utils.h"
-
-#if defined(__APPLE__)
-#include <AvailabilityMacros.h> // For MAC_OS_X_VERSION_*
-#endif
-
-// Used for string functions tests
-static char global_string[] = "global";
-static size_t global_string_length = 6;
-
-const char kStackReadUnderflow[] =
-#if !GTEST_USES_SIMPLE_RE
- ASAN_PCRE_DOTALL
- "READ.*"
-#endif
- "underflows this variable";
-const char kStackReadOverflow[] =
-#if !GTEST_USES_SIMPLE_RE
- ASAN_PCRE_DOTALL
- "READ.*"
-#endif
- "overflows this variable";
-
-namespace {
-enum class OOBKind {
- Heap,
- Stack,
- Global,
-};
-
-string LeftOOBReadMessage(OOBKind oob_kind, int oob_distance) {
- return oob_kind == OOBKind::Stack ? kStackReadUnderflow
- : ::LeftOOBReadMessage(oob_distance);
-}
-
-string RightOOBReadMessage(OOBKind oob_kind, int oob_distance) {
- return oob_kind == OOBKind::Stack ? kStackReadOverflow
- : ::RightOOBReadMessage(oob_distance);
-}
-} // namespace
-
-// Input to a test is a zero-terminated string str with given length
-// Accesses to the bytes to the left and to the right of str
-// are presumed to produce OOB errors
-void StrLenOOBTestTemplate(char *str, size_t length, OOBKind oob_kind) {
- // Normal strlen calls
- EXPECT_EQ(strlen(str), length);
- if (length > 0) {
- EXPECT_EQ(length - 1, strlen(str + 1));
- EXPECT_EQ(0U, strlen(str + length));
- }
- // Arg of strlen is not malloced, OOB access
- if (oob_kind != OOBKind::Global) {
- // We don't insert RedZones to the left of global variables
- EXPECT_DEATH(Ident(strlen(str - 1)), LeftOOBReadMessage(oob_kind, 1));
- EXPECT_DEATH(Ident(strlen(str - 5)), LeftOOBReadMessage(oob_kind, 5));
- }
- EXPECT_DEATH(Ident(strlen(str + length + 1)),
- RightOOBReadMessage(oob_kind, 0));
- // Overwrite terminator
- str[length] = 'a';
- // String is not zero-terminated, strlen will lead to OOB access
- EXPECT_DEATH(Ident(strlen(str)), RightOOBReadMessage(oob_kind, 0));
- EXPECT_DEATH(Ident(strlen(str + length)), RightOOBReadMessage(oob_kind, 0));
- // Restore terminator
- str[length] = 0;
-}
-TEST(AddressSanitizer, StrLenOOBTest) {
- // Check heap-allocated string
- size_t length = Ident(10);
- char *heap_string = Ident((char*)malloc(length + 1));
- char stack_string[10 + 1];
- break_optimization(&stack_string);
- for (size_t i = 0; i < length; i++) {
- heap_string[i] = 'a';
- stack_string[i] = 'b';
- }
- heap_string[length] = 0;
- stack_string[length] = 0;
- StrLenOOBTestTemplate(heap_string, length, OOBKind::Heap);
- StrLenOOBTestTemplate(stack_string, length, OOBKind::Stack);
- StrLenOOBTestTemplate(global_string, global_string_length, OOBKind::Global);
- free(heap_string);
-}
-
-// 32-bit android libc++-based NDK toolchain links wcslen statically, disabling
-// the interceptor.
-#if !defined(__ANDROID__) || defined(__LP64__)
-TEST(AddressSanitizer, WcsLenTest) {
- EXPECT_EQ(0U, wcslen(Ident(L"")));
- size_t hello_len = 13;
- size_t hello_size = (hello_len + 1) * sizeof(wchar_t);
- EXPECT_EQ(hello_len, wcslen(Ident(L"Hello, World!")));
- wchar_t *heap_string = Ident((wchar_t*)malloc(hello_size));
- memcpy(heap_string, L"Hello, World!", hello_size);
- EXPECT_EQ(hello_len, Ident(wcslen(heap_string)));
- EXPECT_DEATH(Ident(wcslen(heap_string + 14)), RightOOBReadMessage(0));
- free(heap_string);
-}
-#endif
-
-#if SANITIZER_TEST_HAS_STRNLEN
-TEST(AddressSanitizer, StrNLenOOBTest) {
- size_t size = Ident(123);
- char *str = MallocAndMemsetString(size);
- // Normal strnlen calls.
- Ident(strnlen(str - 1, 0));
- Ident(strnlen(str, size));
- Ident(strnlen(str + size - 1, 1));
- str[size - 1] = '\0';
- Ident(strnlen(str, 2 * size));
- // Argument points to not allocated memory.
- EXPECT_DEATH(Ident(strnlen(str - 1, 1)), LeftOOBReadMessage(1));
- EXPECT_DEATH(Ident(strnlen(str + size, 1)), RightOOBReadMessage(0));
- // Overwrite the terminating '\0' and hit unallocated memory.
- str[size - 1] = 'z';
- EXPECT_DEATH(Ident(strnlen(str, size + 1)), RightOOBReadMessage(0));
- free(str);
-}
-#endif // SANITIZER_TEST_HAS_STRNLEN
-
-// This test fails with the WinASan dynamic runtime because we fail to intercept
-// strdup.
-#if defined(_MSC_VER) && defined(_DLL)
-#define MAYBE_StrDupOOBTest DISABLED_StrDupOOBTest
-#else
-#define MAYBE_StrDupOOBTest StrDupOOBTest
-#endif
-
-TEST(AddressSanitizer, MAYBE_StrDupOOBTest) {
- size_t size = Ident(42);
- char *str = MallocAndMemsetString(size);
- char *new_str;
- // Normal strdup calls.
- str[size - 1] = '\0';
- new_str = strdup(str);
- free(new_str);
- new_str = strdup(str + size - 1);
- free(new_str);
- // Argument points to not allocated memory.
- EXPECT_DEATH(Ident(strdup(str - 1)), LeftOOBReadMessage(1));
- EXPECT_DEATH(Ident(strdup(str + size)), RightOOBReadMessage(0));
- // Overwrite the terminating '\0' and hit unallocated memory.
- str[size - 1] = 'z';
- EXPECT_DEATH(Ident(strdup(str)), RightOOBReadMessage(0));
- free(str);
-}
-
-#if SANITIZER_TEST_HAS_STRNDUP
-TEST(AddressSanitizer, MAYBE_StrNDupOOBTest) {
- size_t size = Ident(42);
- char *str = MallocAndMemsetString(size);
- char *new_str;
- // Normal strndup calls.
- str[size - 1] = '\0';
- new_str = strndup(str, size - 13);
- free(new_str);
- new_str = strndup(str + size - 1, 13);
- free(new_str);
- // Argument points to not allocated memory.
- EXPECT_DEATH(Ident(strndup(str - 1, 13)), LeftOOBReadMessage(1));
- EXPECT_DEATH(Ident(strndup(str + size, 13)), RightOOBReadMessage(0));
- // Overwrite the terminating '\0' and hit unallocated memory.
- str[size - 1] = 'z';
- EXPECT_DEATH(Ident(strndup(str, size + 13)), RightOOBReadMessage(0));
- // Check handling of non 0 terminated strings.
- Ident(new_str = strndup(str + size - 1, 0));
- free(new_str);
- Ident(new_str = strndup(str + size - 1, 1));
- free(new_str);
- EXPECT_DEATH(Ident(strndup(str + size - 1, 2)), RightOOBReadMessage(0));
- free(str);
-}
-#endif // SANITIZER_TEST_HAS_STRNDUP
-
-TEST(AddressSanitizer, StrCpyOOBTest) {
- size_t to_size = Ident(30);
- size_t from_size = Ident(6); // less than to_size
- char *to = Ident((char*)malloc(to_size));
- char *from = Ident((char*)malloc(from_size));
- // Normal strcpy calls.
- strcpy(from, "hello");
- strcpy(to, from);
- strcpy(to + to_size - from_size, from);
- // Length of "from" is too small.
- EXPECT_DEATH(Ident(strcpy(from, "hello2")), RightOOBWriteMessage(0));
- // "to" or "from" points to not allocated memory.
- EXPECT_DEATH(Ident(strcpy(to - 1, from)), LeftOOBWriteMessage(1));
- EXPECT_DEATH(Ident(strcpy(to, from - 1)), LeftOOBReadMessage(1));
- EXPECT_DEATH(Ident(strcpy(to, from + from_size)), RightOOBReadMessage(0));
- EXPECT_DEATH(Ident(strcpy(to + to_size, from)), RightOOBWriteMessage(0));
- // Overwrite the terminating '\0' character and hit unallocated memory.
- from[from_size - 1] = '!';
- EXPECT_DEATH(Ident(strcpy(to, from)), RightOOBReadMessage(0));
- free(to);
- free(from);
-}
-
-TEST(AddressSanitizer, StrNCpyOOBTest) {
- size_t to_size = Ident(20);
- size_t from_size = Ident(6); // less than to_size
- char *to = Ident((char*)malloc(to_size));
- // From is a zero-terminated string "hello\0" of length 6
- char *from = Ident((char*)malloc(from_size));
- strcpy(from, "hello");
- // copy 0 bytes
- strncpy(to, from, 0);
- strncpy(to - 1, from - 1, 0);
- // normal strncpy calls
- strncpy(to, from, from_size);
- strncpy(to, from, to_size);
- strncpy(to, from + from_size - 1, to_size);
- strncpy(to + to_size - 1, from, 1);
- // One of {to, from} points to not allocated memory
- EXPECT_DEATH(Ident(strncpy(to, from - 1, from_size)),
- LeftOOBReadMessage(1));
- EXPECT_DEATH(Ident(strncpy(to - 1, from, from_size)),
- LeftOOBWriteMessage(1));
- EXPECT_DEATH(Ident(strncpy(to, from + from_size, 1)),
- RightOOBReadMessage(0));
- EXPECT_DEATH(Ident(strncpy(to + to_size, from, 1)),
- RightOOBWriteMessage(0));
- // Length of "to" is too small
- EXPECT_DEATH(Ident(strncpy(to + to_size - from_size + 1, from, from_size)),
- RightOOBWriteMessage(0));
- EXPECT_DEATH(Ident(strncpy(to + 1, from, to_size)),
- RightOOBWriteMessage(0));
- // Overwrite terminator in from
- from[from_size - 1] = '!';
- // normal strncpy call
- strncpy(to, from, from_size);
- // Length of "from" is too small
- EXPECT_DEATH(Ident(strncpy(to, from, to_size)),
- RightOOBReadMessage(0));
- free(to);
- free(from);
-}
-
-// Users may have different definitions of "strchr" and "index", so provide
-// function pointer typedefs and overload RunStrChrTest implementation.
-// We can't use macro for RunStrChrTest body here, as this macro would
-// confuse EXPECT_DEATH gtest macro.
-typedef char*(*PointerToStrChr1)(const char*, int);
-typedef char*(*PointerToStrChr2)(char*, int);
-
-template<typename StrChrFn>
-static void RunStrChrTestImpl(StrChrFn *StrChr) {
- size_t size = Ident(100);
- char *str = MallocAndMemsetString(size);
- str[10] = 'q';
- str[11] = '\0';
- EXPECT_EQ(str, StrChr(str, 'z'));
- EXPECT_EQ(str + 10, StrChr(str, 'q'));
- EXPECT_EQ(NULL, StrChr(str, 'a'));
- // StrChr argument points to not allocated memory.
- EXPECT_DEATH(Ident(StrChr(str - 1, 'z')), LeftOOBReadMessage(1));
- EXPECT_DEATH(Ident(StrChr(str + size, 'z')), RightOOBReadMessage(0));
- // Overwrite the terminator and hit not allocated memory.
- str[11] = 'z';
- EXPECT_DEATH(Ident(StrChr(str, 'a')), RightOOBReadMessage(0));
- free(str);
-}
-
-// Prefer to use the standard signature if both are available.
-UNUSED static void RunStrChrTest(PointerToStrChr1 StrChr, ...) {
- RunStrChrTestImpl(StrChr);
-}
-UNUSED static void RunStrChrTest(PointerToStrChr2 StrChr, int) {
- RunStrChrTestImpl(StrChr);
-}
-
-TEST(AddressSanitizer, StrChrAndIndexOOBTest) {
- RunStrChrTest(&strchr, 0);
-// No index() on Windows and on Android L.
-#if !defined(_WIN32) && !defined(__ANDROID__)
- RunStrChrTest(&index, 0);
-#endif
-}
-
-TEST(AddressSanitizer, StrCmpAndFriendsLogicTest) {
- // strcmp
- EXPECT_EQ(0, strcmp("", ""));
- EXPECT_EQ(0, strcmp("abcd", "abcd"));
- EXPECT_GT(0, strcmp("ab", "ac"));
- EXPECT_GT(0, strcmp("abc", "abcd"));
- EXPECT_LT(0, strcmp("acc", "abc"));
- EXPECT_LT(0, strcmp("abcd", "abc"));
-
- // strncmp
- EXPECT_EQ(0, strncmp("a", "b", 0));
- EXPECT_EQ(0, strncmp("abcd", "abcd", 10));
- EXPECT_EQ(0, strncmp("abcd", "abcef", 3));
- EXPECT_GT(0, strncmp("abcde", "abcfa", 4));
- EXPECT_GT(0, strncmp("a", "b", 5));
- EXPECT_GT(0, strncmp("bc", "bcde", 4));
- EXPECT_LT(0, strncmp("xyz", "xyy", 10));
- EXPECT_LT(0, strncmp("baa", "aaa", 1));
- EXPECT_LT(0, strncmp("zyx", "", 2));
-
-#if !defined(_WIN32) // no str[n]casecmp on Windows.
- // strcasecmp
- EXPECT_EQ(0, strcasecmp("", ""));
- EXPECT_EQ(0, strcasecmp("zzz", "zzz"));
- EXPECT_EQ(0, strcasecmp("abCD", "ABcd"));
- EXPECT_GT(0, strcasecmp("aB", "Ac"));
- EXPECT_GT(0, strcasecmp("ABC", "ABCd"));
- EXPECT_LT(0, strcasecmp("acc", "abc"));
- EXPECT_LT(0, strcasecmp("ABCd", "abc"));
-
- // strncasecmp
- EXPECT_EQ(0, strncasecmp("a", "b", 0));
- EXPECT_EQ(0, strncasecmp("abCD", "ABcd", 10));
- EXPECT_EQ(0, strncasecmp("abCd", "ABcef", 3));
- EXPECT_GT(0, strncasecmp("abcde", "ABCfa", 4));
- EXPECT_GT(0, strncasecmp("a", "B", 5));
- EXPECT_GT(0, strncasecmp("bc", "BCde", 4));
- EXPECT_LT(0, strncasecmp("xyz", "xyy", 10));
- EXPECT_LT(0, strncasecmp("Baa", "aaa", 1));
- EXPECT_LT(0, strncasecmp("zyx", "", 2));
-#endif
-
- // memcmp
- EXPECT_EQ(0, memcmp("a", "b", 0));
- EXPECT_EQ(0, memcmp("ab\0c", "ab\0c", 4));
- EXPECT_GT(0, memcmp("\0ab", "\0ac", 3));
- EXPECT_GT(0, memcmp("abb\0", "abba", 4));
- EXPECT_LT(0, memcmp("ab\0cd", "ab\0c\0", 5));
- EXPECT_LT(0, memcmp("zza", "zyx", 3));
-}
-
-typedef int(*PointerToStrCmp)(const char*, const char*);
-void RunStrCmpTest(PointerToStrCmp StrCmp) {
- size_t size = Ident(100);
- int fill = 'o';
- char *s1 = MallocAndMemsetString(size, fill);
- char *s2 = MallocAndMemsetString(size, fill);
- s1[size - 1] = '\0';
- s2[size - 1] = '\0';
- // Normal StrCmp calls
- Ident(StrCmp(s1, s2));
- Ident(StrCmp(s1, s2 + size - 1));
- Ident(StrCmp(s1 + size - 1, s2 + size - 1));
- // One of arguments points to not allocated memory.
- EXPECT_DEATH(Ident(StrCmp)(s1 - 1, s2), LeftOOBReadMessage(1));
- EXPECT_DEATH(Ident(StrCmp)(s1, s2 - 1), LeftOOBReadMessage(1));
- EXPECT_DEATH(Ident(StrCmp)(s1 + size, s2), RightOOBReadMessage(0));
- EXPECT_DEATH(Ident(StrCmp)(s1, s2 + size), RightOOBReadMessage(0));
- // Hit unallocated memory and die.
- s1[size - 1] = fill;
- EXPECT_DEATH(Ident(StrCmp)(s1, s1), RightOOBReadMessage(0));
- EXPECT_DEATH(Ident(StrCmp)(s1 + size - 1, s2), RightOOBReadMessage(0));
- free(s1);
- free(s2);
-}
-
-TEST(AddressSanitizer, StrCmpOOBTest) {
- RunStrCmpTest(&strcmp);
-}
-
-#if !defined(_WIN32) // no str[n]casecmp on Windows.
-TEST(AddressSanitizer, StrCaseCmpOOBTest) {
- RunStrCmpTest(&strcasecmp);
-}
-#endif
-
-typedef int(*PointerToStrNCmp)(const char*, const char*, size_t);
-void RunStrNCmpTest(PointerToStrNCmp StrNCmp) {
- size_t size = Ident(100);
- char *s1 = MallocAndMemsetString(size);
- char *s2 = MallocAndMemsetString(size);
- s1[size - 1] = '\0';
- s2[size - 1] = '\0';
- // Normal StrNCmp calls
- Ident(StrNCmp(s1, s2, size + 2));
- s1[size - 1] = 'z';
- s2[size - 1] = 'x';
- Ident(StrNCmp(s1 + size - 2, s2 + size - 2, size));
- s2[size - 1] = 'z';
- Ident(StrNCmp(s1 - 1, s2 - 1, 0));
- Ident(StrNCmp(s1 + size - 1, s2 + size - 1, 1));
- // One of arguments points to not allocated memory.
- EXPECT_DEATH(Ident(StrNCmp)(s1 - 1, s2, 1), LeftOOBReadMessage(1));
- EXPECT_DEATH(Ident(StrNCmp)(s1, s2 - 1, 1), LeftOOBReadMessage(1));
- EXPECT_DEATH(Ident(StrNCmp)(s1 + size, s2, 1), RightOOBReadMessage(0));
- EXPECT_DEATH(Ident(StrNCmp)(s1, s2 + size, 1), RightOOBReadMessage(0));
- // Hit unallocated memory and die.
- EXPECT_DEATH(Ident(StrNCmp)(s1 + 1, s2 + 1, size), RightOOBReadMessage(0));
- EXPECT_DEATH(Ident(StrNCmp)(s1 + size - 1, s2, 2), RightOOBReadMessage(0));
- free(s1);
- free(s2);
-}
-
-TEST(AddressSanitizer, StrNCmpOOBTest) {
- RunStrNCmpTest(&strncmp);
-}
-
-#if !defined(_WIN32) // no str[n]casecmp on Windows.
-TEST(AddressSanitizer, StrNCaseCmpOOBTest) {
- RunStrNCmpTest(&strncasecmp);
-}
-#endif
-
-TEST(AddressSanitizer, StrCatOOBTest) {
- // strcat() reads strlen(to) bytes from |to| before concatenating.
- size_t to_size = Ident(100);
- char *to = MallocAndMemsetString(to_size);
- to[0] = '\0';
- size_t from_size = Ident(20);
- char *from = MallocAndMemsetString(from_size);
- from[from_size - 1] = '\0';
- // Normal strcat calls.
- strcat(to, from);
- strcat(to, from);
- strcat(to + from_size, from + from_size - 2);
- // Passing an invalid pointer is an error even when concatenating an empty
- // string.
- EXPECT_DEATH(strcat(to - 1, from + from_size - 1), LeftOOBAccessMessage(1));
- // One of arguments points to not allocated memory.
- EXPECT_DEATH(strcat(to - 1, from), LeftOOBAccessMessage(1));
- EXPECT_DEATH(strcat(to, from - 1), LeftOOBReadMessage(1));
- EXPECT_DEATH(strcat(to, from + from_size), RightOOBReadMessage(0));
-
- // "from" is not zero-terminated.
- from[from_size - 1] = 'z';
- EXPECT_DEATH(strcat(to, from), RightOOBReadMessage(0));
- from[from_size - 1] = '\0';
- // "to" is too short to fit "from".
- memset(to, 'z', to_size);
- to[to_size - from_size + 1] = '\0';
- EXPECT_DEATH(strcat(to, from), RightOOBWriteMessage(0));
- // length of "to" is just enough.
- strcat(to, from + 1);
-
- free(to);
- free(from);
-}
-
-TEST(AddressSanitizer, StrNCatOOBTest) {
- // strncat() reads strlen(to) bytes from |to| before concatenating.
- size_t to_size = Ident(100);
- char *to = MallocAndMemsetString(to_size);
- to[0] = '\0';
- size_t from_size = Ident(20);
- char *from = MallocAndMemsetString(from_size);
- // Normal strncat calls.
- strncat(to, from, 0);
- strncat(to, from, from_size);
- from[from_size - 1] = '\0';
- strncat(to, from, 2 * from_size);
- // Catenating empty string with an invalid string is still an error.
- EXPECT_DEATH(strncat(to - 1, from, 0), LeftOOBAccessMessage(1));
- strncat(to, from + from_size - 1, 10);
- // One of arguments points to not allocated memory.
- EXPECT_DEATH(strncat(to - 1, from, 2), LeftOOBAccessMessage(1));
- EXPECT_DEATH(strncat(to, from - 1, 2), LeftOOBReadMessage(1));
- EXPECT_DEATH(strncat(to, from + from_size, 2), RightOOBReadMessage(0));
-
- memset(from, 'z', from_size);
- memset(to, 'z', to_size);
- to[0] = '\0';
- // "from" is too short.
- EXPECT_DEATH(strncat(to, from, from_size + 1), RightOOBReadMessage(0));
- // "to" is too short to fit "from".
- to[0] = 'z';
- to[to_size - from_size + 1] = '\0';
- EXPECT_DEATH(strncat(to, from, from_size - 1), RightOOBWriteMessage(0));
- // "to" is just enough.
- strncat(to, from, from_size - 2);
-
- free(to);
- free(from);
-}
-
-static string OverlapErrorMessage(const string &func) {
- return func + "-param-overlap";
-}
-
-TEST(AddressSanitizer, StrArgsOverlapTest) {
- size_t size = Ident(100);
- char *str = Ident((char*)malloc(size));
-
-// Do not check memcpy() on OS X 10.7 and later, where it actually aliases
-// memmove().
-#if !defined(__APPLE__) || !defined(MAC_OS_X_VERSION_10_7) || \
- (MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_7)
- // Check "memcpy". Use Ident() to avoid inlining.
-#if PLATFORM_HAS_DIFFERENT_MEMCPY_AND_MEMMOVE
- memset(str, 'z', size);
- Ident(memcpy)(str + 1, str + 11, 10);
- Ident(memcpy)(str, str, 0);
- EXPECT_DEATH(Ident(memcpy)(str, str + 14, 15), OverlapErrorMessage("memcpy"));
- EXPECT_DEATH(Ident(memcpy)(str + 14, str, 15), OverlapErrorMessage("memcpy"));
-#endif
-#endif
-
- // We do not treat memcpy with to==from as a bug.
- // See http://llvm.org/bugs/show_bug.cgi?id=11763.
- // EXPECT_DEATH(Ident(memcpy)(str + 20, str + 20, 1),
- // OverlapErrorMessage("memcpy"));
-
- // Check "strcpy".
- memset(str, 'z', size);
- str[9] = '\0';
- strcpy(str + 10, str);
- EXPECT_DEATH(strcpy(str + 9, str), OverlapErrorMessage("strcpy"));
- EXPECT_DEATH(strcpy(str, str + 4), OverlapErrorMessage("strcpy"));
- strcpy(str, str + 5);
-
- // Check "strncpy".
- memset(str, 'z', size);
- strncpy(str, str + 10, 10);
- EXPECT_DEATH(strncpy(str, str + 9, 10), OverlapErrorMessage("strncpy"));
- EXPECT_DEATH(strncpy(str + 9, str, 10), OverlapErrorMessage("strncpy"));
- str[10] = '\0';
- strncpy(str + 11, str, 20);
- EXPECT_DEATH(strncpy(str + 10, str, 20), OverlapErrorMessage("strncpy"));
-
- // Check "strcat".
- memset(str, 'z', size);
- str[10] = '\0';
- str[20] = '\0';
- strcat(str, str + 10);
- EXPECT_DEATH(strcat(str, str + 11), OverlapErrorMessage("strcat"));
- str[10] = '\0';
- strcat(str + 11, str);
- EXPECT_DEATH(strcat(str, str + 9), OverlapErrorMessage("strcat"));
- EXPECT_DEATH(strcat(str + 9, str), OverlapErrorMessage("strcat"));
- EXPECT_DEATH(strcat(str + 10, str), OverlapErrorMessage("strcat"));
-
- // Check "strncat".
- memset(str, 'z', size);
- str[10] = '\0';
- strncat(str, str + 10, 10); // from is empty
- EXPECT_DEATH(strncat(str, str + 11, 10), OverlapErrorMessage("strncat"));
- str[10] = '\0';
- str[20] = '\0';
- strncat(str + 5, str, 5);
- str[10] = '\0';
- EXPECT_DEATH(strncat(str + 5, str, 6), OverlapErrorMessage("strncat"));
- EXPECT_DEATH(strncat(str, str + 9, 10), OverlapErrorMessage("strncat"));
-
- free(str);
-}
-
-typedef void(*PointerToCallAtoi)(const char*);
-
-void RunAtoiOOBTest(PointerToCallAtoi Atoi) {
- char *array = MallocAndMemsetString(10, '1');
- // Invalid pointer to the string.
- EXPECT_DEATH(Atoi(array + 11), RightOOBReadMessage(1));
- EXPECT_DEATH(Atoi(array - 1), LeftOOBReadMessage(1));
- // Die if a buffer doesn't have terminating NULL.
- EXPECT_DEATH(Atoi(array), RightOOBReadMessage(0));
- // Make last symbol a terminating NULL
- array[9] = '\0';
- Atoi(array);
- // Sometimes we need to detect overflow if no digits are found.
- memset(array, ' ', 10);
- EXPECT_DEATH(Atoi(array), RightOOBReadMessage(0));
- array[9] = '-';
- EXPECT_DEATH(Atoi(array), RightOOBReadMessage(0));
- EXPECT_DEATH(Atoi(array + 9), RightOOBReadMessage(0));
- free(array);
-}
-
-#if !defined(_WIN32) // FIXME: Fix and enable on Windows.
-void CallAtoi(const char *nptr) {
- Ident(atoi(nptr));
-}
-void CallAtol(const char *nptr) {
- Ident(atol(nptr));
-}
-void CallAtoll(const char *nptr) {
- Ident(atoll(nptr));
-}
-TEST(AddressSanitizer, AtoiAndFriendsOOBTest) {
- RunAtoiOOBTest(&CallAtoi);
- RunAtoiOOBTest(&CallAtol);
- RunAtoiOOBTest(&CallAtoll);
-}
-#endif
-
-typedef void(*PointerToCallStrtol)(const char*, char**, int);
-
-void RunStrtolOOBTest(PointerToCallStrtol Strtol) {
- char *array = MallocAndMemsetString(3);
- array[0] = '1';
- array[1] = '2';
- array[2] = '3';
- // Invalid pointer to the string.
- EXPECT_DEATH(Strtol(array + 3, NULL, 0), RightOOBReadMessage(0));
- EXPECT_DEATH(Strtol(array - 1, NULL, 0), LeftOOBReadMessage(1));
- // Buffer overflow if there is no terminating null (depends on base).
- EXPECT_DEATH(Strtol(array, NULL, 0), RightOOBReadMessage(0));
- array[2] = 'z';
- EXPECT_DEATH(Strtol(array, NULL, 36), RightOOBReadMessage(0));
- // Add terminating zero to get rid of overflow.
- array[2] = '\0';
- Strtol(array, NULL, 36);
- // Sometimes we need to detect overflow if no digits are found.
- array[0] = array[1] = array[2] = ' ';
- EXPECT_DEATH(Strtol(array, NULL, 0), RightOOBReadMessage(0));
- array[2] = '+';
- EXPECT_DEATH(Strtol(array, NULL, 0), RightOOBReadMessage(0));
- array[2] = '-';
- EXPECT_DEATH(Strtol(array, NULL, 0), RightOOBReadMessage(0));
- free(array);
-}
-
-#if !defined(_WIN32) // FIXME: Fix and enable on Windows.
-void CallStrtol(const char *nptr, char **endptr, int base) {
- Ident(strtol(nptr, endptr, base));
-}
-void CallStrtoll(const char *nptr, char **endptr, int base) {
- Ident(strtoll(nptr, endptr, base));
-}
-TEST(AddressSanitizer, StrtollOOBTest) {
- RunStrtolOOBTest(&CallStrtoll);
-}
-TEST(AddressSanitizer, StrtolOOBTest) {
- RunStrtolOOBTest(&CallStrtol);
-}
-#endif
--- /dev/null
+//=-- asan_str_test.cpp ---------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a part of AddressSanitizer, an address sanity checker.
+//
+//===----------------------------------------------------------------------===//
+#include "asan_test_utils.h"
+
+#if defined(__APPLE__)
+#include <AvailabilityMacros.h> // For MAC_OS_X_VERSION_*
+#endif
+
+// Used for string functions tests
+static char global_string[] = "global";
+static size_t global_string_length = 6;
+
+const char kStackReadUnderflow[] =
+#if !GTEST_USES_SIMPLE_RE
+ ASAN_PCRE_DOTALL
+ "READ.*"
+#endif
+ "underflows this variable";
+const char kStackReadOverflow[] =
+#if !GTEST_USES_SIMPLE_RE
+ ASAN_PCRE_DOTALL
+ "READ.*"
+#endif
+ "overflows this variable";
+
+namespace {
+enum class OOBKind {
+ Heap,
+ Stack,
+ Global,
+};
+
+string LeftOOBReadMessage(OOBKind oob_kind, int oob_distance) {
+ return oob_kind == OOBKind::Stack ? kStackReadUnderflow
+ : ::LeftOOBReadMessage(oob_distance);
+}
+
+string RightOOBReadMessage(OOBKind oob_kind, int oob_distance) {
+ return oob_kind == OOBKind::Stack ? kStackReadOverflow
+ : ::RightOOBReadMessage(oob_distance);
+}
+} // namespace
+
+// Input to a test is a zero-terminated string str with given length
+// Accesses to the bytes to the left and to the right of str
+// are presumed to produce OOB errors
+void StrLenOOBTestTemplate(char *str, size_t length, OOBKind oob_kind) {
+ // Normal strlen calls
+ EXPECT_EQ(strlen(str), length);
+ if (length > 0) {
+ EXPECT_EQ(length - 1, strlen(str + 1));
+ EXPECT_EQ(0U, strlen(str + length));
+ }
+ // Arg of strlen is not malloced, OOB access
+ if (oob_kind != OOBKind::Global) {
+ // We don't insert RedZones to the left of global variables
+ EXPECT_DEATH(Ident(strlen(str - 1)), LeftOOBReadMessage(oob_kind, 1));
+ EXPECT_DEATH(Ident(strlen(str - 5)), LeftOOBReadMessage(oob_kind, 5));
+ }
+ EXPECT_DEATH(Ident(strlen(str + length + 1)),
+ RightOOBReadMessage(oob_kind, 0));
+ // Overwrite terminator
+ str[length] = 'a';
+ // String is not zero-terminated, strlen will lead to OOB access
+ EXPECT_DEATH(Ident(strlen(str)), RightOOBReadMessage(oob_kind, 0));
+ EXPECT_DEATH(Ident(strlen(str + length)), RightOOBReadMessage(oob_kind, 0));
+ // Restore terminator
+ str[length] = 0;
+}
+TEST(AddressSanitizer, StrLenOOBTest) {
+ // Check heap-allocated string
+ size_t length = Ident(10);
+ char *heap_string = Ident((char*)malloc(length + 1));
+ char stack_string[10 + 1];
+ break_optimization(&stack_string);
+ for (size_t i = 0; i < length; i++) {
+ heap_string[i] = 'a';
+ stack_string[i] = 'b';
+ }
+ heap_string[length] = 0;
+ stack_string[length] = 0;
+ StrLenOOBTestTemplate(heap_string, length, OOBKind::Heap);
+ StrLenOOBTestTemplate(stack_string, length, OOBKind::Stack);
+ StrLenOOBTestTemplate(global_string, global_string_length, OOBKind::Global);
+ free(heap_string);
+}
+
+// 32-bit android libc++-based NDK toolchain links wcslen statically, disabling
+// the interceptor.
+#if !defined(__ANDROID__) || defined(__LP64__)
+TEST(AddressSanitizer, WcsLenTest) {
+ EXPECT_EQ(0U, wcslen(Ident(L"")));
+ size_t hello_len = 13;
+ size_t hello_size = (hello_len + 1) * sizeof(wchar_t);
+ EXPECT_EQ(hello_len, wcslen(Ident(L"Hello, World!")));
+ wchar_t *heap_string = Ident((wchar_t*)malloc(hello_size));
+ memcpy(heap_string, L"Hello, World!", hello_size);
+ EXPECT_EQ(hello_len, Ident(wcslen(heap_string)));
+ EXPECT_DEATH(Ident(wcslen(heap_string + 14)), RightOOBReadMessage(0));
+ free(heap_string);
+}
+#endif
+
+#if SANITIZER_TEST_HAS_STRNLEN
+TEST(AddressSanitizer, StrNLenOOBTest) {
+ size_t size = Ident(123);
+ char *str = MallocAndMemsetString(size);
+ // Normal strnlen calls.
+ Ident(strnlen(str - 1, 0));
+ Ident(strnlen(str, size));
+ Ident(strnlen(str + size - 1, 1));
+ str[size - 1] = '\0';
+ Ident(strnlen(str, 2 * size));
+ // Argument points to not allocated memory.
+ EXPECT_DEATH(Ident(strnlen(str - 1, 1)), LeftOOBReadMessage(1));
+ EXPECT_DEATH(Ident(strnlen(str + size, 1)), RightOOBReadMessage(0));
+ // Overwrite the terminating '\0' and hit unallocated memory.
+ str[size - 1] = 'z';
+ EXPECT_DEATH(Ident(strnlen(str, size + 1)), RightOOBReadMessage(0));
+ free(str);
+}
+#endif // SANITIZER_TEST_HAS_STRNLEN
+
+// This test fails with the WinASan dynamic runtime because we fail to intercept
+// strdup.
+#if defined(_MSC_VER) && defined(_DLL)
+#define MAYBE_StrDupOOBTest DISABLED_StrDupOOBTest
+#else
+#define MAYBE_StrDupOOBTest StrDupOOBTest
+#endif
+
+TEST(AddressSanitizer, MAYBE_StrDupOOBTest) {
+ size_t size = Ident(42);
+ char *str = MallocAndMemsetString(size);
+ char *new_str;
+ // Normal strdup calls.
+ str[size - 1] = '\0';
+ new_str = strdup(str);
+ free(new_str);
+ new_str = strdup(str + size - 1);
+ free(new_str);
+ // Argument points to not allocated memory.
+ EXPECT_DEATH(Ident(strdup(str - 1)), LeftOOBReadMessage(1));
+ EXPECT_DEATH(Ident(strdup(str + size)), RightOOBReadMessage(0));
+ // Overwrite the terminating '\0' and hit unallocated memory.
+ str[size - 1] = 'z';
+ EXPECT_DEATH(Ident(strdup(str)), RightOOBReadMessage(0));
+ free(str);
+}
+
+#if SANITIZER_TEST_HAS_STRNDUP
+TEST(AddressSanitizer, MAYBE_StrNDupOOBTest) {
+ size_t size = Ident(42);
+ char *str = MallocAndMemsetString(size);
+ char *new_str;
+ // Normal strndup calls.
+ str[size - 1] = '\0';
+ new_str = strndup(str, size - 13);
+ free(new_str);
+ new_str = strndup(str + size - 1, 13);
+ free(new_str);
+ // Argument points to not allocated memory.
+ EXPECT_DEATH(Ident(strndup(str - 1, 13)), LeftOOBReadMessage(1));
+ EXPECT_DEATH(Ident(strndup(str + size, 13)), RightOOBReadMessage(0));
+ // Overwrite the terminating '\0' and hit unallocated memory.
+ str[size - 1] = 'z';
+ EXPECT_DEATH(Ident(strndup(str, size + 13)), RightOOBReadMessage(0));
+ // Check handling of non 0 terminated strings.
+ Ident(new_str = strndup(str + size - 1, 0));
+ free(new_str);
+ Ident(new_str = strndup(str + size - 1, 1));
+ free(new_str);
+ EXPECT_DEATH(Ident(strndup(str + size - 1, 2)), RightOOBReadMessage(0));
+ free(str);
+}
+#endif // SANITIZER_TEST_HAS_STRNDUP
+
+TEST(AddressSanitizer, StrCpyOOBTest) {
+ size_t to_size = Ident(30);
+ size_t from_size = Ident(6); // less than to_size
+ char *to = Ident((char*)malloc(to_size));
+ char *from = Ident((char*)malloc(from_size));
+ // Normal strcpy calls.
+ strcpy(from, "hello");
+ strcpy(to, from);
+ strcpy(to + to_size - from_size, from);
+ // Length of "from" is too small.
+ EXPECT_DEATH(Ident(strcpy(from, "hello2")), RightOOBWriteMessage(0));
+ // "to" or "from" points to not allocated memory.
+ EXPECT_DEATH(Ident(strcpy(to - 1, from)), LeftOOBWriteMessage(1));
+ EXPECT_DEATH(Ident(strcpy(to, from - 1)), LeftOOBReadMessage(1));
+ EXPECT_DEATH(Ident(strcpy(to, from + from_size)), RightOOBReadMessage(0));
+ EXPECT_DEATH(Ident(strcpy(to + to_size, from)), RightOOBWriteMessage(0));
+ // Overwrite the terminating '\0' character and hit unallocated memory.
+ from[from_size - 1] = '!';
+ EXPECT_DEATH(Ident(strcpy(to, from)), RightOOBReadMessage(0));
+ free(to);
+ free(from);
+}
+
+TEST(AddressSanitizer, StrNCpyOOBTest) {
+ size_t to_size = Ident(20);
+ size_t from_size = Ident(6); // less than to_size
+ char *to = Ident((char*)malloc(to_size));
+ // From is a zero-terminated string "hello\0" of length 6
+ char *from = Ident((char*)malloc(from_size));
+ strcpy(from, "hello");
+ // copy 0 bytes
+ strncpy(to, from, 0);
+ strncpy(to - 1, from - 1, 0);
+ // normal strncpy calls
+ strncpy(to, from, from_size);
+ strncpy(to, from, to_size);
+ strncpy(to, from + from_size - 1, to_size);
+ strncpy(to + to_size - 1, from, 1);
+ // One of {to, from} points to not allocated memory
+ EXPECT_DEATH(Ident(strncpy(to, from - 1, from_size)),
+ LeftOOBReadMessage(1));
+ EXPECT_DEATH(Ident(strncpy(to - 1, from, from_size)),
+ LeftOOBWriteMessage(1));
+ EXPECT_DEATH(Ident(strncpy(to, from + from_size, 1)),
+ RightOOBReadMessage(0));
+ EXPECT_DEATH(Ident(strncpy(to + to_size, from, 1)),
+ RightOOBWriteMessage(0));
+ // Length of "to" is too small
+ EXPECT_DEATH(Ident(strncpy(to + to_size - from_size + 1, from, from_size)),
+ RightOOBWriteMessage(0));
+ EXPECT_DEATH(Ident(strncpy(to + 1, from, to_size)),
+ RightOOBWriteMessage(0));
+ // Overwrite terminator in from
+ from[from_size - 1] = '!';
+ // normal strncpy call
+ strncpy(to, from, from_size);
+ // Length of "from" is too small
+ EXPECT_DEATH(Ident(strncpy(to, from, to_size)),
+ RightOOBReadMessage(0));
+ free(to);
+ free(from);
+}
+
+// Users may have different definitions of "strchr" and "index", so provide
+// function pointer typedefs and overload RunStrChrTest implementation.
+// We can't use macro for RunStrChrTest body here, as this macro would
+// confuse EXPECT_DEATH gtest macro.
+typedef char*(*PointerToStrChr1)(const char*, int);
+typedef char*(*PointerToStrChr2)(char*, int);
+
+template<typename StrChrFn>
+static void RunStrChrTestImpl(StrChrFn *StrChr) {
+ size_t size = Ident(100);
+ char *str = MallocAndMemsetString(size);
+ str[10] = 'q';
+ str[11] = '\0';
+ EXPECT_EQ(str, StrChr(str, 'z'));
+ EXPECT_EQ(str + 10, StrChr(str, 'q'));
+ EXPECT_EQ(NULL, StrChr(str, 'a'));
+ // StrChr argument points to not allocated memory.
+ EXPECT_DEATH(Ident(StrChr(str - 1, 'z')), LeftOOBReadMessage(1));
+ EXPECT_DEATH(Ident(StrChr(str + size, 'z')), RightOOBReadMessage(0));
+ // Overwrite the terminator and hit not allocated memory.
+ str[11] = 'z';
+ EXPECT_DEATH(Ident(StrChr(str, 'a')), RightOOBReadMessage(0));
+ free(str);
+}
+
+// Prefer to use the standard signature if both are available.
+UNUSED static void RunStrChrTest(PointerToStrChr1 StrChr, ...) {
+ RunStrChrTestImpl(StrChr);
+}
+UNUSED static void RunStrChrTest(PointerToStrChr2 StrChr, int) {
+ RunStrChrTestImpl(StrChr);
+}
+
+TEST(AddressSanitizer, StrChrAndIndexOOBTest) {
+ RunStrChrTest(&strchr, 0);
+// No index() on Windows and on Android L.
+#if !defined(_WIN32) && !defined(__ANDROID__)
+ RunStrChrTest(&index, 0);
+#endif
+}
+
+TEST(AddressSanitizer, StrCmpAndFriendsLogicTest) {
+ // strcmp
+ EXPECT_EQ(0, strcmp("", ""));
+ EXPECT_EQ(0, strcmp("abcd", "abcd"));
+ EXPECT_GT(0, strcmp("ab", "ac"));
+ EXPECT_GT(0, strcmp("abc", "abcd"));
+ EXPECT_LT(0, strcmp("acc", "abc"));
+ EXPECT_LT(0, strcmp("abcd", "abc"));
+
+ // strncmp
+ EXPECT_EQ(0, strncmp("a", "b", 0));
+ EXPECT_EQ(0, strncmp("abcd", "abcd", 10));
+ EXPECT_EQ(0, strncmp("abcd", "abcef", 3));
+ EXPECT_GT(0, strncmp("abcde", "abcfa", 4));
+ EXPECT_GT(0, strncmp("a", "b", 5));
+ EXPECT_GT(0, strncmp("bc", "bcde", 4));
+ EXPECT_LT(0, strncmp("xyz", "xyy", 10));
+ EXPECT_LT(0, strncmp("baa", "aaa", 1));
+ EXPECT_LT(0, strncmp("zyx", "", 2));
+
+#if !defined(_WIN32) // no str[n]casecmp on Windows.
+ // strcasecmp
+ EXPECT_EQ(0, strcasecmp("", ""));
+ EXPECT_EQ(0, strcasecmp("zzz", "zzz"));
+ EXPECT_EQ(0, strcasecmp("abCD", "ABcd"));
+ EXPECT_GT(0, strcasecmp("aB", "Ac"));
+ EXPECT_GT(0, strcasecmp("ABC", "ABCd"));
+ EXPECT_LT(0, strcasecmp("acc", "abc"));
+ EXPECT_LT(0, strcasecmp("ABCd", "abc"));
+
+ // strncasecmp
+ EXPECT_EQ(0, strncasecmp("a", "b", 0));
+ EXPECT_EQ(0, strncasecmp("abCD", "ABcd", 10));
+ EXPECT_EQ(0, strncasecmp("abCd", "ABcef", 3));
+ EXPECT_GT(0, strncasecmp("abcde", "ABCfa", 4));
+ EXPECT_GT(0, strncasecmp("a", "B", 5));
+ EXPECT_GT(0, strncasecmp("bc", "BCde", 4));
+ EXPECT_LT(0, strncasecmp("xyz", "xyy", 10));
+ EXPECT_LT(0, strncasecmp("Baa", "aaa", 1));
+ EXPECT_LT(0, strncasecmp("zyx", "", 2));
+#endif
+
+ // memcmp
+ EXPECT_EQ(0, memcmp("a", "b", 0));
+ EXPECT_EQ(0, memcmp("ab\0c", "ab\0c", 4));
+ EXPECT_GT(0, memcmp("\0ab", "\0ac", 3));
+ EXPECT_GT(0, memcmp("abb\0", "abba", 4));
+ EXPECT_LT(0, memcmp("ab\0cd", "ab\0c\0", 5));
+ EXPECT_LT(0, memcmp("zza", "zyx", 3));
+}
+
+typedef int(*PointerToStrCmp)(const char*, const char*);
+void RunStrCmpTest(PointerToStrCmp StrCmp) {
+ size_t size = Ident(100);
+ int fill = 'o';
+ char *s1 = MallocAndMemsetString(size, fill);
+ char *s2 = MallocAndMemsetString(size, fill);
+ s1[size - 1] = '\0';
+ s2[size - 1] = '\0';
+ // Normal StrCmp calls
+ Ident(StrCmp(s1, s2));
+ Ident(StrCmp(s1, s2 + size - 1));
+ Ident(StrCmp(s1 + size - 1, s2 + size - 1));
+ // One of arguments points to not allocated memory.
+ EXPECT_DEATH(Ident(StrCmp)(s1 - 1, s2), LeftOOBReadMessage(1));
+ EXPECT_DEATH(Ident(StrCmp)(s1, s2 - 1), LeftOOBReadMessage(1));
+ EXPECT_DEATH(Ident(StrCmp)(s1 + size, s2), RightOOBReadMessage(0));
+ EXPECT_DEATH(Ident(StrCmp)(s1, s2 + size), RightOOBReadMessage(0));
+ // Hit unallocated memory and die.
+ s1[size - 1] = fill;
+ EXPECT_DEATH(Ident(StrCmp)(s1, s1), RightOOBReadMessage(0));
+ EXPECT_DEATH(Ident(StrCmp)(s1 + size - 1, s2), RightOOBReadMessage(0));
+ free(s1);
+ free(s2);
+}
+
+TEST(AddressSanitizer, StrCmpOOBTest) {
+ RunStrCmpTest(&strcmp);
+}
+
+#if !defined(_WIN32) // no str[n]casecmp on Windows.
+TEST(AddressSanitizer, StrCaseCmpOOBTest) {
+ RunStrCmpTest(&strcasecmp);
+}
+#endif
+
+typedef int(*PointerToStrNCmp)(const char*, const char*, size_t);
+void RunStrNCmpTest(PointerToStrNCmp StrNCmp) {
+ size_t size = Ident(100);
+ char *s1 = MallocAndMemsetString(size);
+ char *s2 = MallocAndMemsetString(size);
+ s1[size - 1] = '\0';
+ s2[size - 1] = '\0';
+ // Normal StrNCmp calls
+ Ident(StrNCmp(s1, s2, size + 2));
+ s1[size - 1] = 'z';
+ s2[size - 1] = 'x';
+ Ident(StrNCmp(s1 + size - 2, s2 + size - 2, size));
+ s2[size - 1] = 'z';
+ Ident(StrNCmp(s1 - 1, s2 - 1, 0));
+ Ident(StrNCmp(s1 + size - 1, s2 + size - 1, 1));
+ // One of arguments points to not allocated memory.
+ EXPECT_DEATH(Ident(StrNCmp)(s1 - 1, s2, 1), LeftOOBReadMessage(1));
+ EXPECT_DEATH(Ident(StrNCmp)(s1, s2 - 1, 1), LeftOOBReadMessage(1));
+ EXPECT_DEATH(Ident(StrNCmp)(s1 + size, s2, 1), RightOOBReadMessage(0));
+ EXPECT_DEATH(Ident(StrNCmp)(s1, s2 + size, 1), RightOOBReadMessage(0));
+ // Hit unallocated memory and die.
+ EXPECT_DEATH(Ident(StrNCmp)(s1 + 1, s2 + 1, size), RightOOBReadMessage(0));
+ EXPECT_DEATH(Ident(StrNCmp)(s1 + size - 1, s2, 2), RightOOBReadMessage(0));
+ free(s1);
+ free(s2);
+}
+
+TEST(AddressSanitizer, StrNCmpOOBTest) {
+ RunStrNCmpTest(&strncmp);
+}
+
+#if !defined(_WIN32) // no str[n]casecmp on Windows.
+TEST(AddressSanitizer, StrNCaseCmpOOBTest) {
+ RunStrNCmpTest(&strncasecmp);
+}
+#endif
+
+TEST(AddressSanitizer, StrCatOOBTest) {
+ // strcat() reads strlen(to) bytes from |to| before concatenating.
+ size_t to_size = Ident(100);
+ char *to = MallocAndMemsetString(to_size);
+ to[0] = '\0';
+ size_t from_size = Ident(20);
+ char *from = MallocAndMemsetString(from_size);
+ from[from_size - 1] = '\0';
+ // Normal strcat calls.
+ strcat(to, from);
+ strcat(to, from);
+ strcat(to + from_size, from + from_size - 2);
+ // Passing an invalid pointer is an error even when concatenating an empty
+ // string.
+ EXPECT_DEATH(strcat(to - 1, from + from_size - 1), LeftOOBAccessMessage(1));
+ // One of arguments points to not allocated memory.
+ EXPECT_DEATH(strcat(to - 1, from), LeftOOBAccessMessage(1));
+ EXPECT_DEATH(strcat(to, from - 1), LeftOOBReadMessage(1));
+ EXPECT_DEATH(strcat(to, from + from_size), RightOOBReadMessage(0));
+
+ // "from" is not zero-terminated.
+ from[from_size - 1] = 'z';
+ EXPECT_DEATH(strcat(to, from), RightOOBReadMessage(0));
+ from[from_size - 1] = '\0';
+ // "to" is too short to fit "from".
+ memset(to, 'z', to_size);
+ to[to_size - from_size + 1] = '\0';
+ EXPECT_DEATH(strcat(to, from), RightOOBWriteMessage(0));
+ // length of "to" is just enough.
+ strcat(to, from + 1);
+
+ free(to);
+ free(from);
+}
+
+TEST(AddressSanitizer, StrNCatOOBTest) {
+ // strncat() reads strlen(to) bytes from |to| before concatenating.
+ size_t to_size = Ident(100);
+ char *to = MallocAndMemsetString(to_size);
+ to[0] = '\0';
+ size_t from_size = Ident(20);
+ char *from = MallocAndMemsetString(from_size);
+ // Normal strncat calls.
+ strncat(to, from, 0);
+ strncat(to, from, from_size);
+ from[from_size - 1] = '\0';
+ strncat(to, from, 2 * from_size);
+ // Catenating empty string with an invalid string is still an error.
+ EXPECT_DEATH(strncat(to - 1, from, 0), LeftOOBAccessMessage(1));
+ strncat(to, from + from_size - 1, 10);
+ // One of arguments points to not allocated memory.
+ EXPECT_DEATH(strncat(to - 1, from, 2), LeftOOBAccessMessage(1));
+ EXPECT_DEATH(strncat(to, from - 1, 2), LeftOOBReadMessage(1));
+ EXPECT_DEATH(strncat(to, from + from_size, 2), RightOOBReadMessage(0));
+
+ memset(from, 'z', from_size);
+ memset(to, 'z', to_size);
+ to[0] = '\0';
+ // "from" is too short.
+ EXPECT_DEATH(strncat(to, from, from_size + 1), RightOOBReadMessage(0));
+ // "to" is too short to fit "from".
+ to[0] = 'z';
+ to[to_size - from_size + 1] = '\0';
+ EXPECT_DEATH(strncat(to, from, from_size - 1), RightOOBWriteMessage(0));
+ // "to" is just enough.
+ strncat(to, from, from_size - 2);
+
+ free(to);
+ free(from);
+}
+
+static string OverlapErrorMessage(const string &func) {
+ return func + "-param-overlap";
+}
+
+TEST(AddressSanitizer, StrArgsOverlapTest) {
+ size_t size = Ident(100);
+ char *str = Ident((char*)malloc(size));
+
+// Do not check memcpy() on OS X 10.7 and later, where it actually aliases
+// memmove().
+#if !defined(__APPLE__) || !defined(MAC_OS_X_VERSION_10_7) || \
+ (MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_7)
+ // Check "memcpy". Use Ident() to avoid inlining.
+#if PLATFORM_HAS_DIFFERENT_MEMCPY_AND_MEMMOVE
+ memset(str, 'z', size);
+ Ident(memcpy)(str + 1, str + 11, 10);
+ Ident(memcpy)(str, str, 0);
+ EXPECT_DEATH(Ident(memcpy)(str, str + 14, 15), OverlapErrorMessage("memcpy"));
+ EXPECT_DEATH(Ident(memcpy)(str + 14, str, 15), OverlapErrorMessage("memcpy"));
+#endif
+#endif
+
+ // We do not treat memcpy with to==from as a bug.
+ // See http://llvm.org/bugs/show_bug.cgi?id=11763.
+ // EXPECT_DEATH(Ident(memcpy)(str + 20, str + 20, 1),
+ // OverlapErrorMessage("memcpy"));
+
+ // Check "strcpy".
+ memset(str, 'z', size);
+ str[9] = '\0';
+ strcpy(str + 10, str);
+ EXPECT_DEATH(strcpy(str + 9, str), OverlapErrorMessage("strcpy"));
+ EXPECT_DEATH(strcpy(str, str + 4), OverlapErrorMessage("strcpy"));
+ strcpy(str, str + 5);
+
+ // Check "strncpy".
+ memset(str, 'z', size);
+ strncpy(str, str + 10, 10);
+ EXPECT_DEATH(strncpy(str, str + 9, 10), OverlapErrorMessage("strncpy"));
+ EXPECT_DEATH(strncpy(str + 9, str, 10), OverlapErrorMessage("strncpy"));
+ str[10] = '\0';
+ strncpy(str + 11, str, 20);
+ EXPECT_DEATH(strncpy(str + 10, str, 20), OverlapErrorMessage("strncpy"));
+
+ // Check "strcat".
+ memset(str, 'z', size);
+ str[10] = '\0';
+ str[20] = '\0';
+ strcat(str, str + 10);
+ EXPECT_DEATH(strcat(str, str + 11), OverlapErrorMessage("strcat"));
+ str[10] = '\0';
+ strcat(str + 11, str);
+ EXPECT_DEATH(strcat(str, str + 9), OverlapErrorMessage("strcat"));
+ EXPECT_DEATH(strcat(str + 9, str), OverlapErrorMessage("strcat"));
+ EXPECT_DEATH(strcat(str + 10, str), OverlapErrorMessage("strcat"));
+
+ // Check "strncat".
+ memset(str, 'z', size);
+ str[10] = '\0';
+ strncat(str, str + 10, 10); // from is empty
+ EXPECT_DEATH(strncat(str, str + 11, 10), OverlapErrorMessage("strncat"));
+ str[10] = '\0';
+ str[20] = '\0';
+ strncat(str + 5, str, 5);
+ str[10] = '\0';
+ EXPECT_DEATH(strncat(str + 5, str, 6), OverlapErrorMessage("strncat"));
+ EXPECT_DEATH(strncat(str, str + 9, 10), OverlapErrorMessage("strncat"));
+
+ free(str);
+}
+
+typedef void(*PointerToCallAtoi)(const char*);
+
+void RunAtoiOOBTest(PointerToCallAtoi Atoi) {
+ char *array = MallocAndMemsetString(10, '1');
+ // Invalid pointer to the string.
+ EXPECT_DEATH(Atoi(array + 11), RightOOBReadMessage(1));
+ EXPECT_DEATH(Atoi(array - 1), LeftOOBReadMessage(1));
+ // Die if a buffer doesn't have terminating NULL.
+ EXPECT_DEATH(Atoi(array), RightOOBReadMessage(0));
+ // Make last symbol a terminating NULL
+ array[9] = '\0';
+ Atoi(array);
+ // Sometimes we need to detect overflow if no digits are found.
+ memset(array, ' ', 10);
+ EXPECT_DEATH(Atoi(array), RightOOBReadMessage(0));
+ array[9] = '-';
+ EXPECT_DEATH(Atoi(array), RightOOBReadMessage(0));
+ EXPECT_DEATH(Atoi(array + 9), RightOOBReadMessage(0));
+ free(array);
+}
+
+#if !defined(_WIN32) // FIXME: Fix and enable on Windows.
+void CallAtoi(const char *nptr) {
+ Ident(atoi(nptr));
+}
+void CallAtol(const char *nptr) {
+ Ident(atol(nptr));
+}
+void CallAtoll(const char *nptr) {
+ Ident(atoll(nptr));
+}
+TEST(AddressSanitizer, AtoiAndFriendsOOBTest) {
+ RunAtoiOOBTest(&CallAtoi);
+ RunAtoiOOBTest(&CallAtol);
+ RunAtoiOOBTest(&CallAtoll);
+}
+#endif
+
+typedef void(*PointerToCallStrtol)(const char*, char**, int);
+
+void RunStrtolOOBTest(PointerToCallStrtol Strtol) {
+ char *array = MallocAndMemsetString(3);
+ array[0] = '1';
+ array[1] = '2';
+ array[2] = '3';
+ // Invalid pointer to the string.
+ EXPECT_DEATH(Strtol(array + 3, NULL, 0), RightOOBReadMessage(0));
+ EXPECT_DEATH(Strtol(array - 1, NULL, 0), LeftOOBReadMessage(1));
+ // Buffer overflow if there is no terminating null (depends on base).
+ EXPECT_DEATH(Strtol(array, NULL, 0), RightOOBReadMessage(0));
+ array[2] = 'z';
+ EXPECT_DEATH(Strtol(array, NULL, 36), RightOOBReadMessage(0));
+ // Add terminating zero to get rid of overflow.
+ array[2] = '\0';
+ Strtol(array, NULL, 36);
+ // Sometimes we need to detect overflow if no digits are found.
+ array[0] = array[1] = array[2] = ' ';
+ EXPECT_DEATH(Strtol(array, NULL, 0), RightOOBReadMessage(0));
+ array[2] = '+';
+ EXPECT_DEATH(Strtol(array, NULL, 0), RightOOBReadMessage(0));
+ array[2] = '-';
+ EXPECT_DEATH(Strtol(array, NULL, 0), RightOOBReadMessage(0));
+ free(array);
+}
+
+#if !defined(_WIN32) // FIXME: Fix and enable on Windows.
+void CallStrtol(const char *nptr, char **endptr, int base) {
+ Ident(strtol(nptr, endptr, base));
+}
+void CallStrtoll(const char *nptr, char **endptr, int base) {
+ Ident(strtoll(nptr, endptr, base));
+}
+TEST(AddressSanitizer, StrtollOOBTest) {
+ RunStrtolOOBTest(&CallStrtoll);
+}
+TEST(AddressSanitizer, StrtolOOBTest) {
+ RunStrtolOOBTest(&CallStrtol);
+}
+#endif
+++ /dev/null
-//===-- asan_test.cc ------------------------------------------------------===//
-//
-// 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
-//
-//===----------------------------------------------------------------------===//
-//
-// This file is a part of AddressSanitizer, an address sanity checker.
-//
-//===----------------------------------------------------------------------===//
-#include "asan_test_utils.h"
-
-#include <errno.h>
-#include <stdarg.h>
-
-#ifdef _LIBCPP_GET_C_LOCALE
-#define SANITIZER_GET_C_LOCALE _LIBCPP_GET_C_LOCALE
-#else
-#if defined(__FreeBSD__)
-#define SANITIZER_GET_C_LOCALE 0
-#elif defined(__NetBSD__)
-#define SANITIZER_GET_C_LOCALE LC_C_LOCALE
-#endif
-#endif
-
-#if defined(__sun__) && defined(__svr4__)
-using std::_setjmp;
-using std::_longjmp;
-#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 uaf_test(int size, int off) {
- void *p = malloc_aaa(size);
- free_aaa(p);
- for (int i = 1; i < 100; i++)
- free_aaa(malloc_aaa(i));
- fprintf(stderr, "writing %ld byte(s) at %p with offset %d\n",
- (long)sizeof(T), p, off);
- asan_write((T *)((char *)p + off));
-}
-
-TEST(AddressSanitizer, HasFeatureAddressSanitizerTest) {
-#if defined(__has_feature) && __has_feature(address_sanitizer)
- bool asan = 1;
-#elif defined(__SANITIZE_ADDRESS__)
- bool asan = 1;
-#else
- bool asan = 0;
-#endif
- EXPECT_EQ(true, asan);
-}
-
-TEST(AddressSanitizer, SimpleDeathTest) {
- EXPECT_DEATH(exit(1), "");
-}
-
-TEST(AddressSanitizer, VariousMallocsTest) {
- int *a = (int*)malloc(100 * sizeof(int));
- a[50] = 0;
- free(a);
-
- int *r = (int*)malloc(10);
- r = (int*)realloc(r, 2000 * sizeof(int));
- r[1000] = 0;
- free(r);
-
- int *b = new int[100];
- b[50] = 0;
- delete [] b;
-
- int *c = new int;
- *c = 0;
- delete c;
-
-#if SANITIZER_TEST_HAS_POSIX_MEMALIGN
- void *pm = 0;
- // Valid allocation.
- int pm_res = posix_memalign(&pm, kPageSize, kPageSize);
- EXPECT_EQ(0, pm_res);
- EXPECT_NE(nullptr, pm);
- free(pm);
-#endif // SANITIZER_TEST_HAS_POSIX_MEMALIGN
-
-#if SANITIZER_TEST_HAS_MEMALIGN
- int *ma = (int*)memalign(kPageSize, kPageSize);
- EXPECT_EQ(0U, (uintptr_t)ma % kPageSize);
- ma[123] = 0;
- free(ma);
-#endif // SANITIZER_TEST_HAS_MEMALIGN
-}
-
-TEST(AddressSanitizer, CallocTest) {
- int *a = (int*)calloc(100, sizeof(int));
- EXPECT_EQ(0, a[10]);
- free(a);
-}
-
-TEST(AddressSanitizer, CallocReturnsZeroMem) {
- size_t sizes[] = {16, 1000, 10000, 100000, 2100000};
- for (size_t s = 0; s < sizeof(sizes)/sizeof(sizes[0]); s++) {
- size_t size = sizes[s];
- for (size_t iter = 0; iter < 5; iter++) {
- char *x = Ident((char*)calloc(1, size));
- EXPECT_EQ(x[0], 0);
- EXPECT_EQ(x[size - 1], 0);
- EXPECT_EQ(x[size / 2], 0);
- EXPECT_EQ(x[size / 3], 0);
- EXPECT_EQ(x[size / 4], 0);
- memset(x, 0x42, size);
- free(Ident(x));
-#if !defined(_WIN32)
- // FIXME: OOM on Windows. We should just make this a lit test
- // with quarantine size set to 1.
- free(Ident(malloc(Ident(1 << 27)))); // Try to drain the quarantine.
-#endif
- }
- }
-}
-
-// No valloc on Windows or Android.
-#if !defined(_WIN32) && !defined(__ANDROID__)
-TEST(AddressSanitizer, VallocTest) {
- void *a = valloc(100);
- EXPECT_EQ(0U, (uintptr_t)a % kPageSize);
- free(a);
-}
-#endif
-
-#if SANITIZER_TEST_HAS_PVALLOC
-TEST(AddressSanitizer, PvallocTest) {
- char *a = (char*)pvalloc(kPageSize + 100);
- EXPECT_EQ(0U, (uintptr_t)a % kPageSize);
- a[kPageSize + 101] = 1; // we should not report an error here.
- free(a);
-
- a = (char*)pvalloc(0); // pvalloc(0) should allocate at least one page.
- EXPECT_EQ(0U, (uintptr_t)a % kPageSize);
- a[101] = 1; // we should not report an error here.
- free(a);
-}
-#endif // SANITIZER_TEST_HAS_PVALLOC
-
-#if !defined(_WIN32)
-// FIXME: Use an equivalent of pthread_setspecific on Windows.
-void *TSDWorker(void *test_key) {
- if (test_key) {
- pthread_setspecific(*(pthread_key_t*)test_key, (void*)0xfeedface);
- }
- return NULL;
-}
-
-void TSDDestructor(void *tsd) {
- // Spawning a thread will check that the current thread id is not -1.
- pthread_t th;
- PTHREAD_CREATE(&th, NULL, TSDWorker, NULL);
- PTHREAD_JOIN(th, NULL);
-}
-
-// This tests triggers the thread-specific data destruction fiasco which occurs
-// if we don't manage the TSD destructors ourselves. We create a new pthread
-// key with a non-NULL destructor which is likely to be put after the destructor
-// of AsanThread in the list of destructors.
-// In this case the TSD for AsanThread will be destroyed before TSDDestructor
-// is called for the child thread, and a CHECK will fail when we call
-// pthread_create() to spawn the grandchild.
-TEST(AddressSanitizer, DISABLED_TSDTest) {
- pthread_t th;
- pthread_key_t test_key;
- pthread_key_create(&test_key, TSDDestructor);
- PTHREAD_CREATE(&th, NULL, TSDWorker, &test_key);
- PTHREAD_JOIN(th, NULL);
- pthread_key_delete(test_key);
-}
-#endif
-
-TEST(AddressSanitizer, UAF_char) {
- const char *uaf_string = "AddressSanitizer:.*heap-use-after-free";
- EXPECT_DEATH(uaf_test<U1>(1, 0), uaf_string);
- EXPECT_DEATH(uaf_test<U1>(10, 0), uaf_string);
- EXPECT_DEATH(uaf_test<U1>(10, 10), uaf_string);
- EXPECT_DEATH(uaf_test<U1>(kLargeMalloc, 0), uaf_string);
- EXPECT_DEATH(uaf_test<U1>(kLargeMalloc, kLargeMalloc / 2), uaf_string);
-}
-
-TEST(AddressSanitizer, UAF_long_double) {
- if (sizeof(long double) == sizeof(double)) return;
- long double *p = Ident(new long double[10]);
- EXPECT_DEATH(Ident(p)[12] = 0, "WRITE of size 1[026]");
- EXPECT_DEATH(Ident(p)[0] = Ident(p)[12], "READ of size 1[026]");
- delete [] Ident(p);
-}
-
-#if !defined(_WIN32)
-struct Packed5 {
- int x;
- char c;
-} __attribute__((packed));
-#else
-# pragma pack(push, 1)
-struct Packed5 {
- int x;
- char c;
-};
-# pragma pack(pop)
-#endif
-
-TEST(AddressSanitizer, UAF_Packed5) {
- static_assert(sizeof(Packed5) == 5, "Please check the keywords used");
- Packed5 *p = Ident(new Packed5[2]);
- EXPECT_DEATH(p[0] = p[3], "READ of size 5");
- EXPECT_DEATH(p[3] = p[0], "WRITE of size 5");
- delete [] Ident(p);
-}
-
-#if ASAN_HAS_BLACKLIST
-TEST(AddressSanitizer, IgnoreTest) {
- int *x = Ident(new int);
- delete Ident(x);
- *x = 0;
-}
-#endif // ASAN_HAS_BLACKLIST
-
-struct StructWithBitField {
- int bf1:1;
- int bf2:1;
- int bf3:1;
- int bf4:29;
-};
-
-TEST(AddressSanitizer, BitFieldPositiveTest) {
- StructWithBitField *x = new StructWithBitField;
- delete Ident(x);
- EXPECT_DEATH(x->bf1 = 0, "use-after-free");
- EXPECT_DEATH(x->bf2 = 0, "use-after-free");
- EXPECT_DEATH(x->bf3 = 0, "use-after-free");
- EXPECT_DEATH(x->bf4 = 0, "use-after-free");
-}
-
-struct StructWithBitFields_8_24 {
- int a:8;
- int b:24;
-};
-
-TEST(AddressSanitizer, BitFieldNegativeTest) {
- StructWithBitFields_8_24 *x = Ident(new StructWithBitFields_8_24);
- x->a = 0;
- x->b = 0;
- delete Ident(x);
-}
-
-#if ASAN_NEEDS_SEGV
-namespace {
-
-const char kSEGVCrash[] = "AddressSanitizer: SEGV on unknown address";
-const char kOverriddenSigactionHandler[] = "Test sigaction handler\n";
-const char kOverriddenSignalHandler[] = "Test signal handler\n";
-
-TEST(AddressSanitizer, WildAddressTest) {
- char *c = (char*)0x123;
- EXPECT_DEATH(*c = 0, kSEGVCrash);
-}
-
-void my_sigaction_sighandler(int, siginfo_t*, void*) {
- fprintf(stderr, kOverriddenSigactionHandler);
- exit(1);
-}
-
-void my_signal_sighandler(int signum) {
- fprintf(stderr, kOverriddenSignalHandler);
- exit(1);
-}
-
-TEST(AddressSanitizer, SignalTest) {
- struct sigaction sigact;
- memset(&sigact, 0, sizeof(sigact));
- sigact.sa_sigaction = my_sigaction_sighandler;
- sigact.sa_flags = SA_SIGINFO;
- char *c = (char *)0x123;
-
- EXPECT_DEATH(*c = 0, kSEGVCrash);
-
- // ASan should allow to set sigaction()...
- EXPECT_EQ(0, sigaction(SIGSEGV, &sigact, 0));
-#ifdef __APPLE__
- EXPECT_EQ(0, sigaction(SIGBUS, &sigact, 0));
-#endif
- EXPECT_DEATH(*c = 0, kOverriddenSigactionHandler);
-
- // ... and signal().
- EXPECT_NE(SIG_ERR, signal(SIGSEGV, my_signal_sighandler));
- EXPECT_DEATH(*c = 0, kOverriddenSignalHandler);
-}
-} // namespace
-#endif
-
-static void TestLargeMalloc(size_t size) {
- char buff[1024];
- sprintf(buff, "is located 1 bytes to the left of %lu-byte", (long)size);
- EXPECT_DEATH(Ident((char*)malloc(size))[-1] = 0, buff);
-}
-
-TEST(AddressSanitizer, LargeMallocTest) {
- const int max_size = (SANITIZER_WORDSIZE == 32) ? 1 << 26 : 1 << 28;
- for (int i = 113; i < max_size; i = i * 2 + 13) {
- TestLargeMalloc(i);
- }
-}
-
-#if !GTEST_USES_SIMPLE_RE
-TEST(AddressSanitizer, HugeMallocTest) {
- if (SANITIZER_WORDSIZE != 64 || ASAN_AVOID_EXPENSIVE_TESTS) return;
- size_t n_megs = 4100;
- EXPECT_DEATH(Ident((char*)malloc(n_megs << 20))[-1] = 0,
- "is located 1 bytes to the left|"
- "AddressSanitizer failed to allocate");
-}
-#endif
-
-#if SANITIZER_TEST_HAS_MEMALIGN
-void MemalignRun(size_t align, size_t size, int idx) {
- char *p = (char *)memalign(align, size);
- Ident(p)[idx] = 0;
- free(p);
-}
-
-TEST(AddressSanitizer, memalign) {
- for (int align = 16; align <= (1 << 23); align *= 2) {
- size_t size = align * 5;
- EXPECT_DEATH(MemalignRun(align, size, -1),
- "is located 1 bytes to the left");
- EXPECT_DEATH(MemalignRun(align, size, size + 1),
- "is located 1 bytes to the right");
- }
-}
-#endif // SANITIZER_TEST_HAS_MEMALIGN
-
-void *ManyThreadsWorker(void *a) {
- for (int iter = 0; iter < 100; iter++) {
- for (size_t size = 100; size < 2000; size *= 2) {
- free(Ident(malloc(size)));
- }
- }
- return 0;
-}
-
-#if !defined(__aarch64__) && !defined(__powerpc64__)
-// FIXME: Infinite loop in AArch64 (PR24389).
-// FIXME: Also occasional hang on powerpc. Maybe same problem as on AArch64?
-TEST(AddressSanitizer, ManyThreadsTest) {
- const size_t kNumThreads =
- (SANITIZER_WORDSIZE == 32 || ASAN_AVOID_EXPENSIVE_TESTS) ? 30 : 1000;
- pthread_t t[kNumThreads];
- for (size_t i = 0; i < kNumThreads; i++) {
- PTHREAD_CREATE(&t[i], 0, ManyThreadsWorker, (void*)i);
- }
- for (size_t i = 0; i < kNumThreads; i++) {
- PTHREAD_JOIN(t[i], 0);
- }
-}
-#endif
-
-TEST(AddressSanitizer, ReallocTest) {
- const int kMinElem = 5;
- int *ptr = (int*)malloc(sizeof(int) * kMinElem);
- ptr[3] = 3;
- for (int i = 0; i < 10000; i++) {
- ptr = (int*)realloc(ptr,
- (my_rand() % 1000 + kMinElem) * sizeof(int));
- EXPECT_EQ(3, ptr[3]);
- }
- free(ptr);
- // Realloc pointer returned by malloc(0).
- int *ptr2 = Ident((int*)malloc(0));
- ptr2 = Ident((int*)realloc(ptr2, sizeof(*ptr2)));
- *ptr2 = 42;
- EXPECT_EQ(42, *ptr2);
- free(ptr2);
-}
-
-TEST(AddressSanitizer, ReallocFreedPointerTest) {
- void *ptr = Ident(malloc(42));
- ASSERT_TRUE(NULL != ptr);
- free(ptr);
- EXPECT_DEATH(ptr = realloc(ptr, 77), "attempting double-free");
-}
-
-TEST(AddressSanitizer, ReallocInvalidPointerTest) {
- void *ptr = Ident(malloc(42));
- EXPECT_DEATH(ptr = realloc((int*)ptr + 1, 77), "attempting free.*not malloc");
- free(ptr);
-}
-
-TEST(AddressSanitizer, ZeroSizeMallocTest) {
- // Test that malloc(0) and similar functions don't return NULL.
- void *ptr = Ident(malloc(0));
- EXPECT_TRUE(NULL != ptr);
- free(ptr);
-#if SANITIZER_TEST_HAS_POSIX_MEMALIGN
- int pm_res = posix_memalign(&ptr, 1<<20, 0);
- EXPECT_EQ(0, pm_res);
- EXPECT_TRUE(NULL != ptr);
- free(ptr);
-#endif // SANITIZER_TEST_HAS_POSIX_MEMALIGN
- int *int_ptr = new int[0];
- int *int_ptr2 = new int[0];
- EXPECT_TRUE(NULL != int_ptr);
- EXPECT_TRUE(NULL != int_ptr2);
- EXPECT_NE(int_ptr, int_ptr2);
- delete[] int_ptr;
- delete[] int_ptr2;
-}
-
-#if SANITIZER_TEST_HAS_MALLOC_USABLE_SIZE
-static const char *kMallocUsableSizeErrorMsg =
- "AddressSanitizer: attempting to call malloc_usable_size()";
-
-TEST(AddressSanitizer, MallocUsableSizeTest) {
- const size_t kArraySize = 100;
- char *array = Ident((char*)malloc(kArraySize));
- int *int_ptr = Ident(new int);
- EXPECT_EQ(0U, malloc_usable_size(NULL));
- EXPECT_EQ(kArraySize, malloc_usable_size(array));
- EXPECT_EQ(sizeof(int), malloc_usable_size(int_ptr));
- EXPECT_DEATH(malloc_usable_size((void*)0x123), kMallocUsableSizeErrorMsg);
- EXPECT_DEATH(malloc_usable_size(array + kArraySize / 2),
- kMallocUsableSizeErrorMsg);
- free(array);
- EXPECT_DEATH(malloc_usable_size(array), kMallocUsableSizeErrorMsg);
- delete int_ptr;
-}
-#endif // SANITIZER_TEST_HAS_MALLOC_USABLE_SIZE
-
-void WrongFree() {
- int *x = (int*)malloc(100 * sizeof(int));
- // Use the allocated memory, otherwise Clang will optimize it out.
- Ident(x);
- free(x + 1);
-}
-
-#if !defined(_WIN32) // FIXME: This should be a lit test.
-TEST(AddressSanitizer, WrongFreeTest) {
- EXPECT_DEATH(WrongFree(), ASAN_PCRE_DOTALL
- "ERROR: AddressSanitizer: attempting free.*not malloc"
- ".*is located 4 bytes inside of 400-byte region"
- ".*allocated by thread");
-}
-#endif
-
-void DoubleFree() {
- int *x = (int*)malloc(100 * sizeof(int));
- fprintf(stderr, "DoubleFree: x=%p\n", (void *)x);
- free(x);
- free(x);
- fprintf(stderr, "should have failed in the second free(%p)\n", (void *)x);
- abort();
-}
-
-#if !defined(_WIN32) // FIXME: This should be a lit test.
-TEST(AddressSanitizer, DoubleFreeTest) {
- EXPECT_DEATH(DoubleFree(), ASAN_PCRE_DOTALL
- "ERROR: AddressSanitizer: attempting double-free"
- ".*is located 0 bytes inside of 400-byte region"
- ".*freed by thread T0 here"
- ".*previously allocated by thread T0 here");
-}
-#endif
-
-template<int kSize>
-NOINLINE void SizedStackTest() {
- char a[kSize];
- char *A = Ident((char*)&a);
- const char *expected_death = "AddressSanitizer: stack-buffer-";
- for (size_t i = 0; i < kSize; i++)
- A[i] = i;
- EXPECT_DEATH(A[-1] = 0, expected_death);
- EXPECT_DEATH(A[-5] = 0, expected_death);
- EXPECT_DEATH(A[kSize] = 0, expected_death);
- EXPECT_DEATH(A[kSize + 1] = 0, expected_death);
- EXPECT_DEATH(A[kSize + 5] = 0, expected_death);
- if (kSize > 16)
- EXPECT_DEATH(A[kSize + 31] = 0, expected_death);
-}
-
-TEST(AddressSanitizer, SimpleStackTest) {
- SizedStackTest<1>();
- SizedStackTest<2>();
- SizedStackTest<3>();
- SizedStackTest<4>();
- SizedStackTest<5>();
- SizedStackTest<6>();
- SizedStackTest<7>();
- SizedStackTest<16>();
- SizedStackTest<25>();
- SizedStackTest<34>();
- SizedStackTest<43>();
- SizedStackTest<51>();
- SizedStackTest<62>();
- SizedStackTest<64>();
- SizedStackTest<128>();
-}
-
-#if !defined(_WIN32)
-// FIXME: It's a bit hard to write multi-line death test expectations
-// in a portable way. Anyways, this should just be turned into a lit test.
-TEST(AddressSanitizer, ManyStackObjectsTest) {
- char XXX[10];
- char YYY[20];
- char ZZZ[30];
- Ident(XXX);
- Ident(YYY);
- EXPECT_DEATH(Ident(ZZZ)[-1] = 0, ASAN_PCRE_DOTALL "XXX.*YYY.*ZZZ");
-}
-#endif
-
-#if 0 // This test requires online symbolizer.
-// Moved to lit_tests/stack-oob-frames.cc.
-// Reenable here once we have online symbolizer by default.
-NOINLINE static void Frame0(int frame, char *a, char *b, char *c) {
- char d[4] = {0};
- char *D = Ident(d);
- switch (frame) {
- case 3: a[5]++; break;
- case 2: b[5]++; break;
- case 1: c[5]++; break;
- case 0: D[5]++; break;
- }
-}
-NOINLINE static void Frame1(int frame, char *a, char *b) {
- char c[4] = {0}; Frame0(frame, a, b, c);
- break_optimization(0);
-}
-NOINLINE static void Frame2(int frame, char *a) {
- char b[4] = {0}; Frame1(frame, a, b);
- break_optimization(0);
-}
-NOINLINE static void Frame3(int frame) {
- char a[4] = {0}; Frame2(frame, a);
- break_optimization(0);
-}
-
-TEST(AddressSanitizer, GuiltyStackFrame0Test) {
- EXPECT_DEATH(Frame3(0), "located .*in frame <.*Frame0");
-}
-TEST(AddressSanitizer, GuiltyStackFrame1Test) {
- EXPECT_DEATH(Frame3(1), "located .*in frame <.*Frame1");
-}
-TEST(AddressSanitizer, GuiltyStackFrame2Test) {
- EXPECT_DEATH(Frame3(2), "located .*in frame <.*Frame2");
-}
-TEST(AddressSanitizer, GuiltyStackFrame3Test) {
- EXPECT_DEATH(Frame3(3), "located .*in frame <.*Frame3");
-}
-#endif
-
-NOINLINE void LongJmpFunc1(jmp_buf buf) {
- // create three red zones for these two stack objects.
- int a;
- int b;
-
- int *A = Ident(&a);
- int *B = Ident(&b);
- *A = *B;
- longjmp(buf, 1);
-}
-
-NOINLINE void TouchStackFunc() {
- int a[100]; // long array will intersect with redzones from LongJmpFunc1.
- int *A = Ident(a);
- for (int i = 0; i < 100; i++)
- A[i] = i*i;
-}
-
-// Test that we handle longjmp and do not report false positives on stack.
-TEST(AddressSanitizer, LongJmpTest) {
- static jmp_buf buf;
- if (!setjmp(buf)) {
- LongJmpFunc1(buf);
- } else {
- TouchStackFunc();
- }
-}
-
-#if !defined(_WIN32) // Only basic longjmp is available on Windows.
-NOINLINE void UnderscopeLongJmpFunc1(jmp_buf buf) {
- // create three red zones for these two stack objects.
- int a;
- int b;
-
- int *A = Ident(&a);
- int *B = Ident(&b);
- *A = *B;
- _longjmp(buf, 1);
-}
-
-NOINLINE void SigLongJmpFunc1(sigjmp_buf buf) {
- // create three red zones for these two stack objects.
- int a;
- int b;
-
- int *A = Ident(&a);
- int *B = Ident(&b);
- *A = *B;
- siglongjmp(buf, 1);
-}
-
-#if !defined(__ANDROID__) && !defined(__arm__) && \
- !defined(__aarch64__) && !defined(__mips__) && \
- !defined(__mips64) && !defined(__s390__)
-NOINLINE void BuiltinLongJmpFunc1(jmp_buf buf) {
- // create three red zones for these two stack objects.
- int a;
- int b;
-
- int *A = Ident(&a);
- int *B = Ident(&b);
- *A = *B;
- __builtin_longjmp((void**)buf, 1);
-}
-
-// Does not work on ARM:
-// https://github.com/google/sanitizers/issues/185
-TEST(AddressSanitizer, BuiltinLongJmpTest) {
- static jmp_buf buf;
- if (!__builtin_setjmp((void**)buf)) {
- BuiltinLongJmpFunc1(buf);
- } else {
- TouchStackFunc();
- }
-}
-#endif // !defined(__ANDROID__) && !defined(__arm__) &&
- // !defined(__aarch64__) && !defined(__mips__)
- // !defined(__mips64) && !defined(__s390__)
-
-TEST(AddressSanitizer, UnderscopeLongJmpTest) {
- static jmp_buf buf;
- if (!_setjmp(buf)) {
- UnderscopeLongJmpFunc1(buf);
- } else {
- TouchStackFunc();
- }
-}
-
-TEST(AddressSanitizer, SigLongJmpTest) {
- static sigjmp_buf buf;
- if (!sigsetjmp(buf, 1)) {
- SigLongJmpFunc1(buf);
- } else {
- TouchStackFunc();
- }
-}
-#endif
-
-// FIXME: Why does clang-cl define __EXCEPTIONS?
-#if defined(__EXCEPTIONS) && !defined(_WIN32)
-NOINLINE void ThrowFunc() {
- // create three red zones for these two stack objects.
- int a;
- int b;
-
- int *A = Ident(&a);
- int *B = Ident(&b);
- *A = *B;
- ASAN_THROW(1);
-}
-
-TEST(AddressSanitizer, CxxExceptionTest) {
- if (ASAN_UAR) return;
- // TODO(kcc): this test crashes on 32-bit for some reason...
- if (SANITIZER_WORDSIZE == 32) return;
- try {
- ThrowFunc();
- } catch(...) {}
- TouchStackFunc();
-}
-#endif
-
-void *ThreadStackReuseFunc1(void *unused) {
- // create three red zones for these two stack objects.
- int a;
- int b;
-
- int *A = Ident(&a);
- int *B = Ident(&b);
- *A = *B;
- pthread_exit(0);
- return 0;
-}
-
-void *ThreadStackReuseFunc2(void *unused) {
- TouchStackFunc();
- return 0;
-}
-
-#if !defined(__thumb__)
-TEST(AddressSanitizer, ThreadStackReuseTest) {
- pthread_t t;
- PTHREAD_CREATE(&t, 0, ThreadStackReuseFunc1, 0);
- PTHREAD_JOIN(t, 0);
- PTHREAD_CREATE(&t, 0, ThreadStackReuseFunc2, 0);
- PTHREAD_JOIN(t, 0);
-}
-#endif
-
-#if defined(__SSE2__)
-#include <emmintrin.h>
-TEST(AddressSanitizer, Store128Test) {
- char *a = Ident((char*)malloc(Ident(12)));
- char *p = a;
- if (((uintptr_t)a % 16) != 0)
- p = a + 8;
- assert(((uintptr_t)p % 16) == 0);
- __m128i value_wide = _mm_set1_epi16(0x1234);
- EXPECT_DEATH(_mm_store_si128((__m128i*)p, value_wide),
- "AddressSanitizer: heap-buffer-overflow");
- EXPECT_DEATH(_mm_store_si128((__m128i*)p, value_wide),
- "WRITE of size 16");
- EXPECT_DEATH(_mm_store_si128((__m128i*)p, value_wide),
- "located 0 bytes to the right of 12-byte");
- free(a);
-}
-#endif
-
-// FIXME: All tests that use this function should be turned into lit tests.
-string RightOOBErrorMessage(int oob_distance, bool is_write) {
- assert(oob_distance >= 0);
- char expected_str[100];
- sprintf(expected_str, ASAN_PCRE_DOTALL
-#if !GTEST_USES_SIMPLE_RE
- "buffer-overflow.*%s.*"
-#endif
- "located %d bytes to the right",
-#if !GTEST_USES_SIMPLE_RE
- is_write ? "WRITE" : "READ",
-#endif
- oob_distance);
- return string(expected_str);
-}
-
-string RightOOBWriteMessage(int oob_distance) {
- return RightOOBErrorMessage(oob_distance, /*is_write*/true);
-}
-
-string RightOOBReadMessage(int oob_distance) {
- return RightOOBErrorMessage(oob_distance, /*is_write*/false);
-}
-
-// FIXME: All tests that use this function should be turned into lit tests.
-string LeftOOBErrorMessage(int oob_distance, bool is_write) {
- assert(oob_distance > 0);
- char expected_str[100];
- sprintf(expected_str,
-#if !GTEST_USES_SIMPLE_RE
- ASAN_PCRE_DOTALL "%s.*"
-#endif
- "located %d bytes to the left",
-#if !GTEST_USES_SIMPLE_RE
- is_write ? "WRITE" : "READ",
-#endif
- oob_distance);
- return string(expected_str);
-}
-
-string LeftOOBWriteMessage(int oob_distance) {
- return LeftOOBErrorMessage(oob_distance, /*is_write*/true);
-}
-
-string LeftOOBReadMessage(int oob_distance) {
- return LeftOOBErrorMessage(oob_distance, /*is_write*/false);
-}
-
-string LeftOOBAccessMessage(int oob_distance) {
- assert(oob_distance > 0);
- char expected_str[100];
- sprintf(expected_str, "located %d bytes to the left", oob_distance);
- return string(expected_str);
-}
-
-char* MallocAndMemsetString(size_t size, char ch) {
- char *s = Ident((char*)malloc(size));
- memset(s, ch, size);
- return s;
-}
-
-char* MallocAndMemsetString(size_t size) {
- return MallocAndMemsetString(size, 'z');
-}
-
-#if defined(__linux__) && !defined(__ANDROID__)
-#define READ_TEST(READ_N_BYTES) \
- char *x = new char[10]; \
- int fd = open("/proc/self/stat", O_RDONLY); \
- ASSERT_GT(fd, 0); \
- EXPECT_DEATH(READ_N_BYTES, \
- ASAN_PCRE_DOTALL \
- "AddressSanitizer: heap-buffer-overflow" \
- ".* is located 0 bytes to the right of 10-byte region"); \
- close(fd); \
- delete [] x; \
-
-TEST(AddressSanitizer, pread) {
- READ_TEST(pread(fd, x, 15, 0));
-}
-
-TEST(AddressSanitizer, pread64) {
- READ_TEST(pread64(fd, x, 15, 0));
-}
-
-TEST(AddressSanitizer, read) {
- READ_TEST(read(fd, x, 15));
-}
-#endif // defined(__linux__) && !defined(__ANDROID__)
-
-// This test case fails
-// Clang optimizes memcpy/memset calls which lead to unaligned access
-TEST(AddressSanitizer, DISABLED_MemIntrinsicUnalignedAccessTest) {
- int size = Ident(4096);
- char *s = Ident((char*)malloc(size));
- EXPECT_DEATH(memset(s + size - 1, 0, 2), RightOOBWriteMessage(0));
- free(s);
-}
-
-NOINLINE static int LargeFunction(bool do_bad_access) {
- int *x = new int[100];
- x[0]++;
- x[1]++;
- x[2]++;
- x[3]++;
- x[4]++;
- x[5]++;
- x[6]++;
- x[7]++;
- x[8]++;
- x[9]++;
-
- x[do_bad_access ? 100 : 0]++; int res = __LINE__;
-
- x[10]++;
- x[11]++;
- x[12]++;
- x[13]++;
- x[14]++;
- x[15]++;
- x[16]++;
- x[17]++;
- x[18]++;
- x[19]++;
-
- delete[] x;
- return res;
-}
-
-// Test the we have correct debug info for the failing instruction.
-// This test requires the in-process symbolizer to be enabled by default.
-TEST(AddressSanitizer, DISABLED_LargeFunctionSymbolizeTest) {
- int failing_line = LargeFunction(false);
- char expected_warning[128];
- sprintf(expected_warning, "LargeFunction.*asan_test.*:%d", failing_line);
- EXPECT_DEATH(LargeFunction(true), expected_warning);
-}
-
-// Check that we unwind and symbolize correctly.
-TEST(AddressSanitizer, DISABLED_MallocFreeUnwindAndSymbolizeTest) {
- int *a = (int*)malloc_aaa(sizeof(int));
- *a = 1;
- free_aaa(a);
- EXPECT_DEATH(*a = 1, "free_ccc.*free_bbb.*free_aaa.*"
- "malloc_fff.*malloc_eee.*malloc_ddd");
-}
-
-static bool TryToSetThreadName(const char *name) {
-#if defined(__linux__) && defined(PR_SET_NAME)
- return 0 == prctl(PR_SET_NAME, (unsigned long)name, 0, 0, 0);
-#else
- return false;
-#endif
-}
-
-void *ThreadedTestAlloc(void *a) {
- EXPECT_EQ(true, TryToSetThreadName("AllocThr"));
- int **p = (int**)a;
- *p = new int;
- return 0;
-}
-
-void *ThreadedTestFree(void *a) {
- EXPECT_EQ(true, TryToSetThreadName("FreeThr"));
- int **p = (int**)a;
- delete *p;
- return 0;
-}
-
-void *ThreadedTestUse(void *a) {
- EXPECT_EQ(true, TryToSetThreadName("UseThr"));
- int **p = (int**)a;
- **p = 1;
- return 0;
-}
-
-void ThreadedTestSpawn() {
- pthread_t t;
- int *x;
- PTHREAD_CREATE(&t, 0, ThreadedTestAlloc, &x);
- PTHREAD_JOIN(t, 0);
- PTHREAD_CREATE(&t, 0, ThreadedTestFree, &x);
- PTHREAD_JOIN(t, 0);
- PTHREAD_CREATE(&t, 0, ThreadedTestUse, &x);
- PTHREAD_JOIN(t, 0);
-}
-
-#if !defined(_WIN32) // FIXME: This should be a lit test.
-TEST(AddressSanitizer, ThreadedTest) {
- EXPECT_DEATH(ThreadedTestSpawn(),
- ASAN_PCRE_DOTALL
- "Thread T.*created"
- ".*Thread T.*created"
- ".*Thread T.*created");
-}
-#endif
-
-void *ThreadedTestFunc(void *unused) {
- // Check if prctl(PR_SET_NAME) is supported. Return if not.
- if (!TryToSetThreadName("TestFunc"))
- return 0;
- EXPECT_DEATH(ThreadedTestSpawn(),
- ASAN_PCRE_DOTALL
- "WRITE .*thread T. .UseThr."
- ".*freed by thread T. .FreeThr. here:"
- ".*previously allocated by thread T. .AllocThr. here:"
- ".*Thread T. .UseThr. created by T.*TestFunc"
- ".*Thread T. .FreeThr. created by T"
- ".*Thread T. .AllocThr. created by T"
- "");
- return 0;
-}
-
-TEST(AddressSanitizer, ThreadNamesTest) {
- // Run ThreadedTestFunc in a separate thread because it tries to set a
- // thread name and we don't want to change the main thread's name.
- pthread_t t;
- PTHREAD_CREATE(&t, 0, ThreadedTestFunc, 0);
- PTHREAD_JOIN(t, 0);
-}
-
-#if ASAN_NEEDS_SEGV
-TEST(AddressSanitizer, ShadowGapTest) {
-#if SANITIZER_WORDSIZE == 32
- char *addr = (char*)0x23000000;
-#else
-# if defined(__powerpc64__)
- char *addr = (char*)0x024000800000;
-# elif defined(__s390x__)
- char *addr = (char*)0x11000000000000;
-# else
- char *addr = (char*)0x0000100000080000;
-# endif
-#endif
- EXPECT_DEATH(*addr = 1, "AddressSanitizer: (SEGV|BUS) on unknown");
-}
-#endif // ASAN_NEEDS_SEGV
-
-extern "C" {
-NOINLINE static void UseThenFreeThenUse() {
- char *x = Ident((char*)malloc(8));
- *x = 1;
- free_aaa(x);
- *x = 2;
-}
-}
-
-TEST(AddressSanitizer, UseThenFreeThenUseTest) {
- EXPECT_DEATH(UseThenFreeThenUse(), "freed by thread");
-}
-
-TEST(AddressSanitizer, StrDupTest) {
- free(strdup(Ident("123")));
-}
-
-// Currently we create and poison redzone at right of global variables.
-static char static110[110];
-const char ConstGlob[7] = {1, 2, 3, 4, 5, 6, 7};
-static const char StaticConstGlob[3] = {9, 8, 7};
-
-TEST(AddressSanitizer, GlobalTest) {
- static char func_static15[15];
-
- static char fs1[10];
- static char fs2[10];
- static char fs3[10];
-
- glob5[Ident(0)] = 0;
- glob5[Ident(1)] = 0;
- glob5[Ident(2)] = 0;
- glob5[Ident(3)] = 0;
- glob5[Ident(4)] = 0;
-
- EXPECT_DEATH(glob5[Ident(5)] = 0,
- "0 bytes to the right of global variable.*glob5.* size 5");
- EXPECT_DEATH(glob5[Ident(5+6)] = 0,
- "6 bytes to the right of global variable.*glob5.* size 5");
- Ident(static110); // avoid optimizations
- static110[Ident(0)] = 0;
- static110[Ident(109)] = 0;
- EXPECT_DEATH(static110[Ident(110)] = 0,
- "0 bytes to the right of global variable");
- EXPECT_DEATH(static110[Ident(110+7)] = 0,
- "7 bytes to the right of global variable");
-
- Ident(func_static15); // avoid optimizations
- func_static15[Ident(0)] = 0;
- EXPECT_DEATH(func_static15[Ident(15)] = 0,
- "0 bytes to the right of global variable");
- EXPECT_DEATH(func_static15[Ident(15 + 9)] = 0,
- "9 bytes to the right of global variable");
-
- Ident(fs1);
- Ident(fs2);
- Ident(fs3);
-
- // We don't create left redzones, so this is not 100% guaranteed to fail.
- // But most likely will.
- EXPECT_DEATH(fs2[Ident(-1)] = 0, "is located.*of global variable");
-
- EXPECT_DEATH(Ident(Ident(ConstGlob)[8]),
- "is located 1 bytes to the right of .*ConstGlob");
- EXPECT_DEATH(Ident(Ident(StaticConstGlob)[5]),
- "is located 2 bytes to the right of .*StaticConstGlob");
-
- // call stuff from another file.
- GlobalsTest(0);
-}
-
-TEST(AddressSanitizer, GlobalStringConstTest) {
- static const char *zoo = "FOOBAR123";
- const char *p = Ident(zoo);
- EXPECT_DEATH(Ident(p[15]), "is ascii string 'FOOBAR123'");
-}
-
-TEST(AddressSanitizer, FileNameInGlobalReportTest) {
- static char zoo[10];
- const char *p = Ident(zoo);
- // The file name should be present in the report.
- EXPECT_DEATH(Ident(p[15]), "zoo.*asan_test.");
-}
-
-int *ReturnsPointerToALocalObject() {
- int a = 0;
- return Ident(&a);
-}
-
-#if ASAN_UAR == 1
-TEST(AddressSanitizer, LocalReferenceReturnTest) {
- int *(*f)() = Ident(ReturnsPointerToALocalObject);
- int *p = f();
- // Call 'f' a few more times, 'p' should still be poisoned.
- for (int i = 0; i < 32; i++)
- f();
- EXPECT_DEATH(*p = 1, "AddressSanitizer: stack-use-after-return");
- EXPECT_DEATH(*p = 1, "is located.*in frame .*ReturnsPointerToALocal");
-}
-#endif
-
-template <int kSize>
-NOINLINE static void FuncWithStack() {
- char x[kSize];
- Ident(x)[0] = 0;
- Ident(x)[kSize-1] = 0;
-}
-
-static void LotsOfStackReuse() {
- int LargeStack[10000];
- Ident(LargeStack)[0] = 0;
- for (int i = 0; i < 10000; i++) {
- FuncWithStack<128 * 1>();
- FuncWithStack<128 * 2>();
- FuncWithStack<128 * 4>();
- FuncWithStack<128 * 8>();
- FuncWithStack<128 * 16>();
- FuncWithStack<128 * 32>();
- FuncWithStack<128 * 64>();
- FuncWithStack<128 * 128>();
- FuncWithStack<128 * 256>();
- FuncWithStack<128 * 512>();
- Ident(LargeStack)[0] = 0;
- }
-}
-
-TEST(AddressSanitizer, StressStackReuseTest) {
- LotsOfStackReuse();
-}
-
-TEST(AddressSanitizer, ThreadedStressStackReuseTest) {
- const int kNumThreads = 20;
- pthread_t t[kNumThreads];
- for (int i = 0; i < kNumThreads; i++) {
- PTHREAD_CREATE(&t[i], 0, (void* (*)(void *x))LotsOfStackReuse, 0);
- }
- for (int i = 0; i < kNumThreads; i++) {
- PTHREAD_JOIN(t[i], 0);
- }
-}
-
-// pthread_exit tries to perform unwinding stuff that leads to dlopen'ing
-// libgcc_s.so. dlopen in its turn calls malloc to store "libgcc_s.so" string
-// that confuses LSan on Thumb because it fails to understand that this
-// allocation happens in dynamic linker and should be ignored.
-#if !defined(__thumb__)
-static void *PthreadExit(void *a) {
- pthread_exit(0);
- return 0;
-}
-
-TEST(AddressSanitizer, PthreadExitTest) {
- pthread_t t;
- for (int i = 0; i < 1000; i++) {
- PTHREAD_CREATE(&t, 0, PthreadExit, 0);
- PTHREAD_JOIN(t, 0);
- }
-}
-#endif
-
-// FIXME: Why does clang-cl define __EXCEPTIONS?
-#if defined(__EXCEPTIONS) && !defined(_WIN32)
-NOINLINE static void StackReuseAndException() {
- int large_stack[1000];
- Ident(large_stack);
- ASAN_THROW(1);
-}
-
-// TODO(kcc): support exceptions with use-after-return.
-TEST(AddressSanitizer, DISABLED_StressStackReuseAndExceptionsTest) {
- for (int i = 0; i < 10000; i++) {
- try {
- StackReuseAndException();
- } catch(...) {
- }
- }
-}
-#endif
-
-#if !defined(_WIN32)
-TEST(AddressSanitizer, MlockTest) {
- EXPECT_EQ(0, mlockall(MCL_CURRENT));
- EXPECT_EQ(0, mlock((void*)0x12345, 0x5678));
- EXPECT_EQ(0, munlockall());
- EXPECT_EQ(0, munlock((void*)0x987, 0x654));
-}
-#endif
-
-struct LargeStruct {
- int foo[100];
-};
-
-// Test for bug http://llvm.org/bugs/show_bug.cgi?id=11763.
-// Struct copy should not cause asan warning even if lhs == rhs.
-TEST(AddressSanitizer, LargeStructCopyTest) {
- LargeStruct a;
- *Ident(&a) = *Ident(&a);
-}
-
-ATTRIBUTE_NO_SANITIZE_ADDRESS
-static void NoSanitizeAddress() {
- char *foo = new char[10];
- Ident(foo)[10] = 0;
- delete [] foo;
-}
-
-TEST(AddressSanitizer, AttributeNoSanitizeAddressTest) {
- Ident(NoSanitizeAddress)();
-}
-
-// The new/delete/etc mismatch checks don't work on Android,
-// as calls to new/delete go through malloc/free.
-// OS X support is tracked here:
-// https://github.com/google/sanitizers/issues/131
-// Windows support is tracked here:
-// https://github.com/google/sanitizers/issues/309
-#if !defined(__ANDROID__) && \
- !defined(__APPLE__) && \
- !defined(_WIN32)
-static string MismatchStr(const string &str) {
- return string("AddressSanitizer: alloc-dealloc-mismatch \\(") + str;
-}
-
-static string MismatchOrNewDeleteTypeStr(const string &mismatch_str) {
- return "(" + MismatchStr(mismatch_str) +
- ")|(AddressSanitizer: new-delete-type-mismatch)";
-}
-
-TEST(AddressSanitizer, AllocDeallocMismatch) {
- EXPECT_DEATH(free(Ident(new int)),
- MismatchStr("operator new vs free"));
- EXPECT_DEATH(free(Ident(new int[2])),
- MismatchStr("operator new \\[\\] vs free"));
- EXPECT_DEATH(
- delete (Ident(new int[2])),
- MismatchOrNewDeleteTypeStr("operator new \\[\\] vs operator delete"));
- EXPECT_DEATH(delete (Ident((int *)malloc(2 * sizeof(int)))),
- MismatchOrNewDeleteTypeStr("malloc vs operator delete"));
- EXPECT_DEATH(delete [] (Ident(new int)),
- MismatchStr("operator new vs operator delete \\[\\]"));
- EXPECT_DEATH(delete [] (Ident((int*)malloc(2 * sizeof(int)))),
- MismatchStr("malloc vs operator delete \\[\\]"));
-}
-#endif
-
-// ------------------ demo tests; run each one-by-one -------------
-// e.g. --gtest_filter=*DemoOOBLeftHigh --gtest_also_run_disabled_tests
-TEST(AddressSanitizer, DISABLED_DemoThreadedTest) {
- ThreadedTestSpawn();
-}
-
-void *SimpleBugOnSTack(void *x = 0) {
- char a[20];
- Ident(a)[20] = 0;
- return 0;
-}
-
-TEST(AddressSanitizer, DISABLED_DemoStackTest) {
- SimpleBugOnSTack();
-}
-
-TEST(AddressSanitizer, DISABLED_DemoThreadStackTest) {
- pthread_t t;
- PTHREAD_CREATE(&t, 0, SimpleBugOnSTack, 0);
- PTHREAD_JOIN(t, 0);
-}
-
-TEST(AddressSanitizer, DISABLED_DemoUAFLowIn) {
- uaf_test<U1>(10, 0);
-}
-TEST(AddressSanitizer, DISABLED_DemoUAFLowLeft) {
- uaf_test<U1>(10, -2);
-}
-TEST(AddressSanitizer, DISABLED_DemoUAFLowRight) {
- uaf_test<U1>(10, 10);
-}
-
-TEST(AddressSanitizer, DISABLED_DemoUAFHigh) {
- uaf_test<U1>(kLargeMalloc, 0);
-}
-
-TEST(AddressSanitizer, DISABLED_DemoOOM) {
- size_t size = SANITIZER_WORDSIZE == 64 ? (size_t)(1ULL << 40) : (0xf0000000);
- printf("%p\n", malloc(size));
-}
-
-TEST(AddressSanitizer, DISABLED_DemoDoubleFreeTest) {
- DoubleFree();
-}
-
-TEST(AddressSanitizer, DISABLED_DemoNullDerefTest) {
- int *a = 0;
- Ident(a)[10] = 0;
-}
-
-TEST(AddressSanitizer, DISABLED_DemoFunctionStaticTest) {
- static char a[100];
- static char b[100];
- static char c[100];
- Ident(a);
- Ident(b);
- Ident(c);
- Ident(a)[5] = 0;
- Ident(b)[105] = 0;
- Ident(a)[5] = 0;
-}
-
-TEST(AddressSanitizer, DISABLED_DemoTooMuchMemoryTest) {
- const size_t kAllocSize = (1 << 28) - 1024;
- size_t total_size = 0;
- while (true) {
- void *x = malloc(kAllocSize);
- memset(x, 0, kAllocSize);
- total_size += kAllocSize;
- fprintf(stderr, "total: %ldM %p\n", (long)total_size >> 20, x);
- }
-}
-
-#if !defined(__NetBSD__) && !defined(__i386__)
-// https://github.com/google/sanitizers/issues/66
-TEST(AddressSanitizer, BufferOverflowAfterManyFrees) {
- for (int i = 0; i < 1000000; i++) {
- delete [] (Ident(new char [8644]));
- }
- char *x = new char[8192];
- EXPECT_DEATH(x[Ident(8192)] = 0, "AddressSanitizer: heap-buffer-overflow");
- delete [] Ident(x);
-}
-#endif
-
-
-// Test that instrumentation of stack allocations takes into account
-// AllocSize of a type, and not its StoreSize (16 vs 10 bytes for long double).
-// See http://llvm.org/bugs/show_bug.cgi?id=12047 for more details.
-TEST(AddressSanitizer, LongDoubleNegativeTest) {
- long double a, b;
- static long double c;
- memcpy(Ident(&a), Ident(&b), sizeof(long double));
- memcpy(Ident(&c), Ident(&b), sizeof(long double));
-}
-
-#if !defined(_WIN32)
-TEST(AddressSanitizer, pthread_getschedparam) {
- int policy;
- struct sched_param param;
- EXPECT_DEATH(
- pthread_getschedparam(pthread_self(), &policy, Ident(¶m) + 2),
- "AddressSanitizer: stack-buffer-.*flow");
- EXPECT_DEATH(
- pthread_getschedparam(pthread_self(), Ident(&policy) - 1, ¶m),
- "AddressSanitizer: stack-buffer-.*flow");
- int res = pthread_getschedparam(pthread_self(), &policy, ¶m);
- ASSERT_EQ(0, res);
-}
-#endif
-
-#if SANITIZER_TEST_HAS_PRINTF_L
-static int vsnprintf_l_wrapper(char *s, size_t n,
- locale_t l, const char *format, ...) {
- va_list va;
- va_start(va, format);
- int res = vsnprintf_l(s, n , l, format, va);
- va_end(va);
- return res;
-}
-
-TEST(AddressSanitizer, snprintf_l) {
- char buff[5];
- // Check that snprintf_l() works fine with Asan.
- int res = snprintf_l(buff, 5, SANITIZER_GET_C_LOCALE, "%s", "snprintf_l()");
- EXPECT_EQ(12, res);
- // Check that vsnprintf_l() works fine with Asan.
- res = vsnprintf_l_wrapper(buff, 5, SANITIZER_GET_C_LOCALE, "%s",
- "vsnprintf_l()");
- EXPECT_EQ(13, res);
-
- EXPECT_DEATH(
- snprintf_l(buff, 10, SANITIZER_GET_C_LOCALE, "%s", "snprintf_l()"),
- "AddressSanitizer: stack-buffer-overflow");
- EXPECT_DEATH(vsnprintf_l_wrapper(buff, 10, SANITIZER_GET_C_LOCALE, "%s",
- "vsnprintf_l()"),
- "AddressSanitizer: stack-buffer-overflow");
-}
-#endif
--- /dev/null
+//===-- asan_test.cpp -----------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a part of AddressSanitizer, an address sanity checker.
+//
+//===----------------------------------------------------------------------===//
+#include "asan_test_utils.h"
+
+#include <errno.h>
+#include <stdarg.h>
+
+#ifdef _LIBCPP_GET_C_LOCALE
+#define SANITIZER_GET_C_LOCALE _LIBCPP_GET_C_LOCALE
+#else
+#if defined(__FreeBSD__)
+#define SANITIZER_GET_C_LOCALE 0
+#elif defined(__NetBSD__)
+#define SANITIZER_GET_C_LOCALE LC_C_LOCALE
+#endif
+#endif
+
+#if defined(__sun__) && defined(__svr4__)
+using std::_setjmp;
+using std::_longjmp;
+#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 uaf_test(int size, int off) {
+ void *p = malloc_aaa(size);
+ free_aaa(p);
+ for (int i = 1; i < 100; i++)
+ free_aaa(malloc_aaa(i));
+ fprintf(stderr, "writing %ld byte(s) at %p with offset %d\n",
+ (long)sizeof(T), p, off);
+ asan_write((T *)((char *)p + off));
+}
+
+TEST(AddressSanitizer, HasFeatureAddressSanitizerTest) {
+#if defined(__has_feature) && __has_feature(address_sanitizer)
+ bool asan = 1;
+#elif defined(__SANITIZE_ADDRESS__)
+ bool asan = 1;
+#else
+ bool asan = 0;
+#endif
+ EXPECT_EQ(true, asan);
+}
+
+TEST(AddressSanitizer, SimpleDeathTest) {
+ EXPECT_DEATH(exit(1), "");
+}
+
+TEST(AddressSanitizer, VariousMallocsTest) {
+ int *a = (int*)malloc(100 * sizeof(int));
+ a[50] = 0;
+ free(a);
+
+ int *r = (int*)malloc(10);
+ r = (int*)realloc(r, 2000 * sizeof(int));
+ r[1000] = 0;
+ free(r);
+
+ int *b = new int[100];
+ b[50] = 0;
+ delete [] b;
+
+ int *c = new int;
+ *c = 0;
+ delete c;
+
+#if SANITIZER_TEST_HAS_POSIX_MEMALIGN
+ void *pm = 0;
+ // Valid allocation.
+ int pm_res = posix_memalign(&pm, kPageSize, kPageSize);
+ EXPECT_EQ(0, pm_res);
+ EXPECT_NE(nullptr, pm);
+ free(pm);
+#endif // SANITIZER_TEST_HAS_POSIX_MEMALIGN
+
+#if SANITIZER_TEST_HAS_MEMALIGN
+ int *ma = (int*)memalign(kPageSize, kPageSize);
+ EXPECT_EQ(0U, (uintptr_t)ma % kPageSize);
+ ma[123] = 0;
+ free(ma);
+#endif // SANITIZER_TEST_HAS_MEMALIGN
+}
+
+TEST(AddressSanitizer, CallocTest) {
+ int *a = (int*)calloc(100, sizeof(int));
+ EXPECT_EQ(0, a[10]);
+ free(a);
+}
+
+TEST(AddressSanitizer, CallocReturnsZeroMem) {
+ size_t sizes[] = {16, 1000, 10000, 100000, 2100000};
+ for (size_t s = 0; s < sizeof(sizes)/sizeof(sizes[0]); s++) {
+ size_t size = sizes[s];
+ for (size_t iter = 0; iter < 5; iter++) {
+ char *x = Ident((char*)calloc(1, size));
+ EXPECT_EQ(x[0], 0);
+ EXPECT_EQ(x[size - 1], 0);
+ EXPECT_EQ(x[size / 2], 0);
+ EXPECT_EQ(x[size / 3], 0);
+ EXPECT_EQ(x[size / 4], 0);
+ memset(x, 0x42, size);
+ free(Ident(x));
+#if !defined(_WIN32)
+ // FIXME: OOM on Windows. We should just make this a lit test
+ // with quarantine size set to 1.
+ free(Ident(malloc(Ident(1 << 27)))); // Try to drain the quarantine.
+#endif
+ }
+ }
+}
+
+// No valloc on Windows or Android.
+#if !defined(_WIN32) && !defined(__ANDROID__)
+TEST(AddressSanitizer, VallocTest) {
+ void *a = valloc(100);
+ EXPECT_EQ(0U, (uintptr_t)a % kPageSize);
+ free(a);
+}
+#endif
+
+#if SANITIZER_TEST_HAS_PVALLOC
+TEST(AddressSanitizer, PvallocTest) {
+ char *a = (char*)pvalloc(kPageSize + 100);
+ EXPECT_EQ(0U, (uintptr_t)a % kPageSize);
+ a[kPageSize + 101] = 1; // we should not report an error here.
+ free(a);
+
+ a = (char*)pvalloc(0); // pvalloc(0) should allocate at least one page.
+ EXPECT_EQ(0U, (uintptr_t)a % kPageSize);
+ a[101] = 1; // we should not report an error here.
+ free(a);
+}
+#endif // SANITIZER_TEST_HAS_PVALLOC
+
+#if !defined(_WIN32)
+// FIXME: Use an equivalent of pthread_setspecific on Windows.
+void *TSDWorker(void *test_key) {
+ if (test_key) {
+ pthread_setspecific(*(pthread_key_t*)test_key, (void*)0xfeedface);
+ }
+ return NULL;
+}
+
+void TSDDestructor(void *tsd) {
+ // Spawning a thread will check that the current thread id is not -1.
+ pthread_t th;
+ PTHREAD_CREATE(&th, NULL, TSDWorker, NULL);
+ PTHREAD_JOIN(th, NULL);
+}
+
+// This tests triggers the thread-specific data destruction fiasco which occurs
+// if we don't manage the TSD destructors ourselves. We create a new pthread
+// key with a non-NULL destructor which is likely to be put after the destructor
+// of AsanThread in the list of destructors.
+// In this case the TSD for AsanThread will be destroyed before TSDDestructor
+// is called for the child thread, and a CHECK will fail when we call
+// pthread_create() to spawn the grandchild.
+TEST(AddressSanitizer, DISABLED_TSDTest) {
+ pthread_t th;
+ pthread_key_t test_key;
+ pthread_key_create(&test_key, TSDDestructor);
+ PTHREAD_CREATE(&th, NULL, TSDWorker, &test_key);
+ PTHREAD_JOIN(th, NULL);
+ pthread_key_delete(test_key);
+}
+#endif
+
+TEST(AddressSanitizer, UAF_char) {
+ const char *uaf_string = "AddressSanitizer:.*heap-use-after-free";
+ EXPECT_DEATH(uaf_test<U1>(1, 0), uaf_string);
+ EXPECT_DEATH(uaf_test<U1>(10, 0), uaf_string);
+ EXPECT_DEATH(uaf_test<U1>(10, 10), uaf_string);
+ EXPECT_DEATH(uaf_test<U1>(kLargeMalloc, 0), uaf_string);
+ EXPECT_DEATH(uaf_test<U1>(kLargeMalloc, kLargeMalloc / 2), uaf_string);
+}
+
+TEST(AddressSanitizer, UAF_long_double) {
+ if (sizeof(long double) == sizeof(double)) return;
+ long double *p = Ident(new long double[10]);
+ EXPECT_DEATH(Ident(p)[12] = 0, "WRITE of size 1[026]");
+ EXPECT_DEATH(Ident(p)[0] = Ident(p)[12], "READ of size 1[026]");
+ delete [] Ident(p);
+}
+
+#if !defined(_WIN32)
+struct Packed5 {
+ int x;
+ char c;
+} __attribute__((packed));
+#else
+# pragma pack(push, 1)
+struct Packed5 {
+ int x;
+ char c;
+};
+# pragma pack(pop)
+#endif
+
+TEST(AddressSanitizer, UAF_Packed5) {
+ static_assert(sizeof(Packed5) == 5, "Please check the keywords used");
+ Packed5 *p = Ident(new Packed5[2]);
+ EXPECT_DEATH(p[0] = p[3], "READ of size 5");
+ EXPECT_DEATH(p[3] = p[0], "WRITE of size 5");
+ delete [] Ident(p);
+}
+
+#if ASAN_HAS_BLACKLIST
+TEST(AddressSanitizer, IgnoreTest) {
+ int *x = Ident(new int);
+ delete Ident(x);
+ *x = 0;
+}
+#endif // ASAN_HAS_BLACKLIST
+
+struct StructWithBitField {
+ int bf1:1;
+ int bf2:1;
+ int bf3:1;
+ int bf4:29;
+};
+
+TEST(AddressSanitizer, BitFieldPositiveTest) {
+ StructWithBitField *x = new StructWithBitField;
+ delete Ident(x);
+ EXPECT_DEATH(x->bf1 = 0, "use-after-free");
+ EXPECT_DEATH(x->bf2 = 0, "use-after-free");
+ EXPECT_DEATH(x->bf3 = 0, "use-after-free");
+ EXPECT_DEATH(x->bf4 = 0, "use-after-free");
+}
+
+struct StructWithBitFields_8_24 {
+ int a:8;
+ int b:24;
+};
+
+TEST(AddressSanitizer, BitFieldNegativeTest) {
+ StructWithBitFields_8_24 *x = Ident(new StructWithBitFields_8_24);
+ x->a = 0;
+ x->b = 0;
+ delete Ident(x);
+}
+
+#if ASAN_NEEDS_SEGV
+namespace {
+
+const char kSEGVCrash[] = "AddressSanitizer: SEGV on unknown address";
+const char kOverriddenSigactionHandler[] = "Test sigaction handler\n";
+const char kOverriddenSignalHandler[] = "Test signal handler\n";
+
+TEST(AddressSanitizer, WildAddressTest) {
+ char *c = (char*)0x123;
+ EXPECT_DEATH(*c = 0, kSEGVCrash);
+}
+
+void my_sigaction_sighandler(int, siginfo_t*, void*) {
+ fprintf(stderr, kOverriddenSigactionHandler);
+ exit(1);
+}
+
+void my_signal_sighandler(int signum) {
+ fprintf(stderr, kOverriddenSignalHandler);
+ exit(1);
+}
+
+TEST(AddressSanitizer, SignalTest) {
+ struct sigaction sigact;
+ memset(&sigact, 0, sizeof(sigact));
+ sigact.sa_sigaction = my_sigaction_sighandler;
+ sigact.sa_flags = SA_SIGINFO;
+ char *c = (char *)0x123;
+
+ EXPECT_DEATH(*c = 0, kSEGVCrash);
+
+ // ASan should allow to set sigaction()...
+ EXPECT_EQ(0, sigaction(SIGSEGV, &sigact, 0));
+#ifdef __APPLE__
+ EXPECT_EQ(0, sigaction(SIGBUS, &sigact, 0));
+#endif
+ EXPECT_DEATH(*c = 0, kOverriddenSigactionHandler);
+
+ // ... and signal().
+ EXPECT_NE(SIG_ERR, signal(SIGSEGV, my_signal_sighandler));
+ EXPECT_DEATH(*c = 0, kOverriddenSignalHandler);
+}
+} // namespace
+#endif
+
+static void TestLargeMalloc(size_t size) {
+ char buff[1024];
+ sprintf(buff, "is located 1 bytes to the left of %lu-byte", (long)size);
+ EXPECT_DEATH(Ident((char*)malloc(size))[-1] = 0, buff);
+}
+
+TEST(AddressSanitizer, LargeMallocTest) {
+ const int max_size = (SANITIZER_WORDSIZE == 32) ? 1 << 26 : 1 << 28;
+ for (int i = 113; i < max_size; i = i * 2 + 13) {
+ TestLargeMalloc(i);
+ }
+}
+
+#if !GTEST_USES_SIMPLE_RE
+TEST(AddressSanitizer, HugeMallocTest) {
+ if (SANITIZER_WORDSIZE != 64 || ASAN_AVOID_EXPENSIVE_TESTS) return;
+ size_t n_megs = 4100;
+ EXPECT_DEATH(Ident((char*)malloc(n_megs << 20))[-1] = 0,
+ "is located 1 bytes to the left|"
+ "AddressSanitizer failed to allocate");
+}
+#endif
+
+#if SANITIZER_TEST_HAS_MEMALIGN
+void MemalignRun(size_t align, size_t size, int idx) {
+ char *p = (char *)memalign(align, size);
+ Ident(p)[idx] = 0;
+ free(p);
+}
+
+TEST(AddressSanitizer, memalign) {
+ for (int align = 16; align <= (1 << 23); align *= 2) {
+ size_t size = align * 5;
+ EXPECT_DEATH(MemalignRun(align, size, -1),
+ "is located 1 bytes to the left");
+ EXPECT_DEATH(MemalignRun(align, size, size + 1),
+ "is located 1 bytes to the right");
+ }
+}
+#endif // SANITIZER_TEST_HAS_MEMALIGN
+
+void *ManyThreadsWorker(void *a) {
+ for (int iter = 0; iter < 100; iter++) {
+ for (size_t size = 100; size < 2000; size *= 2) {
+ free(Ident(malloc(size)));
+ }
+ }
+ return 0;
+}
+
+#if !defined(__aarch64__) && !defined(__powerpc64__)
+// FIXME: Infinite loop in AArch64 (PR24389).
+// FIXME: Also occasional hang on powerpc. Maybe same problem as on AArch64?
+TEST(AddressSanitizer, ManyThreadsTest) {
+ const size_t kNumThreads =
+ (SANITIZER_WORDSIZE == 32 || ASAN_AVOID_EXPENSIVE_TESTS) ? 30 : 1000;
+ pthread_t t[kNumThreads];
+ for (size_t i = 0; i < kNumThreads; i++) {
+ PTHREAD_CREATE(&t[i], 0, ManyThreadsWorker, (void*)i);
+ }
+ for (size_t i = 0; i < kNumThreads; i++) {
+ PTHREAD_JOIN(t[i], 0);
+ }
+}
+#endif
+
+TEST(AddressSanitizer, ReallocTest) {
+ const int kMinElem = 5;
+ int *ptr = (int*)malloc(sizeof(int) * kMinElem);
+ ptr[3] = 3;
+ for (int i = 0; i < 10000; i++) {
+ ptr = (int*)realloc(ptr,
+ (my_rand() % 1000 + kMinElem) * sizeof(int));
+ EXPECT_EQ(3, ptr[3]);
+ }
+ free(ptr);
+ // Realloc pointer returned by malloc(0).
+ int *ptr2 = Ident((int*)malloc(0));
+ ptr2 = Ident((int*)realloc(ptr2, sizeof(*ptr2)));
+ *ptr2 = 42;
+ EXPECT_EQ(42, *ptr2);
+ free(ptr2);
+}
+
+TEST(AddressSanitizer, ReallocFreedPointerTest) {
+ void *ptr = Ident(malloc(42));
+ ASSERT_TRUE(NULL != ptr);
+ free(ptr);
+ EXPECT_DEATH(ptr = realloc(ptr, 77), "attempting double-free");
+}
+
+TEST(AddressSanitizer, ReallocInvalidPointerTest) {
+ void *ptr = Ident(malloc(42));
+ EXPECT_DEATH(ptr = realloc((int*)ptr + 1, 77), "attempting free.*not malloc");
+ free(ptr);
+}
+
+TEST(AddressSanitizer, ZeroSizeMallocTest) {
+ // Test that malloc(0) and similar functions don't return NULL.
+ void *ptr = Ident(malloc(0));
+ EXPECT_TRUE(NULL != ptr);
+ free(ptr);
+#if SANITIZER_TEST_HAS_POSIX_MEMALIGN
+ int pm_res = posix_memalign(&ptr, 1<<20, 0);
+ EXPECT_EQ(0, pm_res);
+ EXPECT_TRUE(NULL != ptr);
+ free(ptr);
+#endif // SANITIZER_TEST_HAS_POSIX_MEMALIGN
+ int *int_ptr = new int[0];
+ int *int_ptr2 = new int[0];
+ EXPECT_TRUE(NULL != int_ptr);
+ EXPECT_TRUE(NULL != int_ptr2);
+ EXPECT_NE(int_ptr, int_ptr2);
+ delete[] int_ptr;
+ delete[] int_ptr2;
+}
+
+#if SANITIZER_TEST_HAS_MALLOC_USABLE_SIZE
+static const char *kMallocUsableSizeErrorMsg =
+ "AddressSanitizer: attempting to call malloc_usable_size()";
+
+TEST(AddressSanitizer, MallocUsableSizeTest) {
+ const size_t kArraySize = 100;
+ char *array = Ident((char*)malloc(kArraySize));
+ int *int_ptr = Ident(new int);
+ EXPECT_EQ(0U, malloc_usable_size(NULL));
+ EXPECT_EQ(kArraySize, malloc_usable_size(array));
+ EXPECT_EQ(sizeof(int), malloc_usable_size(int_ptr));
+ EXPECT_DEATH(malloc_usable_size((void*)0x123), kMallocUsableSizeErrorMsg);
+ EXPECT_DEATH(malloc_usable_size(array + kArraySize / 2),
+ kMallocUsableSizeErrorMsg);
+ free(array);
+ EXPECT_DEATH(malloc_usable_size(array), kMallocUsableSizeErrorMsg);
+ delete int_ptr;
+}
+#endif // SANITIZER_TEST_HAS_MALLOC_USABLE_SIZE
+
+void WrongFree() {
+ int *x = (int*)malloc(100 * sizeof(int));
+ // Use the allocated memory, otherwise Clang will optimize it out.
+ Ident(x);
+ free(x + 1);
+}
+
+#if !defined(_WIN32) // FIXME: This should be a lit test.
+TEST(AddressSanitizer, WrongFreeTest) {
+ EXPECT_DEATH(WrongFree(), ASAN_PCRE_DOTALL
+ "ERROR: AddressSanitizer: attempting free.*not malloc"
+ ".*is located 4 bytes inside of 400-byte region"
+ ".*allocated by thread");
+}
+#endif
+
+void DoubleFree() {
+ int *x = (int*)malloc(100 * sizeof(int));
+ fprintf(stderr, "DoubleFree: x=%p\n", (void *)x);
+ free(x);
+ free(x);
+ fprintf(stderr, "should have failed in the second free(%p)\n", (void *)x);
+ abort();
+}
+
+#if !defined(_WIN32) // FIXME: This should be a lit test.
+TEST(AddressSanitizer, DoubleFreeTest) {
+ EXPECT_DEATH(DoubleFree(), ASAN_PCRE_DOTALL
+ "ERROR: AddressSanitizer: attempting double-free"
+ ".*is located 0 bytes inside of 400-byte region"
+ ".*freed by thread T0 here"
+ ".*previously allocated by thread T0 here");
+}
+#endif
+
+template<int kSize>
+NOINLINE void SizedStackTest() {
+ char a[kSize];
+ char *A = Ident((char*)&a);
+ const char *expected_death = "AddressSanitizer: stack-buffer-";
+ for (size_t i = 0; i < kSize; i++)
+ A[i] = i;
+ EXPECT_DEATH(A[-1] = 0, expected_death);
+ EXPECT_DEATH(A[-5] = 0, expected_death);
+ EXPECT_DEATH(A[kSize] = 0, expected_death);
+ EXPECT_DEATH(A[kSize + 1] = 0, expected_death);
+ EXPECT_DEATH(A[kSize + 5] = 0, expected_death);
+ if (kSize > 16)
+ EXPECT_DEATH(A[kSize + 31] = 0, expected_death);
+}
+
+TEST(AddressSanitizer, SimpleStackTest) {
+ SizedStackTest<1>();
+ SizedStackTest<2>();
+ SizedStackTest<3>();
+ SizedStackTest<4>();
+ SizedStackTest<5>();
+ SizedStackTest<6>();
+ SizedStackTest<7>();
+ SizedStackTest<16>();
+ SizedStackTest<25>();
+ SizedStackTest<34>();
+ SizedStackTest<43>();
+ SizedStackTest<51>();
+ SizedStackTest<62>();
+ SizedStackTest<64>();
+ SizedStackTest<128>();
+}
+
+#if !defined(_WIN32)
+// FIXME: It's a bit hard to write multi-line death test expectations
+// in a portable way. Anyways, this should just be turned into a lit test.
+TEST(AddressSanitizer, ManyStackObjectsTest) {
+ char XXX[10];
+ char YYY[20];
+ char ZZZ[30];
+ Ident(XXX);
+ Ident(YYY);
+ EXPECT_DEATH(Ident(ZZZ)[-1] = 0, ASAN_PCRE_DOTALL "XXX.*YYY.*ZZZ");
+}
+#endif
+
+#if 0 // This test requires online symbolizer.
+// Moved to lit_tests/stack-oob-frames.cc.
+// Reenable here once we have online symbolizer by default.
+NOINLINE static void Frame0(int frame, char *a, char *b, char *c) {
+ char d[4] = {0};
+ char *D = Ident(d);
+ switch (frame) {
+ case 3: a[5]++; break;
+ case 2: b[5]++; break;
+ case 1: c[5]++; break;
+ case 0: D[5]++; break;
+ }
+}
+NOINLINE static void Frame1(int frame, char *a, char *b) {
+ char c[4] = {0}; Frame0(frame, a, b, c);
+ break_optimization(0);
+}
+NOINLINE static void Frame2(int frame, char *a) {
+ char b[4] = {0}; Frame1(frame, a, b);
+ break_optimization(0);
+}
+NOINLINE static void Frame3(int frame) {
+ char a[4] = {0}; Frame2(frame, a);
+ break_optimization(0);
+}
+
+TEST(AddressSanitizer, GuiltyStackFrame0Test) {
+ EXPECT_DEATH(Frame3(0), "located .*in frame <.*Frame0");
+}
+TEST(AddressSanitizer, GuiltyStackFrame1Test) {
+ EXPECT_DEATH(Frame3(1), "located .*in frame <.*Frame1");
+}
+TEST(AddressSanitizer, GuiltyStackFrame2Test) {
+ EXPECT_DEATH(Frame3(2), "located .*in frame <.*Frame2");
+}
+TEST(AddressSanitizer, GuiltyStackFrame3Test) {
+ EXPECT_DEATH(Frame3(3), "located .*in frame <.*Frame3");
+}
+#endif
+
+NOINLINE void LongJmpFunc1(jmp_buf buf) {
+ // create three red zones for these two stack objects.
+ int a;
+ int b;
+
+ int *A = Ident(&a);
+ int *B = Ident(&b);
+ *A = *B;
+ longjmp(buf, 1);
+}
+
+NOINLINE void TouchStackFunc() {
+ int a[100]; // long array will intersect with redzones from LongJmpFunc1.
+ int *A = Ident(a);
+ for (int i = 0; i < 100; i++)
+ A[i] = i*i;
+}
+
+// Test that we handle longjmp and do not report false positives on stack.
+TEST(AddressSanitizer, LongJmpTest) {
+ static jmp_buf buf;
+ if (!setjmp(buf)) {
+ LongJmpFunc1(buf);
+ } else {
+ TouchStackFunc();
+ }
+}
+
+#if !defined(_WIN32) // Only basic longjmp is available on Windows.
+NOINLINE void UnderscopeLongJmpFunc1(jmp_buf buf) {
+ // create three red zones for these two stack objects.
+ int a;
+ int b;
+
+ int *A = Ident(&a);
+ int *B = Ident(&b);
+ *A = *B;
+ _longjmp(buf, 1);
+}
+
+NOINLINE void SigLongJmpFunc1(sigjmp_buf buf) {
+ // create three red zones for these two stack objects.
+ int a;
+ int b;
+
+ int *A = Ident(&a);
+ int *B = Ident(&b);
+ *A = *B;
+ siglongjmp(buf, 1);
+}
+
+#if !defined(__ANDROID__) && !defined(__arm__) && \
+ !defined(__aarch64__) && !defined(__mips__) && \
+ !defined(__mips64) && !defined(__s390__)
+NOINLINE void BuiltinLongJmpFunc1(jmp_buf buf) {
+ // create three red zones for these two stack objects.
+ int a;
+ int b;
+
+ int *A = Ident(&a);
+ int *B = Ident(&b);
+ *A = *B;
+ __builtin_longjmp((void**)buf, 1);
+}
+
+// Does not work on ARM:
+// https://github.com/google/sanitizers/issues/185
+TEST(AddressSanitizer, BuiltinLongJmpTest) {
+ static jmp_buf buf;
+ if (!__builtin_setjmp((void**)buf)) {
+ BuiltinLongJmpFunc1(buf);
+ } else {
+ TouchStackFunc();
+ }
+}
+#endif // !defined(__ANDROID__) && !defined(__arm__) &&
+ // !defined(__aarch64__) && !defined(__mips__)
+ // !defined(__mips64) && !defined(__s390__)
+
+TEST(AddressSanitizer, UnderscopeLongJmpTest) {
+ static jmp_buf buf;
+ if (!_setjmp(buf)) {
+ UnderscopeLongJmpFunc1(buf);
+ } else {
+ TouchStackFunc();
+ }
+}
+
+TEST(AddressSanitizer, SigLongJmpTest) {
+ static sigjmp_buf buf;
+ if (!sigsetjmp(buf, 1)) {
+ SigLongJmpFunc1(buf);
+ } else {
+ TouchStackFunc();
+ }
+}
+#endif
+
+// FIXME: Why does clang-cl define __EXCEPTIONS?
+#if defined(__EXCEPTIONS) && !defined(_WIN32)
+NOINLINE void ThrowFunc() {
+ // create three red zones for these two stack objects.
+ int a;
+ int b;
+
+ int *A = Ident(&a);
+ int *B = Ident(&b);
+ *A = *B;
+ ASAN_THROW(1);
+}
+
+TEST(AddressSanitizer, CxxExceptionTest) {
+ if (ASAN_UAR) return;
+ // TODO(kcc): this test crashes on 32-bit for some reason...
+ if (SANITIZER_WORDSIZE == 32) return;
+ try {
+ ThrowFunc();
+ } catch(...) {}
+ TouchStackFunc();
+}
+#endif
+
+void *ThreadStackReuseFunc1(void *unused) {
+ // create three red zones for these two stack objects.
+ int a;
+ int b;
+
+ int *A = Ident(&a);
+ int *B = Ident(&b);
+ *A = *B;
+ pthread_exit(0);
+ return 0;
+}
+
+void *ThreadStackReuseFunc2(void *unused) {
+ TouchStackFunc();
+ return 0;
+}
+
+#if !defined(__thumb__)
+TEST(AddressSanitizer, ThreadStackReuseTest) {
+ pthread_t t;
+ PTHREAD_CREATE(&t, 0, ThreadStackReuseFunc1, 0);
+ PTHREAD_JOIN(t, 0);
+ PTHREAD_CREATE(&t, 0, ThreadStackReuseFunc2, 0);
+ PTHREAD_JOIN(t, 0);
+}
+#endif
+
+#if defined(__SSE2__)
+#include <emmintrin.h>
+TEST(AddressSanitizer, Store128Test) {
+ char *a = Ident((char*)malloc(Ident(12)));
+ char *p = a;
+ if (((uintptr_t)a % 16) != 0)
+ p = a + 8;
+ assert(((uintptr_t)p % 16) == 0);
+ __m128i value_wide = _mm_set1_epi16(0x1234);
+ EXPECT_DEATH(_mm_store_si128((__m128i*)p, value_wide),
+ "AddressSanitizer: heap-buffer-overflow");
+ EXPECT_DEATH(_mm_store_si128((__m128i*)p, value_wide),
+ "WRITE of size 16");
+ EXPECT_DEATH(_mm_store_si128((__m128i*)p, value_wide),
+ "located 0 bytes to the right of 12-byte");
+ free(a);
+}
+#endif
+
+// FIXME: All tests that use this function should be turned into lit tests.
+string RightOOBErrorMessage(int oob_distance, bool is_write) {
+ assert(oob_distance >= 0);
+ char expected_str[100];
+ sprintf(expected_str, ASAN_PCRE_DOTALL
+#if !GTEST_USES_SIMPLE_RE
+ "buffer-overflow.*%s.*"
+#endif
+ "located %d bytes to the right",
+#if !GTEST_USES_SIMPLE_RE
+ is_write ? "WRITE" : "READ",
+#endif
+ oob_distance);
+ return string(expected_str);
+}
+
+string RightOOBWriteMessage(int oob_distance) {
+ return RightOOBErrorMessage(oob_distance, /*is_write*/true);
+}
+
+string RightOOBReadMessage(int oob_distance) {
+ return RightOOBErrorMessage(oob_distance, /*is_write*/false);
+}
+
+// FIXME: All tests that use this function should be turned into lit tests.
+string LeftOOBErrorMessage(int oob_distance, bool is_write) {
+ assert(oob_distance > 0);
+ char expected_str[100];
+ sprintf(expected_str,
+#if !GTEST_USES_SIMPLE_RE
+ ASAN_PCRE_DOTALL "%s.*"
+#endif
+ "located %d bytes to the left",
+#if !GTEST_USES_SIMPLE_RE
+ is_write ? "WRITE" : "READ",
+#endif
+ oob_distance);
+ return string(expected_str);
+}
+
+string LeftOOBWriteMessage(int oob_distance) {
+ return LeftOOBErrorMessage(oob_distance, /*is_write*/true);
+}
+
+string LeftOOBReadMessage(int oob_distance) {
+ return LeftOOBErrorMessage(oob_distance, /*is_write*/false);
+}
+
+string LeftOOBAccessMessage(int oob_distance) {
+ assert(oob_distance > 0);
+ char expected_str[100];
+ sprintf(expected_str, "located %d bytes to the left", oob_distance);
+ return string(expected_str);
+}
+
+char* MallocAndMemsetString(size_t size, char ch) {
+ char *s = Ident((char*)malloc(size));
+ memset(s, ch, size);
+ return s;
+}
+
+char* MallocAndMemsetString(size_t size) {
+ return MallocAndMemsetString(size, 'z');
+}
+
+#if defined(__linux__) && !defined(__ANDROID__)
+#define READ_TEST(READ_N_BYTES) \
+ char *x = new char[10]; \
+ int fd = open("/proc/self/stat", O_RDONLY); \
+ ASSERT_GT(fd, 0); \
+ EXPECT_DEATH(READ_N_BYTES, \
+ ASAN_PCRE_DOTALL \
+ "AddressSanitizer: heap-buffer-overflow" \
+ ".* is located 0 bytes to the right of 10-byte region"); \
+ close(fd); \
+ delete [] x; \
+
+TEST(AddressSanitizer, pread) {
+ READ_TEST(pread(fd, x, 15, 0));
+}
+
+TEST(AddressSanitizer, pread64) {
+ READ_TEST(pread64(fd, x, 15, 0));
+}
+
+TEST(AddressSanitizer, read) {
+ READ_TEST(read(fd, x, 15));
+}
+#endif // defined(__linux__) && !defined(__ANDROID__)
+
+// This test case fails
+// Clang optimizes memcpy/memset calls which lead to unaligned access
+TEST(AddressSanitizer, DISABLED_MemIntrinsicUnalignedAccessTest) {
+ int size = Ident(4096);
+ char *s = Ident((char*)malloc(size));
+ EXPECT_DEATH(memset(s + size - 1, 0, 2), RightOOBWriteMessage(0));
+ free(s);
+}
+
+NOINLINE static int LargeFunction(bool do_bad_access) {
+ int *x = new int[100];
+ x[0]++;
+ x[1]++;
+ x[2]++;
+ x[3]++;
+ x[4]++;
+ x[5]++;
+ x[6]++;
+ x[7]++;
+ x[8]++;
+ x[9]++;
+
+ x[do_bad_access ? 100 : 0]++; int res = __LINE__;
+
+ x[10]++;
+ x[11]++;
+ x[12]++;
+ x[13]++;
+ x[14]++;
+ x[15]++;
+ x[16]++;
+ x[17]++;
+ x[18]++;
+ x[19]++;
+
+ delete[] x;
+ return res;
+}
+
+// Test the we have correct debug info for the failing instruction.
+// This test requires the in-process symbolizer to be enabled by default.
+TEST(AddressSanitizer, DISABLED_LargeFunctionSymbolizeTest) {
+ int failing_line = LargeFunction(false);
+ char expected_warning[128];
+ sprintf(expected_warning, "LargeFunction.*asan_test.*:%d", failing_line);
+ EXPECT_DEATH(LargeFunction(true), expected_warning);
+}
+
+// Check that we unwind and symbolize correctly.
+TEST(AddressSanitizer, DISABLED_MallocFreeUnwindAndSymbolizeTest) {
+ int *a = (int*)malloc_aaa(sizeof(int));
+ *a = 1;
+ free_aaa(a);
+ EXPECT_DEATH(*a = 1, "free_ccc.*free_bbb.*free_aaa.*"
+ "malloc_fff.*malloc_eee.*malloc_ddd");
+}
+
+static bool TryToSetThreadName(const char *name) {
+#if defined(__linux__) && defined(PR_SET_NAME)
+ return 0 == prctl(PR_SET_NAME, (unsigned long)name, 0, 0, 0);
+#else
+ return false;
+#endif
+}
+
+void *ThreadedTestAlloc(void *a) {
+ EXPECT_EQ(true, TryToSetThreadName("AllocThr"));
+ int **p = (int**)a;
+ *p = new int;
+ return 0;
+}
+
+void *ThreadedTestFree(void *a) {
+ EXPECT_EQ(true, TryToSetThreadName("FreeThr"));
+ int **p = (int**)a;
+ delete *p;
+ return 0;
+}
+
+void *ThreadedTestUse(void *a) {
+ EXPECT_EQ(true, TryToSetThreadName("UseThr"));
+ int **p = (int**)a;
+ **p = 1;
+ return 0;
+}
+
+void ThreadedTestSpawn() {
+ pthread_t t;
+ int *x;
+ PTHREAD_CREATE(&t, 0, ThreadedTestAlloc, &x);
+ PTHREAD_JOIN(t, 0);
+ PTHREAD_CREATE(&t, 0, ThreadedTestFree, &x);
+ PTHREAD_JOIN(t, 0);
+ PTHREAD_CREATE(&t, 0, ThreadedTestUse, &x);
+ PTHREAD_JOIN(t, 0);
+}
+
+#if !defined(_WIN32) // FIXME: This should be a lit test.
+TEST(AddressSanitizer, ThreadedTest) {
+ EXPECT_DEATH(ThreadedTestSpawn(),
+ ASAN_PCRE_DOTALL
+ "Thread T.*created"
+ ".*Thread T.*created"
+ ".*Thread T.*created");
+}
+#endif
+
+void *ThreadedTestFunc(void *unused) {
+ // Check if prctl(PR_SET_NAME) is supported. Return if not.
+ if (!TryToSetThreadName("TestFunc"))
+ return 0;
+ EXPECT_DEATH(ThreadedTestSpawn(),
+ ASAN_PCRE_DOTALL
+ "WRITE .*thread T. .UseThr."
+ ".*freed by thread T. .FreeThr. here:"
+ ".*previously allocated by thread T. .AllocThr. here:"
+ ".*Thread T. .UseThr. created by T.*TestFunc"
+ ".*Thread T. .FreeThr. created by T"
+ ".*Thread T. .AllocThr. created by T"
+ "");
+ return 0;
+}
+
+TEST(AddressSanitizer, ThreadNamesTest) {
+ // Run ThreadedTestFunc in a separate thread because it tries to set a
+ // thread name and we don't want to change the main thread's name.
+ pthread_t t;
+ PTHREAD_CREATE(&t, 0, ThreadedTestFunc, 0);
+ PTHREAD_JOIN(t, 0);
+}
+
+#if ASAN_NEEDS_SEGV
+TEST(AddressSanitizer, ShadowGapTest) {
+#if SANITIZER_WORDSIZE == 32
+ char *addr = (char*)0x23000000;
+#else
+# if defined(__powerpc64__)
+ char *addr = (char*)0x024000800000;
+# elif defined(__s390x__)
+ char *addr = (char*)0x11000000000000;
+# else
+ char *addr = (char*)0x0000100000080000;
+# endif
+#endif
+ EXPECT_DEATH(*addr = 1, "AddressSanitizer: (SEGV|BUS) on unknown");
+}
+#endif // ASAN_NEEDS_SEGV
+
+extern "C" {
+NOINLINE static void UseThenFreeThenUse() {
+ char *x = Ident((char*)malloc(8));
+ *x = 1;
+ free_aaa(x);
+ *x = 2;
+}
+}
+
+TEST(AddressSanitizer, UseThenFreeThenUseTest) {
+ EXPECT_DEATH(UseThenFreeThenUse(), "freed by thread");
+}
+
+TEST(AddressSanitizer, StrDupTest) {
+ free(strdup(Ident("123")));
+}
+
+// Currently we create and poison redzone at right of global variables.
+static char static110[110];
+const char ConstGlob[7] = {1, 2, 3, 4, 5, 6, 7};
+static const char StaticConstGlob[3] = {9, 8, 7};
+
+TEST(AddressSanitizer, GlobalTest) {
+ static char func_static15[15];
+
+ static char fs1[10];
+ static char fs2[10];
+ static char fs3[10];
+
+ glob5[Ident(0)] = 0;
+ glob5[Ident(1)] = 0;
+ glob5[Ident(2)] = 0;
+ glob5[Ident(3)] = 0;
+ glob5[Ident(4)] = 0;
+
+ EXPECT_DEATH(glob5[Ident(5)] = 0,
+ "0 bytes to the right of global variable.*glob5.* size 5");
+ EXPECT_DEATH(glob5[Ident(5+6)] = 0,
+ "6 bytes to the right of global variable.*glob5.* size 5");
+ Ident(static110); // avoid optimizations
+ static110[Ident(0)] = 0;
+ static110[Ident(109)] = 0;
+ EXPECT_DEATH(static110[Ident(110)] = 0,
+ "0 bytes to the right of global variable");
+ EXPECT_DEATH(static110[Ident(110+7)] = 0,
+ "7 bytes to the right of global variable");
+
+ Ident(func_static15); // avoid optimizations
+ func_static15[Ident(0)] = 0;
+ EXPECT_DEATH(func_static15[Ident(15)] = 0,
+ "0 bytes to the right of global variable");
+ EXPECT_DEATH(func_static15[Ident(15 + 9)] = 0,
+ "9 bytes to the right of global variable");
+
+ Ident(fs1);
+ Ident(fs2);
+ Ident(fs3);
+
+ // We don't create left redzones, so this is not 100% guaranteed to fail.
+ // But most likely will.
+ EXPECT_DEATH(fs2[Ident(-1)] = 0, "is located.*of global variable");
+
+ EXPECT_DEATH(Ident(Ident(ConstGlob)[8]),
+ "is located 1 bytes to the right of .*ConstGlob");
+ EXPECT_DEATH(Ident(Ident(StaticConstGlob)[5]),
+ "is located 2 bytes to the right of .*StaticConstGlob");
+
+ // call stuff from another file.
+ GlobalsTest(0);
+}
+
+TEST(AddressSanitizer, GlobalStringConstTest) {
+ static const char *zoo = "FOOBAR123";
+ const char *p = Ident(zoo);
+ EXPECT_DEATH(Ident(p[15]), "is ascii string 'FOOBAR123'");
+}
+
+TEST(AddressSanitizer, FileNameInGlobalReportTest) {
+ static char zoo[10];
+ const char *p = Ident(zoo);
+ // The file name should be present in the report.
+ EXPECT_DEATH(Ident(p[15]), "zoo.*asan_test.");
+}
+
+int *ReturnsPointerToALocalObject() {
+ int a = 0;
+ return Ident(&a);
+}
+
+#if ASAN_UAR == 1
+TEST(AddressSanitizer, LocalReferenceReturnTest) {
+ int *(*f)() = Ident(ReturnsPointerToALocalObject);
+ int *p = f();
+ // Call 'f' a few more times, 'p' should still be poisoned.
+ for (int i = 0; i < 32; i++)
+ f();
+ EXPECT_DEATH(*p = 1, "AddressSanitizer: stack-use-after-return");
+ EXPECT_DEATH(*p = 1, "is located.*in frame .*ReturnsPointerToALocal");
+}
+#endif
+
+template <int kSize>
+NOINLINE static void FuncWithStack() {
+ char x[kSize];
+ Ident(x)[0] = 0;
+ Ident(x)[kSize-1] = 0;
+}
+
+static void LotsOfStackReuse() {
+ int LargeStack[10000];
+ Ident(LargeStack)[0] = 0;
+ for (int i = 0; i < 10000; i++) {
+ FuncWithStack<128 * 1>();
+ FuncWithStack<128 * 2>();
+ FuncWithStack<128 * 4>();
+ FuncWithStack<128 * 8>();
+ FuncWithStack<128 * 16>();
+ FuncWithStack<128 * 32>();
+ FuncWithStack<128 * 64>();
+ FuncWithStack<128 * 128>();
+ FuncWithStack<128 * 256>();
+ FuncWithStack<128 * 512>();
+ Ident(LargeStack)[0] = 0;
+ }
+}
+
+TEST(AddressSanitizer, StressStackReuseTest) {
+ LotsOfStackReuse();
+}
+
+TEST(AddressSanitizer, ThreadedStressStackReuseTest) {
+ const int kNumThreads = 20;
+ pthread_t t[kNumThreads];
+ for (int i = 0; i < kNumThreads; i++) {
+ PTHREAD_CREATE(&t[i], 0, (void* (*)(void *x))LotsOfStackReuse, 0);
+ }
+ for (int i = 0; i < kNumThreads; i++) {
+ PTHREAD_JOIN(t[i], 0);
+ }
+}
+
+// pthread_exit tries to perform unwinding stuff that leads to dlopen'ing
+// libgcc_s.so. dlopen in its turn calls malloc to store "libgcc_s.so" string
+// that confuses LSan on Thumb because it fails to understand that this
+// allocation happens in dynamic linker and should be ignored.
+#if !defined(__thumb__)
+static void *PthreadExit(void *a) {
+ pthread_exit(0);
+ return 0;
+}
+
+TEST(AddressSanitizer, PthreadExitTest) {
+ pthread_t t;
+ for (int i = 0; i < 1000; i++) {
+ PTHREAD_CREATE(&t, 0, PthreadExit, 0);
+ PTHREAD_JOIN(t, 0);
+ }
+}
+#endif
+
+// FIXME: Why does clang-cl define __EXCEPTIONS?
+#if defined(__EXCEPTIONS) && !defined(_WIN32)
+NOINLINE static void StackReuseAndException() {
+ int large_stack[1000];
+ Ident(large_stack);
+ ASAN_THROW(1);
+}
+
+// TODO(kcc): support exceptions with use-after-return.
+TEST(AddressSanitizer, DISABLED_StressStackReuseAndExceptionsTest) {
+ for (int i = 0; i < 10000; i++) {
+ try {
+ StackReuseAndException();
+ } catch(...) {
+ }
+ }
+}
+#endif
+
+#if !defined(_WIN32)
+TEST(AddressSanitizer, MlockTest) {
+ EXPECT_EQ(0, mlockall(MCL_CURRENT));
+ EXPECT_EQ(0, mlock((void*)0x12345, 0x5678));
+ EXPECT_EQ(0, munlockall());
+ EXPECT_EQ(0, munlock((void*)0x987, 0x654));
+}
+#endif
+
+struct LargeStruct {
+ int foo[100];
+};
+
+// Test for bug http://llvm.org/bugs/show_bug.cgi?id=11763.
+// Struct copy should not cause asan warning even if lhs == rhs.
+TEST(AddressSanitizer, LargeStructCopyTest) {
+ LargeStruct a;
+ *Ident(&a) = *Ident(&a);
+}
+
+ATTRIBUTE_NO_SANITIZE_ADDRESS
+static void NoSanitizeAddress() {
+ char *foo = new char[10];
+ Ident(foo)[10] = 0;
+ delete [] foo;
+}
+
+TEST(AddressSanitizer, AttributeNoSanitizeAddressTest) {
+ Ident(NoSanitizeAddress)();
+}
+
+// The new/delete/etc mismatch checks don't work on Android,
+// as calls to new/delete go through malloc/free.
+// OS X support is tracked here:
+// https://github.com/google/sanitizers/issues/131
+// Windows support is tracked here:
+// https://github.com/google/sanitizers/issues/309
+#if !defined(__ANDROID__) && \
+ !defined(__APPLE__) && \
+ !defined(_WIN32)
+static string MismatchStr(const string &str) {
+ return string("AddressSanitizer: alloc-dealloc-mismatch \\(") + str;
+}
+
+static string MismatchOrNewDeleteTypeStr(const string &mismatch_str) {
+ return "(" + MismatchStr(mismatch_str) +
+ ")|(AddressSanitizer: new-delete-type-mismatch)";
+}
+
+TEST(AddressSanitizer, AllocDeallocMismatch) {
+ EXPECT_DEATH(free(Ident(new int)),
+ MismatchStr("operator new vs free"));
+ EXPECT_DEATH(free(Ident(new int[2])),
+ MismatchStr("operator new \\[\\] vs free"));
+ EXPECT_DEATH(
+ delete (Ident(new int[2])),
+ MismatchOrNewDeleteTypeStr("operator new \\[\\] vs operator delete"));
+ EXPECT_DEATH(delete (Ident((int *)malloc(2 * sizeof(int)))),
+ MismatchOrNewDeleteTypeStr("malloc vs operator delete"));
+ EXPECT_DEATH(delete [] (Ident(new int)),
+ MismatchStr("operator new vs operator delete \\[\\]"));
+ EXPECT_DEATH(delete [] (Ident((int*)malloc(2 * sizeof(int)))),
+ MismatchStr("malloc vs operator delete \\[\\]"));
+}
+#endif
+
+// ------------------ demo tests; run each one-by-one -------------
+// e.g. --gtest_filter=*DemoOOBLeftHigh --gtest_also_run_disabled_tests
+TEST(AddressSanitizer, DISABLED_DemoThreadedTest) {
+ ThreadedTestSpawn();
+}
+
+void *SimpleBugOnSTack(void *x = 0) {
+ char a[20];
+ Ident(a)[20] = 0;
+ return 0;
+}
+
+TEST(AddressSanitizer, DISABLED_DemoStackTest) {
+ SimpleBugOnSTack();
+}
+
+TEST(AddressSanitizer, DISABLED_DemoThreadStackTest) {
+ pthread_t t;
+ PTHREAD_CREATE(&t, 0, SimpleBugOnSTack, 0);
+ PTHREAD_JOIN(t, 0);
+}
+
+TEST(AddressSanitizer, DISABLED_DemoUAFLowIn) {
+ uaf_test<U1>(10, 0);
+}
+TEST(AddressSanitizer, DISABLED_DemoUAFLowLeft) {
+ uaf_test<U1>(10, -2);
+}
+TEST(AddressSanitizer, DISABLED_DemoUAFLowRight) {
+ uaf_test<U1>(10, 10);
+}
+
+TEST(AddressSanitizer, DISABLED_DemoUAFHigh) {
+ uaf_test<U1>(kLargeMalloc, 0);
+}
+
+TEST(AddressSanitizer, DISABLED_DemoOOM) {
+ size_t size = SANITIZER_WORDSIZE == 64 ? (size_t)(1ULL << 40) : (0xf0000000);
+ printf("%p\n", malloc(size));
+}
+
+TEST(AddressSanitizer, DISABLED_DemoDoubleFreeTest) {
+ DoubleFree();
+}
+
+TEST(AddressSanitizer, DISABLED_DemoNullDerefTest) {
+ int *a = 0;
+ Ident(a)[10] = 0;
+}
+
+TEST(AddressSanitizer, DISABLED_DemoFunctionStaticTest) {
+ static char a[100];
+ static char b[100];
+ static char c[100];
+ Ident(a);
+ Ident(b);
+ Ident(c);
+ Ident(a)[5] = 0;
+ Ident(b)[105] = 0;
+ Ident(a)[5] = 0;
+}
+
+TEST(AddressSanitizer, DISABLED_DemoTooMuchMemoryTest) {
+ const size_t kAllocSize = (1 << 28) - 1024;
+ size_t total_size = 0;
+ while (true) {
+ void *x = malloc(kAllocSize);
+ memset(x, 0, kAllocSize);
+ total_size += kAllocSize;
+ fprintf(stderr, "total: %ldM %p\n", (long)total_size >> 20, x);
+ }
+}
+
+#if !defined(__NetBSD__) && !defined(__i386__)
+// https://github.com/google/sanitizers/issues/66
+TEST(AddressSanitizer, BufferOverflowAfterManyFrees) {
+ for (int i = 0; i < 1000000; i++) {
+ delete [] (Ident(new char [8644]));
+ }
+ char *x = new char[8192];
+ EXPECT_DEATH(x[Ident(8192)] = 0, "AddressSanitizer: heap-buffer-overflow");
+ delete [] Ident(x);
+}
+#endif
+
+
+// Test that instrumentation of stack allocations takes into account
+// AllocSize of a type, and not its StoreSize (16 vs 10 bytes for long double).
+// See http://llvm.org/bugs/show_bug.cgi?id=12047 for more details.
+TEST(AddressSanitizer, LongDoubleNegativeTest) {
+ long double a, b;
+ static long double c;
+ memcpy(Ident(&a), Ident(&b), sizeof(long double));
+ memcpy(Ident(&c), Ident(&b), sizeof(long double));
+}
+
+#if !defined(_WIN32)
+TEST(AddressSanitizer, pthread_getschedparam) {
+ int policy;
+ struct sched_param param;
+ EXPECT_DEATH(
+ pthread_getschedparam(pthread_self(), &policy, Ident(¶m) + 2),
+ "AddressSanitizer: stack-buffer-.*flow");
+ EXPECT_DEATH(
+ pthread_getschedparam(pthread_self(), Ident(&policy) - 1, ¶m),
+ "AddressSanitizer: stack-buffer-.*flow");
+ int res = pthread_getschedparam(pthread_self(), &policy, ¶m);
+ ASSERT_EQ(0, res);
+}
+#endif
+
+#if SANITIZER_TEST_HAS_PRINTF_L
+static int vsnprintf_l_wrapper(char *s, size_t n,
+ locale_t l, const char *format, ...) {
+ va_list va;
+ va_start(va, format);
+ int res = vsnprintf_l(s, n , l, format, va);
+ va_end(va);
+ return res;
+}
+
+TEST(AddressSanitizer, snprintf_l) {
+ char buff[5];
+ // Check that snprintf_l() works fine with Asan.
+ int res = snprintf_l(buff, 5, SANITIZER_GET_C_LOCALE, "%s", "snprintf_l()");
+ EXPECT_EQ(12, res);
+ // Check that vsnprintf_l() works fine with Asan.
+ res = vsnprintf_l_wrapper(buff, 5, SANITIZER_GET_C_LOCALE, "%s",
+ "vsnprintf_l()");
+ EXPECT_EQ(13, res);
+
+ EXPECT_DEATH(
+ snprintf_l(buff, 10, SANITIZER_GET_C_LOCALE, "%s", "snprintf_l()"),
+ "AddressSanitizer: stack-buffer-overflow");
+ EXPECT_DEATH(vsnprintf_l_wrapper(buff, 10, SANITIZER_GET_C_LOCALE, "%s",
+ "vsnprintf_l()"),
+ "AddressSanitizer: stack-buffer-overflow");
+}
+#endif
+++ /dev/null
-//===-- asan_test_main.cc -------------------------------------------------===//
-//
-// 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
-//
-//===----------------------------------------------------------------------===//
-//
-// This file is a part of AddressSanitizer, an address sanity checker.
-//
-//===----------------------------------------------------------------------===//
-#include "asan_test_utils.h"
-#include "sanitizer_common/sanitizer_platform.h"
-
-// Default ASAN_OPTIONS for the unit tests.
-extern "C" const char* __asan_default_options() {
-#if SANITIZER_MAC
- // On Darwin, we default to `abort_on_error=1`, which would make tests run
- // much slower. Let's override this and run lit tests with 'abort_on_error=0'
- // and make sure we do not overwhelm the syslog while testing. Also, let's
- // turn symbolization off to speed up testing, especially when not running
- // with llvm-symbolizer but with atos.
- return "symbolize=false:abort_on_error=0:log_to_syslog=0";
-#elif SANITIZER_SUPPRESS_LEAK_ON_PTHREAD_EXIT
- // On PowerPC and ARM Thumb, a couple tests involving pthread_exit fail due to
- // leaks detected by LSan. Symbolized leak report is required to apply a
- // suppression for this known problem.
- return "";
-#else
- // Let's turn symbolization off to speed up testing (more than 3 times speedup
- // observed).
- return "symbolize=false";
-#endif
-}
-
-namespace __sanitizer {
-bool ReexecDisabled() {
-#if __has_feature(address_sanitizer) && SANITIZER_MAC
- // Allow re-exec in instrumented unit tests on Darwin. Technically, we only
- // need this for 10.10 and below, where re-exec is required for the
- // interceptors to work, but to avoid duplicating the version detection logic,
- // let's just allow re-exec for all Darwin versions. On newer OS versions,
- // returning 'false' doesn't do anything anyway, because we don't re-exec.
- return false;
-#else
- return true;
-#endif
-}
-} // namespace __sanitizer
-
-int main(int argc, char **argv) {
- testing::GTEST_FLAG(death_test_style) = "threadsafe";
- testing::InitGoogleTest(&argc, argv);
- return RUN_ALL_TESTS();
-}
--- /dev/null
+//===-- asan_test_main.cpp ------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a part of AddressSanitizer, an address sanity checker.
+//
+//===----------------------------------------------------------------------===//
+#include "asan_test_utils.h"
+#include "sanitizer_common/sanitizer_platform.h"
+
+// Default ASAN_OPTIONS for the unit tests.
+extern "C" const char* __asan_default_options() {
+#if SANITIZER_MAC
+ // On Darwin, we default to `abort_on_error=1`, which would make tests run
+ // much slower. Let's override this and run lit tests with 'abort_on_error=0'
+ // and make sure we do not overwhelm the syslog while testing. Also, let's
+ // turn symbolization off to speed up testing, especially when not running
+ // with llvm-symbolizer but with atos.
+ return "symbolize=false:abort_on_error=0:log_to_syslog=0";
+#elif SANITIZER_SUPPRESS_LEAK_ON_PTHREAD_EXIT
+ // On PowerPC and ARM Thumb, a couple tests involving pthread_exit fail due to
+ // leaks detected by LSan. Symbolized leak report is required to apply a
+ // suppression for this known problem.
+ return "";
+#else
+ // Let's turn symbolization off to speed up testing (more than 3 times speedup
+ // observed).
+ return "symbolize=false";
+#endif
+}
+
+namespace __sanitizer {
+bool ReexecDisabled() {
+#if __has_feature(address_sanitizer) && SANITIZER_MAC
+ // Allow re-exec in instrumented unit tests on Darwin. Technically, we only
+ // need this for 10.10 and below, where re-exec is required for the
+ // interceptors to work, but to avoid duplicating the version detection logic,
+ // let's just allow re-exec for all Darwin versions. On newer OS versions,
+ // returning 'false' doesn't do anything anyway, because we don't re-exec.
+ return false;
+#else
+ return true;
+#endif
+}
+} // namespace __sanitizer
+
+int main(int argc, char **argv) {
+ testing::GTEST_FLAG(death_test_style) = "threadsafe";
+ testing::InitGoogleTest(&argc, argv);
+ return RUN_ALL_TESTS();
+}
ASAN_RTL=${COMPILER_RT}/lib/asan
run_lint ${ASAN_RTL_LINT_FILTER} ${ASAN_RTL}/*.cpp \
${ASAN_RTL}/*.h &
-run_lint ${ASAN_TEST_LINT_FILTER} ${ASAN_RTL}/tests/*.cc \
+run_lint ${ASAN_TEST_LINT_FILTER} ${ASAN_RTL}/tests/*.cpp \
${ASAN_RTL}/tests/*.h &
run_lint ${ASAN_LIT_TEST_LINT_FILTER} ${LIT_TESTS}/asan/*/*.cc &