github.com/prysmaticlabs/prysm@v1.4.4/third_party/afl/alloc-inl.h (about) 1 /* 2 american fuzzy lop - error-checking, memory-zeroing alloc routines 3 ------------------------------------------------------------------ 4 5 Written and maintained by Michal Zalewski <lcamtuf@google.com> 6 7 Copyright 2013, 2014, 2015 Google Inc. All rights reserved. 8 9 Licensed under the Apache License, Version 2.0 (the "License"); 10 you may not use this file except in compliance with the License. 11 You may obtain a copy of the License at: 12 13 http://www.apache.org/licenses/LICENSE-2.0 14 15 This allocator is not designed to resist malicious attackers (the canaries 16 are small and predictable), but provides a robust and portable way to detect 17 use-after-free, off-by-one writes, stale pointers, and so on. 18 19 */ 20 21 #ifndef _HAVE_ALLOC_INL_H 22 #define _HAVE_ALLOC_INL_H 23 24 #include <stdio.h> 25 #include <stdlib.h> 26 #include <string.h> 27 28 #include "config.h" 29 #include "types.h" 30 #include "debug.h" 31 32 /* User-facing macro to sprintf() to a dynamically allocated buffer. */ 33 34 #define alloc_printf(_str...) ({ \ 35 u8* _tmp; \ 36 s32 _len = snprintf(NULL, 0, _str); \ 37 if (_len < 0) FATAL("Whoa, snprintf() fails?!"); \ 38 _tmp = ck_alloc(_len + 1); \ 39 snprintf((char*)_tmp, _len + 1, _str); \ 40 _tmp; \ 41 }) 42 43 /* Macro to enforce allocation limits as a last-resort defense against 44 integer overflows. */ 45 46 #define ALLOC_CHECK_SIZE(_s) do { \ 47 if ((_s) > MAX_ALLOC) \ 48 ABORT("Bad alloc request: %u bytes", (_s)); \ 49 } while (0) 50 51 /* Macro to check malloc() failures and the like. */ 52 53 #define ALLOC_CHECK_RESULT(_r, _s) do { \ 54 if (!(_r)) \ 55 ABORT("Out of memory: can't allocate %u bytes", (_s)); \ 56 } while (0) 57 58 /* Magic tokens used to mark used / freed chunks. */ 59 60 #define ALLOC_MAGIC_C1 0xFF00FF00 /* Used head (dword) */ 61 #define ALLOC_MAGIC_F 0xFE00FE00 /* Freed head (dword) */ 62 #define ALLOC_MAGIC_C2 0xF0 /* Used tail (byte) */ 63 64 /* Positions of guard tokens in relation to the user-visible pointer. */ 65 66 #define ALLOC_C1(_ptr) (((u32*)(_ptr))[-2]) 67 #define ALLOC_S(_ptr) (((u32*)(_ptr))[-1]) 68 #define ALLOC_C2(_ptr) (((u8*)(_ptr))[ALLOC_S(_ptr)]) 69 70 #define ALLOC_OFF_HEAD 8 71 #define ALLOC_OFF_TOTAL (ALLOC_OFF_HEAD + 1) 72 73 /* Allocator increments for ck_realloc_block(). */ 74 75 #define ALLOC_BLK_INC 256 76 77 /* Sanity-checking macros for pointers. */ 78 79 #define CHECK_PTR(_p) do { \ 80 if (_p) { \ 81 if (ALLOC_C1(_p) ^ ALLOC_MAGIC_C1) {\ 82 if (ALLOC_C1(_p) == ALLOC_MAGIC_F) \ 83 ABORT("Use after free."); \ 84 else ABORT("Corrupted head alloc canary."); \ 85 } \ 86 if (ALLOC_C2(_p) ^ ALLOC_MAGIC_C2) \ 87 ABORT("Corrupted tail alloc canary."); \ 88 } \ 89 } while (0) 90 91 #define CHECK_PTR_EXPR(_p) ({ \ 92 typeof (_p) _tmp = (_p); \ 93 CHECK_PTR(_tmp); \ 94 _tmp; \ 95 }) 96 97 98 /* Allocate a buffer, explicitly not zeroing it. Returns NULL for zero-sized 99 requests. */ 100 101 static inline void* DFL_ck_alloc_nozero(u32 size) { 102 103 void* ret; 104 105 if (!size) return NULL; 106 107 ALLOC_CHECK_SIZE(size); 108 ret = malloc(size + ALLOC_OFF_TOTAL); 109 ALLOC_CHECK_RESULT(ret, size); 110 111 ret += ALLOC_OFF_HEAD; 112 113 ALLOC_C1(ret) = ALLOC_MAGIC_C1; 114 ALLOC_S(ret) = size; 115 ALLOC_C2(ret) = ALLOC_MAGIC_C2; 116 117 return ret; 118 119 } 120 121 122 /* Allocate a buffer, returning zeroed memory. */ 123 124 static inline void* DFL_ck_alloc(u32 size) { 125 126 void* mem; 127 128 if (!size) return NULL; 129 mem = DFL_ck_alloc_nozero(size); 130 131 return memset(mem, 0, size); 132 133 } 134 135 136 /* Free memory, checking for double free and corrupted heap. When DEBUG_BUILD 137 is set, the old memory will be also clobbered with 0xFF. */ 138 139 static inline void DFL_ck_free(void* mem) { 140 141 if (!mem) return; 142 143 CHECK_PTR(mem); 144 145 #ifdef DEBUG_BUILD 146 147 /* Catch pointer issues sooner. */ 148 memset(mem, 0xFF, ALLOC_S(mem)); 149 150 #endif /* DEBUG_BUILD */ 151 152 ALLOC_C1(mem) = ALLOC_MAGIC_F; 153 154 free(mem - ALLOC_OFF_HEAD); 155 156 } 157 158 159 /* Re-allocate a buffer, checking for issues and zeroing any newly-added tail. 160 With DEBUG_BUILD, the buffer is always reallocated to a new addresses and the 161 old memory is clobbered with 0xFF. */ 162 163 static inline void* DFL_ck_realloc(void* orig, u32 size) { 164 165 void* ret; 166 u32 old_size = 0; 167 168 if (!size) { 169 170 DFL_ck_free(orig); 171 return NULL; 172 173 } 174 175 if (orig) { 176 177 CHECK_PTR(orig); 178 179 #ifndef DEBUG_BUILD 180 ALLOC_C1(orig) = ALLOC_MAGIC_F; 181 #endif /* !DEBUG_BUILD */ 182 183 old_size = ALLOC_S(orig); 184 orig -= ALLOC_OFF_HEAD; 185 186 ALLOC_CHECK_SIZE(old_size); 187 188 } 189 190 ALLOC_CHECK_SIZE(size); 191 192 #ifndef DEBUG_BUILD 193 194 ret = realloc(orig, size + ALLOC_OFF_TOTAL); 195 ALLOC_CHECK_RESULT(ret, size); 196 197 #else 198 199 /* Catch pointer issues sooner: force relocation and make sure that the 200 original buffer is wiped. */ 201 202 ret = malloc(size + ALLOC_OFF_TOTAL); 203 ALLOC_CHECK_RESULT(ret, size); 204 205 if (orig) { 206 207 memcpy(ret + ALLOC_OFF_HEAD, orig + ALLOC_OFF_HEAD, MIN(size, old_size)); 208 memset(orig + ALLOC_OFF_HEAD, 0xFF, old_size); 209 210 ALLOC_C1(orig + ALLOC_OFF_HEAD) = ALLOC_MAGIC_F; 211 212 free(orig); 213 214 } 215 216 #endif /* ^!DEBUG_BUILD */ 217 218 ret += ALLOC_OFF_HEAD; 219 220 ALLOC_C1(ret) = ALLOC_MAGIC_C1; 221 ALLOC_S(ret) = size; 222 ALLOC_C2(ret) = ALLOC_MAGIC_C2; 223 224 if (size > old_size) 225 memset(ret + old_size, 0, size - old_size); 226 227 return ret; 228 229 } 230 231 232 /* Re-allocate a buffer with ALLOC_BLK_INC increments (used to speed up 233 repeated small reallocs without complicating the user code). */ 234 235 static inline void* DFL_ck_realloc_block(void* orig, u32 size) { 236 237 #ifndef DEBUG_BUILD 238 239 if (orig) { 240 241 CHECK_PTR(orig); 242 243 if (ALLOC_S(orig) >= size) return orig; 244 245 size += ALLOC_BLK_INC; 246 247 } 248 249 #endif /* !DEBUG_BUILD */ 250 251 return DFL_ck_realloc(orig, size); 252 253 } 254 255 256 /* Create a buffer with a copy of a string. Returns NULL for NULL inputs. */ 257 258 static inline u8* DFL_ck_strdup(u8* str) { 259 260 void* ret; 261 u32 size; 262 263 if (!str) return NULL; 264 265 size = strlen((char*)str) + 1; 266 267 ALLOC_CHECK_SIZE(size); 268 ret = malloc(size + ALLOC_OFF_TOTAL); 269 ALLOC_CHECK_RESULT(ret, size); 270 271 ret += ALLOC_OFF_HEAD; 272 273 ALLOC_C1(ret) = ALLOC_MAGIC_C1; 274 ALLOC_S(ret) = size; 275 ALLOC_C2(ret) = ALLOC_MAGIC_C2; 276 277 return memcpy(ret, str, size); 278 279 } 280 281 282 /* Create a buffer with a copy of a memory block. Returns NULL for zero-sized 283 or NULL inputs. */ 284 285 static inline void* DFL_ck_memdup(void* mem, u32 size) { 286 287 void* ret; 288 289 if (!mem || !size) return NULL; 290 291 ALLOC_CHECK_SIZE(size); 292 ret = malloc(size + ALLOC_OFF_TOTAL); 293 ALLOC_CHECK_RESULT(ret, size); 294 295 ret += ALLOC_OFF_HEAD; 296 297 ALLOC_C1(ret) = ALLOC_MAGIC_C1; 298 ALLOC_S(ret) = size; 299 ALLOC_C2(ret) = ALLOC_MAGIC_C2; 300 301 return memcpy(ret, mem, size); 302 303 } 304 305 306 /* Create a buffer with a block of text, appending a NUL terminator at the end. 307 Returns NULL for zero-sized or NULL inputs. */ 308 309 static inline u8* DFL_ck_memdup_str(u8* mem, u32 size) { 310 311 u8* ret; 312 313 if (!mem || !size) return NULL; 314 315 ALLOC_CHECK_SIZE(size); 316 ret = malloc(size + ALLOC_OFF_TOTAL + 1); 317 ALLOC_CHECK_RESULT(ret, size); 318 319 ret += ALLOC_OFF_HEAD; 320 321 ALLOC_C1(ret) = ALLOC_MAGIC_C1; 322 ALLOC_S(ret) = size; 323 ALLOC_C2(ret) = ALLOC_MAGIC_C2; 324 325 memcpy(ret, mem, size); 326 ret[size] = 0; 327 328 return ret; 329 330 } 331 332 333 #ifndef DEBUG_BUILD 334 335 /* In non-debug mode, we just do straightforward aliasing of the above functions 336 to user-visible names such as ck_alloc(). */ 337 338 #define ck_alloc DFL_ck_alloc 339 #define ck_alloc_nozero DFL_ck_alloc_nozero 340 #define ck_realloc DFL_ck_realloc 341 #define ck_realloc_block DFL_ck_realloc_block 342 #define ck_strdup DFL_ck_strdup 343 #define ck_memdup DFL_ck_memdup 344 #define ck_memdup_str DFL_ck_memdup_str 345 #define ck_free DFL_ck_free 346 347 #define alloc_report() 348 349 #else 350 351 /* In debugging mode, we also track allocations to detect memory leaks, and the 352 flow goes through one more layer of indirection. */ 353 354 /* Alloc tracking data structures: */ 355 356 #define ALLOC_BUCKETS 4096 357 358 struct TRK_obj { 359 void *ptr; 360 char *file, *func; 361 u32 line; 362 }; 363 364 #ifdef AFL_MAIN 365 366 struct TRK_obj* TRK[ALLOC_BUCKETS]; 367 u32 TRK_cnt[ALLOC_BUCKETS]; 368 369 # define alloc_report() TRK_report() 370 371 #else 372 373 extern struct TRK_obj* TRK[ALLOC_BUCKETS]; 374 extern u32 TRK_cnt[ALLOC_BUCKETS]; 375 376 # define alloc_report() 377 378 #endif /* ^AFL_MAIN */ 379 380 /* Bucket-assigning function for a given pointer: */ 381 382 #define TRKH(_ptr) (((((u32)(_ptr)) >> 16) ^ ((u32)(_ptr))) % ALLOC_BUCKETS) 383 384 385 /* Add a new entry to the list of allocated objects. */ 386 387 static inline void TRK_alloc_buf(void* ptr, const char* file, const char* func, 388 u32 line) { 389 390 u32 i, bucket; 391 392 if (!ptr) return; 393 394 bucket = TRKH(ptr); 395 396 /* Find a free slot in the list of entries for that bucket. */ 397 398 for (i = 0; i < TRK_cnt[bucket]; i++) 399 400 if (!TRK[bucket][i].ptr) { 401 402 TRK[bucket][i].ptr = ptr; 403 TRK[bucket][i].file = (char*)file; 404 TRK[bucket][i].func = (char*)func; 405 TRK[bucket][i].line = line; 406 return; 407 408 } 409 410 /* No space available - allocate more. */ 411 412 TRK[bucket] = DFL_ck_realloc_block(TRK[bucket], 413 (TRK_cnt[bucket] + 1) * sizeof(struct TRK_obj)); 414 415 TRK[bucket][i].ptr = ptr; 416 TRK[bucket][i].file = (char*)file; 417 TRK[bucket][i].func = (char*)func; 418 TRK[bucket][i].line = line; 419 420 TRK_cnt[bucket]++; 421 422 } 423 424 425 /* Remove entry from the list of allocated objects. */ 426 427 static inline void TRK_free_buf(void* ptr, const char* file, const char* func, 428 u32 line) { 429 430 u32 i, bucket; 431 432 if (!ptr) return; 433 434 bucket = TRKH(ptr); 435 436 /* Find the element on the list... */ 437 438 for (i = 0; i < TRK_cnt[bucket]; i++) 439 440 if (TRK[bucket][i].ptr == ptr) { 441 442 TRK[bucket][i].ptr = 0; 443 return; 444 445 } 446 447 WARNF("ALLOC: Attempt to free non-allocated memory in %s (%s:%u)", 448 func, file, line); 449 450 } 451 452 453 /* Do a final report on all non-deallocated objects. */ 454 455 static inline void TRK_report(void) { 456 457 u32 i, bucket; 458 459 fflush(0); 460 461 for (bucket = 0; bucket < ALLOC_BUCKETS; bucket++) 462 for (i = 0; i < TRK_cnt[bucket]; i++) 463 if (TRK[bucket][i].ptr) 464 WARNF("ALLOC: Memory never freed, created in %s (%s:%u)", 465 TRK[bucket][i].func, TRK[bucket][i].file, TRK[bucket][i].line); 466 467 } 468 469 470 /* Simple wrappers for non-debugging functions: */ 471 472 static inline void* TRK_ck_alloc(u32 size, const char* file, const char* func, 473 u32 line) { 474 475 void* ret = DFL_ck_alloc(size); 476 TRK_alloc_buf(ret, file, func, line); 477 return ret; 478 479 } 480 481 482 static inline void* TRK_ck_realloc(void* orig, u32 size, const char* file, 483 const char* func, u32 line) { 484 485 void* ret = DFL_ck_realloc(orig, size); 486 TRK_free_buf(orig, file, func, line); 487 TRK_alloc_buf(ret, file, func, line); 488 return ret; 489 490 } 491 492 493 static inline void* TRK_ck_realloc_block(void* orig, u32 size, const char* file, 494 const char* func, u32 line) { 495 496 void* ret = DFL_ck_realloc_block(orig, size); 497 TRK_free_buf(orig, file, func, line); 498 TRK_alloc_buf(ret, file, func, line); 499 return ret; 500 501 } 502 503 504 static inline void* TRK_ck_strdup(u8* str, const char* file, const char* func, 505 u32 line) { 506 507 void* ret = DFL_ck_strdup(str); 508 TRK_alloc_buf(ret, file, func, line); 509 return ret; 510 511 } 512 513 514 static inline void* TRK_ck_memdup(void* mem, u32 size, const char* file, 515 const char* func, u32 line) { 516 517 void* ret = DFL_ck_memdup(mem, size); 518 TRK_alloc_buf(ret, file, func, line); 519 return ret; 520 521 } 522 523 524 static inline void* TRK_ck_memdup_str(void* mem, u32 size, const char* file, 525 const char* func, u32 line) { 526 527 void* ret = DFL_ck_memdup_str(mem, size); 528 TRK_alloc_buf(ret, file, func, line); 529 return ret; 530 531 } 532 533 534 static inline void TRK_ck_free(void* ptr, const char* file, 535 const char* func, u32 line) { 536 537 TRK_free_buf(ptr, file, func, line); 538 DFL_ck_free(ptr); 539 540 } 541 542 /* Aliasing user-facing names to tracking functions: */ 543 544 #define ck_alloc(_p1) \ 545 TRK_ck_alloc(_p1, __FILE__, __FUNCTION__, __LINE__) 546 547 #define ck_alloc_nozero(_p1) \ 548 TRK_ck_alloc(_p1, __FILE__, __FUNCTION__, __LINE__) 549 550 #define ck_realloc(_p1, _p2) \ 551 TRK_ck_realloc(_p1, _p2, __FILE__, __FUNCTION__, __LINE__) 552 553 #define ck_realloc_block(_p1, _p2) \ 554 TRK_ck_realloc_block(_p1, _p2, __FILE__, __FUNCTION__, __LINE__) 555 556 #define ck_strdup(_p1) \ 557 TRK_ck_strdup(_p1, __FILE__, __FUNCTION__, __LINE__) 558 559 #define ck_memdup(_p1, _p2) \ 560 TRK_ck_memdup(_p1, _p2, __FILE__, __FUNCTION__, __LINE__) 561 562 #define ck_memdup_str(_p1, _p2) \ 563 TRK_ck_memdup_str(_p1, _p2, __FILE__, __FUNCTION__, __LINE__) 564 565 #define ck_free(_p1) \ 566 TRK_ck_free(_p1, __FILE__, __FUNCTION__, __LINE__) 567 568 #endif /* ^!DEBUG_BUILD */ 569 570 #endif /* ! _HAVE_ALLOC_INL_H */