| 1 | //===-- tsan_mman_test.cpp ------------------------------------------------===// |
| 2 | // |
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
| 4 | // See https://llvm.org/LICENSE.txt for license information. |
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
| 6 | // |
| 7 | //===----------------------------------------------------------------------===// |
| 8 | // |
| 9 | // This file is a part of ThreadSanitizer (TSan), a race detector. |
| 10 | // |
| 11 | //===----------------------------------------------------------------------===// |
| 12 | #include <limits> |
| 13 | #include <sanitizer/allocator_interface.h> |
| 14 | #include "tsan_mman.h" |
| 15 | #include "tsan_rtl.h" |
| 16 | #include "gtest/gtest.h" |
| 17 | |
| 18 | namespace __tsan { |
| 19 | |
| 20 | TEST(Mman, Internal) { |
| 21 | char *p = (char *)Alloc(10); |
| 22 | EXPECT_NE(p, (char*)0); |
| 23 | char *p2 = (char *)Alloc(20); |
| 24 | EXPECT_NE(p2, (char*)0); |
| 25 | EXPECT_NE(p2, p); |
| 26 | for (int i = 0; i < 10; i++) { |
| 27 | p[i] = 42; |
| 28 | } |
| 29 | for (int i = 0; i < 20; i++) { |
| 30 | ((char*)p2)[i] = 42; |
| 31 | } |
| 32 | Free(p); |
| 33 | Free(p2); |
| 34 | } |
| 35 | |
| 36 | TEST(Mman, User) { |
| 37 | ThreadState *thr = cur_thread(); |
| 38 | uptr pc = 0; |
| 39 | char *p = (char*)user_alloc(thr, pc, 10); |
| 40 | EXPECT_NE(p, (char*)0); |
| 41 | char *p2 = (char*)user_alloc(thr, pc, 20); |
| 42 | EXPECT_NE(p2, (char*)0); |
| 43 | EXPECT_NE(p2, p); |
| 44 | EXPECT_EQ(10U, user_alloc_usable_size(p)); |
| 45 | EXPECT_EQ(20U, user_alloc_usable_size(p2)); |
| 46 | user_free(thr, pc, p); |
| 47 | user_free(thr, pc, p2); |
| 48 | } |
| 49 | |
| 50 | TEST(Mman, UserRealloc) { |
| 51 | ThreadState *thr = cur_thread(); |
| 52 | uptr pc = 0; |
| 53 | { |
| 54 | void *p = user_realloc(thr, pc, 0, 0); |
| 55 | // Realloc(NULL, N) is equivalent to malloc(N), thus must return |
| 56 | // non-NULL pointer. |
| 57 | EXPECT_NE(p, (void*)0); |
| 58 | user_free(thr, pc, p); |
| 59 | } |
| 60 | { |
| 61 | void *p = user_realloc(thr, pc, 0, 100); |
| 62 | EXPECT_NE(p, (void*)0); |
| 63 | memset(p, 0xde, 100); |
| 64 | user_free(thr, pc, p); |
| 65 | } |
| 66 | { |
| 67 | void *p = user_alloc(thr, pc, 100); |
| 68 | EXPECT_NE(p, (void*)0); |
| 69 | memset(p, 0xde, 100); |
| 70 | // Realloc(P, 0) is equivalent to free(P) and returns NULL. |
| 71 | void *p2 = user_realloc(thr, pc, p, 0); |
| 72 | EXPECT_EQ(p2, (void*)0); |
| 73 | } |
| 74 | { |
| 75 | void *p = user_realloc(thr, pc, 0, 100); |
| 76 | EXPECT_NE(p, (void*)0); |
| 77 | memset(p, 0xde, 100); |
| 78 | void *p2 = user_realloc(thr, pc, p, 10000); |
| 79 | EXPECT_NE(p2, (void*)0); |
| 80 | for (int i = 0; i < 100; i++) |
| 81 | EXPECT_EQ(((char*)p2)[i], (char)0xde); |
| 82 | memset(p2, 0xde, 10000); |
| 83 | user_free(thr, pc, p2); |
| 84 | } |
| 85 | { |
| 86 | void *p = user_realloc(thr, pc, 0, 10000); |
| 87 | EXPECT_NE(p, (void*)0); |
| 88 | memset(p, 0xde, 10000); |
| 89 | void *p2 = user_realloc(thr, pc, p, 10); |
| 90 | EXPECT_NE(p2, (void*)0); |
| 91 | for (int i = 0; i < 10; i++) |
| 92 | EXPECT_EQ(((char*)p2)[i], (char)0xde); |
| 93 | user_free(thr, pc, p2); |
| 94 | } |
| 95 | } |
| 96 | |
| 97 | TEST(Mman, UsableSize) { |
| 98 | ThreadState *thr = cur_thread(); |
| 99 | uptr pc = 0; |
| 100 | char *p = (char*)user_alloc(thr, pc, 10); |
| 101 | char *p2 = (char*)user_alloc(thr, pc, 20); |
| 102 | EXPECT_EQ(0U, user_alloc_usable_size(NULL)); |
| 103 | EXPECT_EQ(10U, user_alloc_usable_size(p)); |
| 104 | EXPECT_EQ(20U, user_alloc_usable_size(p2)); |
| 105 | user_free(thr, pc, p); |
| 106 | user_free(thr, pc, p2); |
| 107 | EXPECT_EQ(0U, user_alloc_usable_size((void*)0x4123)); |
| 108 | } |
| 109 | |
| 110 | TEST(Mman, Stats) { |
| 111 | ThreadState *thr = cur_thread(); |
| 112 | |
| 113 | uptr alloc0 = __sanitizer_get_current_allocated_bytes(); |
| 114 | uptr heap0 = __sanitizer_get_heap_size(); |
| 115 | uptr free0 = __sanitizer_get_free_bytes(); |
| 116 | uptr unmapped0 = __sanitizer_get_unmapped_bytes(); |
| 117 | |
| 118 | EXPECT_EQ(10U, __sanitizer_get_estimated_allocated_size(size: 10)); |
| 119 | EXPECT_EQ(20U, __sanitizer_get_estimated_allocated_size(size: 20)); |
| 120 | EXPECT_EQ(100U, __sanitizer_get_estimated_allocated_size(size: 100)); |
| 121 | |
| 122 | char *p = (char*)user_alloc(thr, 0, 10); |
| 123 | EXPECT_TRUE(__sanitizer_get_ownership(p)); |
| 124 | EXPECT_EQ(10U, __sanitizer_get_allocated_size(p)); |
| 125 | |
| 126 | EXPECT_EQ(alloc0 + 16, __sanitizer_get_current_allocated_bytes()); |
| 127 | EXPECT_GE(__sanitizer_get_heap_size(), heap0); |
| 128 | EXPECT_EQ(free0, __sanitizer_get_free_bytes()); |
| 129 | EXPECT_EQ(unmapped0, __sanitizer_get_unmapped_bytes()); |
| 130 | |
| 131 | user_free(thr, 0, p); |
| 132 | |
| 133 | EXPECT_EQ(alloc0, __sanitizer_get_current_allocated_bytes()); |
| 134 | EXPECT_GE(__sanitizer_get_heap_size(), heap0); |
| 135 | EXPECT_EQ(free0, __sanitizer_get_free_bytes()); |
| 136 | EXPECT_EQ(unmapped0, __sanitizer_get_unmapped_bytes()); |
| 137 | } |
| 138 | |
| 139 | TEST(Mman, Valloc) { |
| 140 | ThreadState *thr = cur_thread(); |
| 141 | uptr page_size = GetPageSizeCached(); |
| 142 | |
| 143 | void *p = user_valloc(thr, 0, 100); |
| 144 | EXPECT_NE(p, (void*)0); |
| 145 | user_free(thr, 0, p); |
| 146 | |
| 147 | p = user_pvalloc(thr, 0, 100); |
| 148 | EXPECT_NE(p, (void*)0); |
| 149 | user_free(thr, 0, p); |
| 150 | |
| 151 | p = user_pvalloc(thr, 0, 0); |
| 152 | EXPECT_NE(p, (void*)0); |
| 153 | EXPECT_EQ(page_size, __sanitizer_get_allocated_size(p)); |
| 154 | user_free(thr, 0, p); |
| 155 | } |
| 156 | |
| 157 | #if !SANITIZER_DEBUG |
| 158 | // EXPECT_DEATH clones a thread with 4K stack, |
| 159 | // which is overflown by tsan memory accesses functions in debug mode. |
| 160 | |
| 161 | TEST(Mman, Memalign) { |
| 162 | ThreadState *thr = cur_thread(); |
| 163 | |
| 164 | void *p = user_memalign(thr, 0, 8, 100); |
| 165 | EXPECT_NE(p, (void*)0); |
| 166 | user_free(thr, 0, p); |
| 167 | |
| 168 | // TODO(alekseyshl): Remove this death test when memalign is verified by |
| 169 | // tests in sanitizer_common. |
| 170 | p = NULL; |
| 171 | EXPECT_DEATH(p = user_memalign(thr, 0, 7, 100), |
| 172 | "invalid-allocation-alignment" ); |
| 173 | EXPECT_EQ(0L, p); |
| 174 | } |
| 175 | |
| 176 | #endif |
| 177 | |
| 178 | TEST(Mman, PosixMemalign) { |
| 179 | ThreadState *thr = cur_thread(); |
| 180 | |
| 181 | void *p = NULL; |
| 182 | int res = user_posix_memalign(thr, 0, &p, 8, 100); |
| 183 | EXPECT_NE(p, (void*)0); |
| 184 | EXPECT_EQ(res, 0); |
| 185 | user_free(thr, 0, p); |
| 186 | } |
| 187 | |
| 188 | TEST(Mman, AlignedAlloc) { |
| 189 | ThreadState *thr = cur_thread(); |
| 190 | |
| 191 | void *p = user_aligned_alloc(thr, 0, 8, 64); |
| 192 | EXPECT_NE(p, (void*)0); |
| 193 | user_free(thr, 0, p); |
| 194 | } |
| 195 | |
| 196 | } // namespace __tsan |
| 197 | |