mirror of
https://github.com/AFLplusplus/AFLplusplus.git
synced 2025-06-08 16:21:32 +00:00
223 lines
5.6 KiB
C
223 lines
5.6 KiB
C
/*
|
|
american fuzzy lop++ - error-checking, memory-zeroing alloc routines
|
|
--------------------------------------------------------------------
|
|
|
|
Originally written by Michal Zalewski
|
|
|
|
Now maintained by Marc Heuse <mh@mh-sec.de>,
|
|
Heiko Eißfeldt <heiko.eissfeldt@hexco.de> and
|
|
Andrea Fioraldi <andreafioraldi@gmail.com>
|
|
|
|
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 <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)
|
|
|
|
/* 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 */
|
|
|