88#define FUZZ_HARNESS_NAME "fuzz_memorypool"
101#define FZ_ALIGN_SIZE (2 * sizeof (void *))
108#ifdef MHD_ASAN_POISON_ACTIVE
109#define FZ_RED_ZONE_SIZE FZ_ALIGN_SIZE
111#define FZ_RED_ZONE_SIZE ((size_t) 0)
118#define FZ_MAX_BLOCKS 24
146 1, 15, 16, 17, 32, 48, 64, 96, 128, 129, 192, 256, 320, 384, 512,
147 768, 1024, 1400, 1500, 2048, 4096, 8192, 16384, 32768, 65536, 131072
150#define FZ_NUM_POOL_SIZES \
151 (sizeof (fz_pool_sizes) / sizeof (fz_pool_sizes[0]))
207 struct MemoryPool *pool;
340 "%s: ops=%lu allocations=%lu (failed %lu) "
341 "moved reallocations=%lu resets=%lu\n",
358 (void) snprintf (msg,
sizeof (msg),
"%s: %s",
op, what);
382 return (uint8_t) ((((
unsigned int) tag) * 131u)
383 + ((
unsigned int) (idx * 17u))
401 for (i = from; i < to; i++)
425 expect = (uint8_t *) malloc (n);
428 for (i = 0; i < n; i++)
429 expect[i] =
fz_pat (tag, i);
430 if (0 != memcmp (expect, ptr, n))
445 for (i = 0; i < st->nblk; i++)
450 "the contents of a live allocation changed");
465 const uint8_t *up = (
const uint8_t *) p;
469 if ( (up < st->base) ||
470 (up > st->base + st->cap) )
472 fz_report (
op,
"returned a pointer outside of the pool");
475 off = (size_t) (up - st->base);
476 if ( (size > st->cap) ||
477 (off + size > st->cap) )
478 fz_report (
op,
"returned a block that extends past the end of the pool");
483 for (i = 0; i < st->nblk; i++)
485 const uint8_t *q = st->blk[i].ptr;
487 if (0 == st->blk[i].size)
489 if ( (up < q + st->blk[i].size) &&
492 fz_report (
op,
"returned a block overlapping another live allocation");
512 fz_report (
op,
"MHD_pool_get_free() exceeds the size of the pool");
513 for (i = 0; i < st->nblk; i++)
514 total += st->blk[i].size;
516 fz_report (
op,
"the live allocations alone exceed the size of the pool");
517 else if (total + freem > st->cap)
519 "the live allocations plus the free space exceed the size "
526static struct fz_block *
532 struct fz_block *b = &st->blk[st->nblk++];
534 b->ptr = (uint8_t *) ptr;
536 b->tag = st->next_tag++;
537 b->from_end = from_end;
538 fz_fill (b->ptr, b->tag, 0, size);
547 *b = st->blk[--st->nblk];
559static struct fz_block *
568 for (i = 0; i < st->nblk; i++)
570 if ( (! front_only) ||
571 (! st->blk[i].from_end) )
576 idx = ((
unsigned int) sel) % n;
577 for (i = 0; i < st->nblk; i++)
580 (st->blk[i].from_end) )
607 return (
size_t) (sel >> 2);
609 return (((
size_t) ((sel >> 2) + 1)) * cap) / 64u;
611 d = (size_t) ((sel >> 2) & 0x07u);
612 if (0 != (sel & 0x20))
614 return (freem > d) ? (freem - d) : 0;
616 return SIZE_MAX - (size_t) (sel >> 2);
644 if (
NULL == st->pool)
649 "a fresh pool does not offer the requested size rounded "
650 "up to the alignment");
657 fz_report (
"MHD_pool_reset",
"returned NULL for an empty pool");
661 st->base = (uint8_t *) base;
678 static const char *
const nm[2] = {
"MHD_pool_allocate",
679 "MHD_pool_allocate (from_end)" };
680 const bool from_end = (0 != (
op[1] & 0x01)) || prefer_end;
681 const char *name = nm[from_end ? 1 : 0];
697 fz_report (name,
"a failed allocation changed the amount of free space");
701 "allocation failed although MHD_pool_get_free() reported "
707 fz_report (name,
"MHD_pool_get_free() increased across an allocation");
708 else if (freem - after < size)
710 "MHD_pool_get_free() dropped by less than the allocated size");
712 (void)
fz_add (st, p, size, from_end);
725 static const char name[] =
"MHD_pool_allocate (all free)";
726 const bool from_end = (0 != (
op[1] & 0x01));
740 "allocating exactly MHD_pool_get_free() bytes failed");
747 "the pool still reports free space after all of it was "
749 (void)
fz_add (st, p, freem, from_end);
760 static const char name[] =
"MHD_pool_try_alloc";
778 fz_report (name,
"a failed allocation changed the amount of free space");
781 "the allocation failed but no additional memory is "
782 "reported to be required");
786 "more memory is reported to be required than the pool "
791 "allocation failed although MHD_pool_get_free() reported "
798 "the allocation succeeded but required_bytes was not "
801 fz_report (name,
"MHD_pool_get_free() increased across an allocation");
802 else if (freem - after < size)
804 "MHD_pool_get_free() dropped by less than the allocated size");
807 (void)
fz_add (st, p, size,
true);
823 static const char name[] =
"MHD_pool_try_alloc (squeeze)";
829 struct fz_block *victim =
NULL;
838 (void)
fz_add (st, p, size,
true);
844 for (i = 0; i < st->nblk; i++)
846 if (st->blk[i].from_end)
848 if (st->blk[i].size < need)
854 victim = &st->blk[i];
860 const size_t new_size = victim->size - need;
869 "shrinking a block that is resizable in-place failed");
872 if (shrunk != victim->ptr)
874 "shrinking a block that is resizable in-place moved it");
875 victim->ptr = (uint8_t *) shrunk;
876 victim->size = new_size;
877 fz_verify (victim->ptr, victim->size, victim->tag, name,
878 "shrinking a block damaged its contents");
884 "the allocation still fails after freeing the number of "
885 "bytes that required_bytes asked for");
889 (void)
fz_add (st, p, size,
true);
903 static const char name[] =
"MHD_pool_reallocate";
904 struct fz_block *b =
fz_pick (st,
op[1],
true);
905 struct fz_block saved;
915 new_size =
fz_size (
op[2], st->cap, freem);
916 if ( (0 == b->size) &&
929 "a failed reallocation changed the amount of free space");
930 fz_verify (saved.ptr, saved.size, saved.tag, name,
931 "a failed reallocation damaged the old block");
933 (new_size <= saved.size + freem) )
935 "reallocation failed although the block is resizable "
936 "in-place and the pool has the required free space");
942 "a block that MHD_pool_is_resizable_inplace() accepted was "
944 if ( (new_size >= saved.size) &&
947 "MHD_pool_get_free() increased across a growing "
955 (new_size < saved.size) ? new_size : saved.size,
958 "reallocation did not preserve the contents of the block");
959 b = &st->blk[st->nblk++];
960 b->ptr = (uint8_t *) p;
964 if (new_size > saved.size)
965 fz_fill (b->ptr, b->tag, saved.size, new_size);
978 static const char name[] =
"MHD_pool_reallocate (fresh)";
994 "allocation failed although MHD_pool_get_free() reported "
1000 fz_report (name,
"MHD_pool_get_free() increased across an allocation");
1002 (void)
fz_add (st, p, size,
false);
1016 static const char name[] =
"MHD_pool_deallocate";
1017 struct fz_block *b =
fz_pick (st,
op[1],
false);
1038 for (i = 0; i < st->nblk; i++)
1040 if ( (st->blk[i].from_end) &&
1041 (0 != st->blk[i].size) &&
1042 (st->blk[i].ptr < b->ptr) )
1054 fz_verify (b->ptr, b->size, b->tag, name,
1055 "the contents of the block changed before it was freed");
1061 fz_report (name,
"deallocation reduced the amount of free space");
1074 static const char name[] =
"MHD_pool_reset";
1075 struct fz_block *b =
fz_pick (st, (uint8_t) (
op[1] & 0x0F),
false);
1082 if (new_size > st->cap)
1087 copy = (b->size * ((size_t) (
op[1] >> 4))) / 15u;
1090 if (copy > new_size)
1093 fz_verify (b->ptr, b->size, b->tag, name,
1094 "the contents of the kept block changed before the reset");
1109 fz_verify ((
const uint8_t *) p, copy, tag, name,
1110 "the kept bytes did not survive the reset");
1111 b =
fz_add (st, p, new_size,
false);
1123 static const char name[] =
"MHD_pool_is_resizable_inplace";
1124 struct fz_block *b =
fz_pick (st,
op[1],
false);
1128 (0 != (
op[1] & 0x80)) )
1131 fz_report (name,
"an unallocated block is reported as resizable");
1139 "a block allocated from the end is reported as resizable "
1151 "reallocating a resizable block to its own size failed");
1152 else if (p != b->ptr)
1154 "reallocating a resizable block to its own size moved it");
1164 const char *name =
"operation";
1194 name =
"MHD_pool_get_free";
1220 static bool inited =
false;
1240 e = getenv (
"MHD_FUZZ_POOL_FULL_DEALLOC");
1243 e = getenv (
"MHD_FUZZ_POOL_WRAP_REALLOC");
1247 memset (&st, 0,
sizeof (st));
1248 st.paranoid = (0 != (
data[1] & 0x01));
1251 nops = (size - 2) / 3;
1254 for (i = 0; i < nops; i++)
1256 if (
NULL == st.pool)
1305 return (uint8_t) ((
fuzz_below (rng, 64) << 2) | 0u);
1307 return (uint8_t) ((
fuzz_below (rng, 64) << 2) | 1u);
1316 return (uint8_t) ((d << 2) | (sign << 5) | 2u);
1318 return (uint8_t) ((
fuzz_below (rng, 64) << 2) | 3u);
1341 buf[len++] = (uint8_t) psel;
1349 for (i = 0; i < nops; i++)
1366#define SZ_TINY(n) ((uint8_t) ((((unsigned int) (n)) << 2) | 0u))
1367#define SZ_FRAC(k) ((uint8_t) ((((unsigned int) (k)) << 2) | 1u))
1368#define SZ_FREE ((uint8_t) 2u)
1369#define SZ_FREE_M(d) ((uint8_t) ((((unsigned int) (d)) << 2) | 2u))
1370#define SZ_FREE_P(d) ((uint8_t) ((((unsigned int) (d)) << 2) | 0x20u | 2u))
1371#define SZ_HUGE ((uint8_t) 3u)
1385#define OPR(o,b,s) ((uint8_t) (o)), ((uint8_t) (b)), (s)
1573 const uint8_t *bytes;
1577#define MSEED(a) { (a), sizeof (a) }
1607static const uint8_t *
Shared, header-only fuzzing driver for the MHD in-process fuzzers.
static FUZZ_UNUSED int fuzz_verbose
static FUZZ_UNUSED uint32_t fuzz_below(struct fuzz_rng *r, uint32_t n)
static FUZZ_UNUSED uint8_t fuzz_byte(struct fuzz_rng *r)
static FUZZ_UNUSED void fuzz_report_finding(const char *what)
static FUZZ_UNUSED int fuzz_chance(struct fuzz_rng *r, uint32_t n)
static void fz_report(const char *op, const char *what)
static void fz_op_alloc_all(struct fz_pool *st, const uint8_t *op)
static const uint8_t seed_squeeze[]
static unsigned long stat_resets
static size_t fuzz_seed_count(void)
static uint8_t gen_size_sel(struct fuzz_rng *rng)
static void fz_op_alloc(struct fz_pool *st, const uint8_t *op, bool prefer_end)
static unsigned long stat_ops
static const uint8_t seed_reset_keep[]
static int known_bugs_read
static const uint8_t seed_tiny_pool[]
static struct fz_block * fz_add(struct fz_pool *st, void *ptr, size_t size, bool from_end)
#define FZ_NUM_POOL_SIZES
static const size_t fz_pool_sizes[]
static size_t fz_round(size_t n)
static const uint8_t seed_boundary[]
static void fz_op_resizable(struct fz_pool *st, const uint8_t *op)
static const uint8_t seed_recreate[]
static void fz_do_op(struct fz_pool *st, const uint8_t *op, bool prefer_end)
static void fz_pool_close(struct fz_pool *st)
static unsigned long stat_alloc_ok
#define FUZZ_HARNESS_NAME
static const uint8_t seed_wrap[]
static void fz_op_dealloc(struct fz_pool *st, const uint8_t *op)
static const uint8_t * fuzz_seed_get(size_t idx, size_t *len)
static const uint8_t seed_dealloc_end_full[]
static unsigned long stat_realloc_moved
static void fz_verify_all(struct fz_pool *st, const char *op)
static int wrap_realloc_enabled
static void fz_op_realloc_new(struct fz_pool *st, const uint8_t *op)
static const uint8_t seed_from_end[]
static const uint8_t seed_two_blocks_realloc[]
static void fz_op_reset(struct fz_pool *st, const uint8_t *op)
static void fz_check_ptr(struct fz_pool *st, void *p, size_t size, const char *op)
static int full_dealloc_enabled
static void fz_op_try_alloc(struct fz_pool *st, const uint8_t *op)
static void fz_check_invariants(struct fz_pool *st, const char *op)
static const uint8_t seed_connection_cycle[]
int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
static const uint8_t seed_reset_full[]
static bool fz_pool_open(struct fz_pool *st, uint8_t sel)
static size_t fuzz_generate(struct fuzz_rng *rng, uint8_t *buf, size_t cap)
static uint8_t fz_pat(uint8_t tag, size_t idx)
static void print_stats(void)
static const uint8_t seed_zero_sizes[]
static struct fz_block * fz_pick(struct fz_pool *st, uint8_t sel, bool front_only)
static unsigned long stat_alloc_fail
static const uint8_t seed_many_small[]
static const uint8_t seed_realloc_wrap[]
static void fz_op_realloc(struct fz_pool *st, const uint8_t *op)
static void fz_op_squeeze(struct fz_pool *st, const uint8_t *op)
static void fz_del(struct fz_pool *st, struct fz_block *b)
static const uint8_t seed_squeeze_small[]
static const uint8_t seed_grow_shrink[]
static void fz_verify(const uint8_t *ptr, size_t size, uint8_t tag, const char *op, const char *what)
static size_t fz_size(uint8_t sel, size_t cap, size_t freem)
static const uint8_t seed_fill_exactly[]
static const uint8_t gen_ops[]
static const struct mp_seed mp_seeds[]
static void fz_fill(uint8_t *ptr, uint8_t tag, size_t from, size_t to)
MHD internal shared structures.
void MHD_init_mem_pools_(void)
void * MHD_pool_reallocate(struct MemoryPool *pool, void *old, size_t old_size, size_t new_size)
void MHD_pool_destroy(struct MemoryPool *pool)
bool MHD_pool_is_resizable_inplace(struct MemoryPool *pool, void *block, size_t block_size)
void MHD_pool_deallocate(struct MemoryPool *pool, void *block, size_t block_size)
void * MHD_pool_try_alloc(struct MemoryPool *pool, size_t size, size_t *required_bytes)
size_t MHD_pool_get_free(struct MemoryPool *pool)
void * MHD_pool_reset(struct MemoryPool *pool, void *keep, size_t copy_bytes, size_t new_size)
struct MemoryPool * MHD_pool_create(size_t max)
void * MHD_pool_allocate(struct MemoryPool *pool, size_t size, bool from_end)
memory pool; mostly used for efficient (de)allocation for each connection and bounding memory use for...