/* american fuzzy lop++ - error-checking, memory-zeroing alloc routines -------------------------------------------------------------------- Originally written by Michal Zalewski Now maintained by Marc Heuse , Heiko Eißfeldt and Andrea Fioraldi Copyright 2016, 2017 Google Inc. All rights reserved. Copyright 2019-2020 AFLplusplus Project. 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 #include #include #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) /* Allocator increments for ck_realloc_block(). */ #define ALLOC_BLK_INC 256 /* Allocate a buffer, explicitly not zeroing it. Returns NULL for zero-sized requests. */ static inline void* DFL_ck_alloc_nozero(u32 size) { u8* ret; if (!size) return NULL; ALLOC_CHECK_SIZE(size); ret = malloc(size); ALLOC_CHECK_RESULT(ret, size); return (void*)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 */ static inline void DFL_ck_free(void* mem) { free(mem); } /* 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) { u8* ret; u32 old_size = 0; if (!size) { DFL_ck_free(orig); return NULL; } ALLOC_CHECK_SIZE(size); ret = realloc(orig, size); ALLOC_CHECK_RESULT(ret, size); if (size > old_size) memset(ret + old_size, 0, size - old_size); return (void*)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) { if (orig) size += ALLOC_BLK_INC; 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) { u8* ret; u32 size; if (!str) return NULL; size = strlen((char*)str) + 1; ALLOC_CHECK_SIZE(size); ret = malloc(size); ALLOC_CHECK_RESULT(ret, size); 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) { u8* ret; if (!mem || !size) return NULL; ALLOC_CHECK_SIZE(size); ret = malloc(size); ALLOC_CHECK_RESULT(ret, size); 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 + 1); ALLOC_CHECK_RESULT(ret, size); memcpy(ret, mem, size); ret[size] = 0; return ret; } /* 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() #endif /* ! _HAVE_ALLOC_INL_H */