| Index: third_party/afl/src/alloc-inl.h
|
| diff --git a/third_party/afl/src/alloc-inl.h b/third_party/afl/src/alloc-inl.h
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..d3c125fbb4cf58a5f96cb252efed0d0d7428171b
|
| --- /dev/null
|
| +++ b/third_party/afl/src/alloc-inl.h
|
| @@ -0,0 +1,570 @@
|
| +/*
|
| + american fuzzy lop - error-checking, memory-zeroing alloc routines
|
| + ------------------------------------------------------------------
|
| +
|
| + Written and maintained by Michal Zalewski <lcamtuf@google.com>
|
| +
|
| + Copyright 2013, 2014, 2015 Google Inc. All rights reserved.
|
| +
|
| + Licensed under the Apache License, Version 2.0 (the "License");
|
| + you may not use this file except in compliance with the License.
|
| + You may obtain a copy of the License at:
|
| +
|
| + http://www.apache.org/licenses/LICENSE-2.0
|
| +
|
| + This allocator is not designed to resist malicious attackers (the canaries
|
| + are small and predictable), but provides a robust and portable way to detect
|
| + use-after-free, off-by-one writes, stale pointers, and so on.
|
| +
|
| + */
|
| +
|
| +#ifndef _HAVE_ALLOC_INL_H
|
| +#define _HAVE_ALLOC_INL_H
|
| +
|
| +#include <stdio.h>
|
| +#include <stdlib.h>
|
| +#include <string.h>
|
| +
|
| +#include "config.h"
|
| +#include "types.h"
|
| +#include "debug.h"
|
| +
|
| +/* User-facing macro to sprintf() to a dynamically allocated buffer. */
|
| +
|
| +#define alloc_printf(_str...) ({ \
|
| + u8* _tmp; \
|
| + s32 _len = snprintf(NULL, 0, _str); \
|
| + if (_len < 0) FATAL("Whoa, snprintf() fails?!"); \
|
| + _tmp = ck_alloc(_len + 1); \
|
| + snprintf((char*)_tmp, _len + 1, _str); \
|
| + _tmp; \
|
| + })
|
| +
|
| +/* Macro to enforce allocation limits as a last-resort defense against
|
| + integer overflows. */
|
| +
|
| +#define ALLOC_CHECK_SIZE(_s) do { \
|
| + if ((_s) > MAX_ALLOC) \
|
| + ABORT("Bad alloc request: %u bytes", (_s)); \
|
| + } while (0)
|
| +
|
| +/* Macro to check malloc() failures and the like. */
|
| +
|
| +#define ALLOC_CHECK_RESULT(_r, _s) do { \
|
| + if (!(_r)) \
|
| + ABORT("Out of memory: can't allocate %u bytes", (_s)); \
|
| + } while (0)
|
| +
|
| +/* Magic tokens used to mark used / freed chunks. */
|
| +
|
| +#define ALLOC_MAGIC_C1 0xFF00FF00 /* Used head (dword) */
|
| +#define ALLOC_MAGIC_F 0xFE00FE00 /* Freed head (dword) */
|
| +#define ALLOC_MAGIC_C2 0xF0 /* Used tail (byte) */
|
| +
|
| +/* Positions of guard tokens in relation to the user-visible pointer. */
|
| +
|
| +#define ALLOC_C1(_ptr) (((u32*)(_ptr))[-2])
|
| +#define ALLOC_S(_ptr) (((u32*)(_ptr))[-1])
|
| +#define ALLOC_C2(_ptr) (((u8*)(_ptr))[ALLOC_S(_ptr)])
|
| +
|
| +#define ALLOC_OFF_HEAD 8
|
| +#define ALLOC_OFF_TOTAL (ALLOC_OFF_HEAD + 1)
|
| +
|
| +/* Allocator increments for ck_realloc_block(). */
|
| +
|
| +#define ALLOC_BLK_INC 256
|
| +
|
| +/* Sanity-checking macros for pointers. */
|
| +
|
| +#define CHECK_PTR(_p) do { \
|
| + if (_p) { \
|
| + if (ALLOC_C1(_p) ^ ALLOC_MAGIC_C1) {\
|
| + if (ALLOC_C1(_p) == ALLOC_MAGIC_F) \
|
| + ABORT("Use after free."); \
|
| + else ABORT("Corrupted head alloc canary."); \
|
| + } \
|
| + if (ALLOC_C2(_p) ^ ALLOC_MAGIC_C2) \
|
| + ABORT("Corrupted tail alloc canary."); \
|
| + } \
|
| + } while (0)
|
| +
|
| +#define CHECK_PTR_EXPR(_p) ({ \
|
| + typeof (_p) _tmp = (_p); \
|
| + CHECK_PTR(_tmp); \
|
| + _tmp; \
|
| + })
|
| +
|
| +
|
| +/* Allocate a buffer, explicitly not zeroing it. Returns NULL for zero-sized
|
| + requests. */
|
| +
|
| +static inline void* DFL_ck_alloc_nozero(u32 size) {
|
| +
|
| + void* ret;
|
| +
|
| + if (!size) return NULL;
|
| +
|
| + ALLOC_CHECK_SIZE(size);
|
| + ret = malloc(size + ALLOC_OFF_TOTAL);
|
| + ALLOC_CHECK_RESULT(ret, size);
|
| +
|
| + ret += ALLOC_OFF_HEAD;
|
| +
|
| + ALLOC_C1(ret) = ALLOC_MAGIC_C1;
|
| + ALLOC_S(ret) = size;
|
| + ALLOC_C2(ret) = ALLOC_MAGIC_C2;
|
| +
|
| + return ret;
|
| +
|
| +}
|
| +
|
| +
|
| +/* Allocate a buffer, returning zeroed memory. */
|
| +
|
| +static inline void* DFL_ck_alloc(u32 size) {
|
| +
|
| + void* mem;
|
| +
|
| + if (!size) return NULL;
|
| + mem = DFL_ck_alloc_nozero(size);
|
| +
|
| + return memset(mem, 0, size);
|
| +
|
| +}
|
| +
|
| +
|
| +/* Free memory, checking for double free and corrupted heap. When DEBUG_BUILD
|
| + is set, the old memory will be also clobbered with 0xFF. */
|
| +
|
| +static inline void DFL_ck_free(void* mem) {
|
| +
|
| + if (!mem) return;
|
| +
|
| + CHECK_PTR(mem);
|
| +
|
| +#ifdef DEBUG_BUILD
|
| +
|
| + /* Catch pointer issues sooner. */
|
| + memset(mem, 0xFF, ALLOC_S(mem));
|
| +
|
| +#endif /* DEBUG_BUILD */
|
| +
|
| + ALLOC_C1(mem) = ALLOC_MAGIC_F;
|
| +
|
| + free(mem - ALLOC_OFF_HEAD);
|
| +
|
| +}
|
| +
|
| +
|
| +/* Re-allocate a buffer, checking for issues and zeroing any newly-added tail.
|
| + With DEBUG_BUILD, the buffer is always reallocated to a new addresses and the
|
| + old memory is clobbered with 0xFF. */
|
| +
|
| +static inline void* DFL_ck_realloc(void* orig, u32 size) {
|
| +
|
| + void* ret;
|
| + u32 old_size = 0;
|
| +
|
| + if (!size) {
|
| +
|
| + DFL_ck_free(orig);
|
| + return NULL;
|
| +
|
| + }
|
| +
|
| + if (orig) {
|
| +
|
| + CHECK_PTR(orig);
|
| +
|
| +#ifndef DEBUG_BUILD
|
| + ALLOC_C1(orig) = ALLOC_MAGIC_F;
|
| +#endif /* !DEBUG_BUILD */
|
| +
|
| + old_size = ALLOC_S(orig);
|
| + orig -= ALLOC_OFF_HEAD;
|
| +
|
| + ALLOC_CHECK_SIZE(old_size);
|
| +
|
| + }
|
| +
|
| + ALLOC_CHECK_SIZE(size);
|
| +
|
| +#ifndef DEBUG_BUILD
|
| +
|
| + ret = realloc(orig, size + ALLOC_OFF_TOTAL);
|
| + ALLOC_CHECK_RESULT(ret, size);
|
| +
|
| +#else
|
| +
|
| + /* Catch pointer issues sooner: force relocation and make sure that the
|
| + original buffer is wiped. */
|
| +
|
| + ret = malloc(size + ALLOC_OFF_TOTAL);
|
| + ALLOC_CHECK_RESULT(ret, size);
|
| +
|
| + if (orig) {
|
| +
|
| + memcpy(ret + ALLOC_OFF_HEAD, orig + ALLOC_OFF_HEAD, MIN(size, old_size));
|
| + memset(orig + ALLOC_OFF_HEAD, 0xFF, old_size);
|
| +
|
| + ALLOC_C1(orig + ALLOC_OFF_HEAD) = ALLOC_MAGIC_F;
|
| +
|
| + free(orig);
|
| +
|
| + }
|
| +
|
| +#endif /* ^!DEBUG_BUILD */
|
| +
|
| + ret += ALLOC_OFF_HEAD;
|
| +
|
| + ALLOC_C1(ret) = ALLOC_MAGIC_C1;
|
| + ALLOC_S(ret) = size;
|
| + ALLOC_C2(ret) = ALLOC_MAGIC_C2;
|
| +
|
| + if (size > old_size)
|
| + memset(ret + old_size, 0, size - old_size);
|
| +
|
| + return ret;
|
| +
|
| +}
|
| +
|
| +
|
| +/* Re-allocate a buffer with ALLOC_BLK_INC increments (used to speed up
|
| + repeated small reallocs without complicating the user code). */
|
| +
|
| +static inline void* DFL_ck_realloc_block(void* orig, u32 size) {
|
| +
|
| +#ifndef DEBUG_BUILD
|
| +
|
| + if (orig) {
|
| +
|
| + CHECK_PTR(orig);
|
| +
|
| + if (ALLOC_S(orig) >= size) return orig;
|
| +
|
| + size += ALLOC_BLK_INC;
|
| +
|
| + }
|
| +
|
| +#endif /* !DEBUG_BUILD */
|
| +
|
| + return DFL_ck_realloc(orig, size);
|
| +
|
| +}
|
| +
|
| +
|
| +/* Create a buffer with a copy of a string. Returns NULL for NULL inputs. */
|
| +
|
| +static inline u8* DFL_ck_strdup(u8* str) {
|
| +
|
| + void* ret;
|
| + u32 size;
|
| +
|
| + if (!str) return NULL;
|
| +
|
| + size = strlen((char*)str) + 1;
|
| +
|
| + ALLOC_CHECK_SIZE(size);
|
| + ret = malloc(size + ALLOC_OFF_TOTAL);
|
| + ALLOC_CHECK_RESULT(ret, size);
|
| +
|
| + ret += ALLOC_OFF_HEAD;
|
| +
|
| + ALLOC_C1(ret) = ALLOC_MAGIC_C1;
|
| + ALLOC_S(ret) = size;
|
| + ALLOC_C2(ret) = ALLOC_MAGIC_C2;
|
| +
|
| + return memcpy(ret, str, size);
|
| +
|
| +}
|
| +
|
| +
|
| +/* Create a buffer with a copy of a memory block. Returns NULL for zero-sized
|
| + or NULL inputs. */
|
| +
|
| +static inline void* DFL_ck_memdup(void* mem, u32 size) {
|
| +
|
| + void* ret;
|
| +
|
| + if (!mem || !size) return NULL;
|
| +
|
| + ALLOC_CHECK_SIZE(size);
|
| + ret = malloc(size + ALLOC_OFF_TOTAL);
|
| + ALLOC_CHECK_RESULT(ret, size);
|
| +
|
| + ret += ALLOC_OFF_HEAD;
|
| +
|
| + ALLOC_C1(ret) = ALLOC_MAGIC_C1;
|
| + ALLOC_S(ret) = size;
|
| + ALLOC_C2(ret) = ALLOC_MAGIC_C2;
|
| +
|
| + return memcpy(ret, mem, size);
|
| +
|
| +}
|
| +
|
| +
|
| +/* Create a buffer with a block of text, appending a NUL terminator at the end.
|
| + Returns NULL for zero-sized or NULL inputs. */
|
| +
|
| +static inline u8* DFL_ck_memdup_str(u8* mem, u32 size) {
|
| +
|
| + u8* ret;
|
| +
|
| + if (!mem || !size) return NULL;
|
| +
|
| + ALLOC_CHECK_SIZE(size);
|
| + ret = malloc(size + ALLOC_OFF_TOTAL + 1);
|
| + ALLOC_CHECK_RESULT(ret, size);
|
| +
|
| + ret += ALLOC_OFF_HEAD;
|
| +
|
| + ALLOC_C1(ret) = ALLOC_MAGIC_C1;
|
| + ALLOC_S(ret) = size;
|
| + ALLOC_C2(ret) = ALLOC_MAGIC_C2;
|
| +
|
| + memcpy(ret, mem, size);
|
| + ret[size] = 0;
|
| +
|
| + return ret;
|
| +
|
| +}
|
| +
|
| +
|
| +#ifndef DEBUG_BUILD
|
| +
|
| +/* In non-debug mode, we just do straightforward aliasing of the above functions
|
| + to user-visible names such as ck_alloc(). */
|
| +
|
| +#define ck_alloc DFL_ck_alloc
|
| +#define ck_alloc_nozero DFL_ck_alloc_nozero
|
| +#define ck_realloc DFL_ck_realloc
|
| +#define ck_realloc_block DFL_ck_realloc_block
|
| +#define ck_strdup DFL_ck_strdup
|
| +#define ck_memdup DFL_ck_memdup
|
| +#define ck_memdup_str DFL_ck_memdup_str
|
| +#define ck_free DFL_ck_free
|
| +
|
| +#define alloc_report()
|
| +
|
| +#else
|
| +
|
| +/* In debugging mode, we also track allocations to detect memory leaks, and the
|
| + flow goes through one more layer of indirection. */
|
| +
|
| +/* Alloc tracking data structures: */
|
| +
|
| +#define ALLOC_BUCKETS 4096
|
| +
|
| +struct TRK_obj {
|
| + void *ptr;
|
| + char *file, *func;
|
| + u32 line;
|
| +};
|
| +
|
| +#ifdef AFL_MAIN
|
| +
|
| +struct TRK_obj* TRK[ALLOC_BUCKETS];
|
| +u32 TRK_cnt[ALLOC_BUCKETS];
|
| +
|
| +# define alloc_report() TRK_report()
|
| +
|
| +#else
|
| +
|
| +extern struct TRK_obj* TRK[ALLOC_BUCKETS];
|
| +extern u32 TRK_cnt[ALLOC_BUCKETS];
|
| +
|
| +# define alloc_report()
|
| +
|
| +#endif /* ^AFL_MAIN */
|
| +
|
| +/* Bucket-assigning function for a given pointer: */
|
| +
|
| +#define TRKH(_ptr) (((((u32)(_ptr)) >> 16) ^ ((u32)(_ptr))) % ALLOC_BUCKETS)
|
| +
|
| +
|
| +/* Add a new entry to the list of allocated objects. */
|
| +
|
| +static inline void TRK_alloc_buf(void* ptr, const char* file, const char* func,
|
| + u32 line) {
|
| +
|
| + u32 i, bucket;
|
| +
|
| + if (!ptr) return;
|
| +
|
| + bucket = TRKH(ptr);
|
| +
|
| + /* Find a free slot in the list of entries for that bucket. */
|
| +
|
| + for (i = 0; i < TRK_cnt[bucket]; i++)
|
| +
|
| + if (!TRK[bucket][i].ptr) {
|
| +
|
| + TRK[bucket][i].ptr = ptr;
|
| + TRK[bucket][i].file = (char*)file;
|
| + TRK[bucket][i].func = (char*)func;
|
| + TRK[bucket][i].line = line;
|
| + return;
|
| +
|
| + }
|
| +
|
| + /* No space available - allocate more. */
|
| +
|
| + TRK[bucket] = DFL_ck_realloc_block(TRK[bucket],
|
| + (TRK_cnt[bucket] + 1) * sizeof(struct TRK_obj));
|
| +
|
| + TRK[bucket][i].ptr = ptr;
|
| + TRK[bucket][i].file = (char*)file;
|
| + TRK[bucket][i].func = (char*)func;
|
| + TRK[bucket][i].line = line;
|
| +
|
| + TRK_cnt[bucket]++;
|
| +
|
| +}
|
| +
|
| +
|
| +/* Remove entry from the list of allocated objects. */
|
| +
|
| +static inline void TRK_free_buf(void* ptr, const char* file, const char* func,
|
| + u32 line) {
|
| +
|
| + u32 i, bucket;
|
| +
|
| + if (!ptr) return;
|
| +
|
| + bucket = TRKH(ptr);
|
| +
|
| + /* Find the element on the list... */
|
| +
|
| + for (i = 0; i < TRK_cnt[bucket]; i++)
|
| +
|
| + if (TRK[bucket][i].ptr == ptr) {
|
| +
|
| + TRK[bucket][i].ptr = 0;
|
| + return;
|
| +
|
| + }
|
| +
|
| + WARNF("ALLOC: Attempt to free non-allocated memory in %s (%s:%u)",
|
| + func, file, line);
|
| +
|
| +}
|
| +
|
| +
|
| +/* Do a final report on all non-deallocated objects. */
|
| +
|
| +static inline void TRK_report(void) {
|
| +
|
| + u32 i, bucket;
|
| +
|
| + fflush(0);
|
| +
|
| + for (bucket = 0; bucket < ALLOC_BUCKETS; bucket++)
|
| + for (i = 0; i < TRK_cnt[bucket]; i++)
|
| + if (TRK[bucket][i].ptr)
|
| + WARNF("ALLOC: Memory never freed, created in %s (%s:%u)",
|
| + TRK[bucket][i].func, TRK[bucket][i].file, TRK[bucket][i].line);
|
| +
|
| +}
|
| +
|
| +
|
| +/* Simple wrappers for non-debugging functions: */
|
| +
|
| +static inline void* TRK_ck_alloc(u32 size, const char* file, const char* func,
|
| + u32 line) {
|
| +
|
| + void* ret = DFL_ck_alloc(size);
|
| + TRK_alloc_buf(ret, file, func, line);
|
| + return ret;
|
| +
|
| +}
|
| +
|
| +
|
| +static inline void* TRK_ck_realloc(void* orig, u32 size, const char* file,
|
| + const char* func, u32 line) {
|
| +
|
| + void* ret = DFL_ck_realloc(orig, size);
|
| + TRK_free_buf(orig, file, func, line);
|
| + TRK_alloc_buf(ret, file, func, line);
|
| + return ret;
|
| +
|
| +}
|
| +
|
| +
|
| +static inline void* TRK_ck_realloc_block(void* orig, u32 size, const char* file,
|
| + const char* func, u32 line) {
|
| +
|
| + void* ret = DFL_ck_realloc_block(orig, size);
|
| + TRK_free_buf(orig, file, func, line);
|
| + TRK_alloc_buf(ret, file, func, line);
|
| + return ret;
|
| +
|
| +}
|
| +
|
| +
|
| +static inline void* TRK_ck_strdup(u8* str, const char* file, const char* func,
|
| + u32 line) {
|
| +
|
| + void* ret = DFL_ck_strdup(str);
|
| + TRK_alloc_buf(ret, file, func, line);
|
| + return ret;
|
| +
|
| +}
|
| +
|
| +
|
| +static inline void* TRK_ck_memdup(void* mem, u32 size, const char* file,
|
| + const char* func, u32 line) {
|
| +
|
| + void* ret = DFL_ck_memdup(mem, size);
|
| + TRK_alloc_buf(ret, file, func, line);
|
| + return ret;
|
| +
|
| +}
|
| +
|
| +
|
| +static inline void* TRK_ck_memdup_str(void* mem, u32 size, const char* file,
|
| + const char* func, u32 line) {
|
| +
|
| + void* ret = DFL_ck_memdup_str(mem, size);
|
| + TRK_alloc_buf(ret, file, func, line);
|
| + return ret;
|
| +
|
| +}
|
| +
|
| +
|
| +static inline void TRK_ck_free(void* ptr, const char* file,
|
| + const char* func, u32 line) {
|
| +
|
| + TRK_free_buf(ptr, file, func, line);
|
| + DFL_ck_free(ptr);
|
| +
|
| +}
|
| +
|
| +/* Aliasing user-facing names to tracking functions: */
|
| +
|
| +#define ck_alloc(_p1) \
|
| + TRK_ck_alloc(_p1, __FILE__, __FUNCTION__, __LINE__)
|
| +
|
| +#define ck_alloc_nozero(_p1) \
|
| + TRK_ck_alloc(_p1, __FILE__, __FUNCTION__, __LINE__)
|
| +
|
| +#define ck_realloc(_p1, _p2) \
|
| + TRK_ck_realloc(_p1, _p2, __FILE__, __FUNCTION__, __LINE__)
|
| +
|
| +#define ck_realloc_block(_p1, _p2) \
|
| + TRK_ck_realloc_block(_p1, _p2, __FILE__, __FUNCTION__, __LINE__)
|
| +
|
| +#define ck_strdup(_p1) \
|
| + TRK_ck_strdup(_p1, __FILE__, __FUNCTION__, __LINE__)
|
| +
|
| +#define ck_memdup(_p1, _p2) \
|
| + TRK_ck_memdup(_p1, _p2, __FILE__, __FUNCTION__, __LINE__)
|
| +
|
| +#define ck_memdup_str(_p1, _p2) \
|
| + TRK_ck_memdup_str(_p1, _p2, __FILE__, __FUNCTION__, __LINE__)
|
| +
|
| +#define ck_free(_p1) \
|
| + TRK_ck_free(_p1, __FILE__, __FUNCTION__, __LINE__)
|
| +
|
| +#endif /* ^!DEBUG_BUILD */
|
| +
|
| +#endif /* ! _HAVE_ALLOC_INL_H */
|
|
|