1 //===-- wrappers_c_test.cpp -------------------------------------*- C++ -*-===// 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 #include "platform.h" 10 11 #include "gtest/gtest.h" 12 13 #include <limits.h> 14 #include <malloc.h> 15 #include <stdlib.h> 16 #include <unistd.h> 17 18 extern "C" { 19 void malloc_enable(void); 20 void malloc_disable(void); 21 int malloc_iterate(uintptr_t base, size_t size, 22 void (*callback)(uintptr_t base, size_t size, void *arg), 23 void *arg); 24 } 25 26 // Note that every C allocation function in the test binary will be fulfilled 27 // by Scudo (this includes the gtest APIs, etc.), which is a test by itself. 28 // But this might also lead to unexpected side-effects, since the allocation and 29 // deallocation operations in the TEST functions will coexist with others (see 30 // the EXPECT_DEATH comment below). 31 32 // We have to use a small quarantine to make sure that our double-free tests 33 // trigger. Otherwise EXPECT_DEATH ends up reallocating the chunk that was just 34 // freed (this depends on the size obviously) and the following free succeeds. 35 extern "C" __attribute__((visibility("default"))) const char * 36 __scudo_default_options() { 37 return "quarantine_size_kb=256:thread_local_quarantine_size_kb=128:" 38 "quarantine_max_chunk_size=512"; 39 } 40 41 static const size_t Size = 100U; 42 43 TEST(ScudoWrappersCTest, Malloc) { 44 void *P = malloc(Size); 45 EXPECT_NE(P, nullptr); 46 EXPECT_LE(Size, malloc_usable_size(P)); 47 EXPECT_EQ(reinterpret_cast<uintptr_t>(P) % FIRST_32_SECOND_64(8U, 16U), 0U); 48 EXPECT_DEATH( 49 free(reinterpret_cast<void *>(reinterpret_cast<uintptr_t>(P) | 1U)), ""); 50 free(P); 51 EXPECT_DEATH(free(P), ""); 52 53 P = malloc(0U); 54 EXPECT_NE(P, nullptr); 55 free(P); 56 57 errno = 0; 58 EXPECT_EQ(malloc(SIZE_MAX), nullptr); 59 EXPECT_EQ(errno, ENOMEM); 60 } 61 62 TEST(ScudoWrappersCTest, Calloc) { 63 void *P = calloc(1U, Size); 64 EXPECT_NE(P, nullptr); 65 EXPECT_LE(Size, malloc_usable_size(P)); 66 for (size_t I = 0; I < Size; I++) 67 EXPECT_EQ((reinterpret_cast<uint8_t *>(P))[I], 0U); 68 free(P); 69 70 P = calloc(1U, 0U); 71 EXPECT_NE(P, nullptr); 72 free(P); 73 P = calloc(0U, 1U); 74 EXPECT_NE(P, nullptr); 75 free(P); 76 77 errno = 0; 78 EXPECT_EQ(calloc(SIZE_MAX, 1U), nullptr); 79 EXPECT_EQ(errno, ENOMEM); 80 errno = 0; 81 EXPECT_EQ(calloc(static_cast<size_t>(LONG_MAX) + 1U, 2U), nullptr); 82 if (SCUDO_ANDROID) 83 EXPECT_EQ(errno, ENOMEM); 84 errno = 0; 85 EXPECT_EQ(calloc(SIZE_MAX, SIZE_MAX), nullptr); 86 EXPECT_EQ(errno, ENOMEM); 87 } 88 89 TEST(ScudoWrappersCTest, Memalign) { 90 void *P; 91 for (size_t I = FIRST_32_SECOND_64(2U, 3U); I <= 18U; I++) { 92 const size_t Alignment = 1U << I; 93 94 P = memalign(Alignment, Size); 95 EXPECT_NE(P, nullptr); 96 EXPECT_LE(Size, malloc_usable_size(P)); 97 EXPECT_EQ(reinterpret_cast<uintptr_t>(P) % Alignment, 0U); 98 free(P); 99 100 P = nullptr; 101 EXPECT_EQ(posix_memalign(&P, Alignment, Size), 0); 102 EXPECT_NE(P, nullptr); 103 EXPECT_LE(Size, malloc_usable_size(P)); 104 EXPECT_EQ(reinterpret_cast<uintptr_t>(P) % Alignment, 0U); 105 free(P); 106 } 107 108 EXPECT_EQ(memalign(4096U, SIZE_MAX), nullptr); 109 EXPECT_EQ(posix_memalign(&P, 15U, Size), EINVAL); 110 EXPECT_EQ(posix_memalign(&P, 4096U, SIZE_MAX), ENOMEM); 111 112 // Android's memalign accepts non power-of-2 alignments, and 0. 113 if (SCUDO_ANDROID) { 114 for (size_t Alignment = 0U; Alignment <= 128U; Alignment++) { 115 P = memalign(Alignment, 1024U); 116 EXPECT_NE(P, nullptr); 117 free(P); 118 } 119 } 120 } 121 122 TEST(ScudoWrappersCTest, AlignedAlloc) { 123 const size_t Alignment = 4096U; 124 void *P = aligned_alloc(Alignment, Alignment * 4U); 125 EXPECT_NE(P, nullptr); 126 EXPECT_LE(Alignment * 4U, malloc_usable_size(P)); 127 EXPECT_EQ(reinterpret_cast<uintptr_t>(P) % Alignment, 0U); 128 free(P); 129 130 errno = 0; 131 P = aligned_alloc(Alignment, Size); 132 EXPECT_EQ(P, nullptr); 133 EXPECT_EQ(errno, EINVAL); 134 } 135 136 TEST(ScudoWrappersCTest, Realloc) { 137 // realloc(nullptr, N) is malloc(N) 138 void *P = realloc(nullptr, 0U); 139 EXPECT_NE(P, nullptr); 140 free(P); 141 142 P = malloc(Size); 143 EXPECT_NE(P, nullptr); 144 // realloc(P, 0U) is free(P) and returns nullptr 145 EXPECT_EQ(realloc(P, 0U), nullptr); 146 147 P = malloc(Size); 148 EXPECT_NE(P, nullptr); 149 EXPECT_LE(Size, malloc_usable_size(P)); 150 memset(P, 0x42, Size); 151 152 P = realloc(P, Size * 2U); 153 EXPECT_NE(P, nullptr); 154 EXPECT_LE(Size * 2U, malloc_usable_size(P)); 155 for (size_t I = 0; I < Size; I++) 156 EXPECT_EQ(0x42, (reinterpret_cast<uint8_t *>(P))[I]); 157 158 P = realloc(P, Size / 2U); 159 EXPECT_NE(P, nullptr); 160 EXPECT_LE(Size / 2U, malloc_usable_size(P)); 161 for (size_t I = 0; I < Size / 2U; I++) 162 EXPECT_EQ(0x42, (reinterpret_cast<uint8_t *>(P))[I]); 163 free(P); 164 165 EXPECT_DEATH(P = realloc(P, Size), ""); 166 167 errno = 0; 168 EXPECT_EQ(realloc(nullptr, SIZE_MAX), nullptr); 169 EXPECT_EQ(errno, ENOMEM); 170 P = malloc(Size); 171 EXPECT_NE(P, nullptr); 172 errno = 0; 173 EXPECT_EQ(realloc(P, SIZE_MAX), nullptr); 174 EXPECT_EQ(errno, ENOMEM); 175 free(P); 176 177 // Android allows realloc of memalign pointers. 178 if (SCUDO_ANDROID) { 179 const size_t Alignment = 1024U; 180 P = memalign(Alignment, Size); 181 EXPECT_NE(P, nullptr); 182 EXPECT_LE(Size, malloc_usable_size(P)); 183 EXPECT_EQ(reinterpret_cast<uintptr_t>(P) % Alignment, 0U); 184 memset(P, 0x42, Size); 185 186 P = realloc(P, Size * 2U); 187 EXPECT_NE(P, nullptr); 188 EXPECT_LE(Size * 2U, malloc_usable_size(P)); 189 for (size_t I = 0; I < Size; I++) 190 EXPECT_EQ(0x42, (reinterpret_cast<uint8_t *>(P))[I]); 191 free(P); 192 } 193 } 194 195 #ifndef M_DECAY_TIME 196 #define M_DECAY_TIME -100 197 #endif 198 199 #ifndef M_PURGE 200 #define M_PURGE -101 201 #endif 202 203 TEST(ScudoWrappersCTest, MallOpt) { 204 errno = 0; 205 EXPECT_EQ(mallopt(-1000, 1), 0); 206 // mallopt doesn't set errno. 207 EXPECT_EQ(errno, 0); 208 209 EXPECT_EQ(mallopt(M_PURGE, 0), 1); 210 211 EXPECT_EQ(mallopt(M_DECAY_TIME, 1), 1); 212 EXPECT_EQ(mallopt(M_DECAY_TIME, 0), 1); 213 EXPECT_EQ(mallopt(M_DECAY_TIME, 1), 1); 214 EXPECT_EQ(mallopt(M_DECAY_TIME, 0), 1); 215 } 216 217 TEST(ScudoWrappersCTest, OtherAlloc) { 218 const size_t PageSize = sysconf(_SC_PAGESIZE); 219 220 void *P = pvalloc(Size); 221 EXPECT_NE(P, nullptr); 222 EXPECT_EQ(reinterpret_cast<uintptr_t>(P) & (PageSize - 1), 0U); 223 EXPECT_LE(PageSize, malloc_usable_size(P)); 224 free(P); 225 226 EXPECT_EQ(pvalloc(SIZE_MAX), nullptr); 227 228 P = pvalloc(Size); 229 EXPECT_NE(P, nullptr); 230 EXPECT_EQ(reinterpret_cast<uintptr_t>(P) & (PageSize - 1), 0U); 231 free(P); 232 233 EXPECT_EQ(valloc(SIZE_MAX), nullptr); 234 } 235 236 TEST(ScudoWrappersCTest, MallInfo) { 237 const size_t BypassQuarantineSize = 1024U; 238 239 struct mallinfo MI = mallinfo(); 240 size_t Allocated = MI.uordblks; 241 void *P = malloc(BypassQuarantineSize); 242 EXPECT_NE(P, nullptr); 243 MI = mallinfo(); 244 EXPECT_GE(static_cast<size_t>(MI.uordblks), Allocated + BypassQuarantineSize); 245 EXPECT_GT(static_cast<size_t>(MI.hblkhd), 0U); 246 size_t Free = MI.fordblks; 247 free(P); 248 MI = mallinfo(); 249 EXPECT_GE(static_cast<size_t>(MI.fordblks), Free + BypassQuarantineSize); 250 } 251 252 static uintptr_t BoundaryP; 253 static size_t Count; 254 255 static void callback(uintptr_t Base, size_t Size, void *Arg) { 256 if (Base == BoundaryP) 257 Count++; 258 } 259 260 // Verify that a block located on an iteration boundary is not mis-accounted. 261 // To achieve this, we allocate a chunk for which the backing block will be 262 // aligned on a page, then run the malloc_iterate on both the pages that the 263 // block is a boundary for. It must only be seen once by the callback function. 264 TEST(ScudoWrappersCTest, MallocIterateBoundary) { 265 const size_t PageSize = sysconf(_SC_PAGESIZE); 266 const size_t BlockDelta = FIRST_32_SECOND_64(8U, 16U); 267 const size_t SpecialSize = PageSize - BlockDelta; 268 269 void *P = malloc(SpecialSize); 270 EXPECT_NE(P, nullptr); 271 BoundaryP = reinterpret_cast<uintptr_t>(P); 272 const uintptr_t Block = BoundaryP - BlockDelta; 273 EXPECT_EQ((Block & (PageSize - 1)), 0U); 274 275 Count = 0U; 276 malloc_disable(); 277 malloc_iterate(Block - PageSize, PageSize, callback, nullptr); 278 malloc_iterate(Block, PageSize, callback, nullptr); 279 malloc_enable(); 280 EXPECT_EQ(Count, 1U); 281 282 free(P); 283 } 284 285 TEST(ScudoWrappersCTest, MallocInfo) { 286 char Buffer[64]; 287 FILE *F = fmemopen(Buffer, sizeof(Buffer), "w+"); 288 EXPECT_NE(F, nullptr); 289 errno = 0; 290 EXPECT_EQ(malloc_info(0, F), 0); 291 EXPECT_EQ(errno, 0); 292 fclose(F); 293 EXPECT_EQ(strncmp(Buffer, "<malloc version=\"scudo-", 23), 0); 294 } 295