GNU libmicrohttpd 1.0.9
Loading...
Searching...
No Matches
fuzz_memorypool.c
Go to the documentation of this file.
1/*
2 This file is part of libmicrohttpd
3 Copyright (C) 2026 Christian Grothoff
4
5 This library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Lesser General Public
7 License as published by the Free Software Foundation; either
8 version 2.1 of the License, or (at your option) any later version.
9
10 This library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Lesser General Public License for more details.
14
15 You should have received a copy of the GNU Lesser General Public
16 License along with this library.
17 If not, see <http://www.gnu.org/licenses/>.
18*/
19
88#define FUZZ_HARNESS_NAME "fuzz_memorypool"
89#include "fuzz_common.h"
90
91/* internal.h pulls in MHD_config.h and <microhttpd.h> in the right
92 order; including <microhttpd.h> first would redefine _MHD_EXTERN. */
93#include "internal.h"
94#include "memorypool.h"
95
96
101#define FZ_ALIGN_SIZE (2 * sizeof (void *))
102
108#ifdef MHD_ASAN_POISON_ACTIVE
109#define FZ_RED_ZONE_SIZE FZ_ALIGN_SIZE
110#else /* ! MHD_ASAN_POISON_ACTIVE */
111#define FZ_RED_ZONE_SIZE ((size_t) 0)
112#endif /* ! MHD_ASAN_POISON_ACTIVE */
113
118#define FZ_MAX_BLOCKS 24
119
123#define FZ_MAX_OPS 64
124
131#define FZ_PAT_MAX 96
132
145static const size_t fz_pool_sizes[] = {
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
148};
149
150#define FZ_NUM_POOL_SIZES \
151 (sizeof (fz_pool_sizes) / sizeof (fz_pool_sizes[0]))
152
153
170
171
175struct fz_block
176{
180 uint8_t *ptr;
181
186 size_t size;
187
191 uint8_t tag;
192
198 bool from_end;
199};
200
201
205struct fz_pool
206{
207 struct MemoryPool *pool;
208
214 uint8_t *base;
215
219 size_t cap;
220
221 struct fz_block blk[FZ_MAX_BLOCKS];
222
223 unsigned int nblk;
224
225 uint8_t next_tag;
226
230 bool paranoid;
231};
232
233
271
323
325
327static unsigned long stat_ops;
328static unsigned long stat_alloc_ok;
329static unsigned long stat_alloc_fail;
330static unsigned long stat_realloc_moved;
331static unsigned long stat_resets;
332
333
334static void
336{
337 if (! fuzz_verbose)
338 return;
339 fprintf (stderr,
340 "%s: ops=%lu allocations=%lu (failed %lu) "
341 "moved reallocations=%lu resets=%lu\n",
345}
346
347
352static void
353fz_report (const char *op,
354 const char *what)
355{
356 char msg[256];
357
358 (void) snprintf (msg, sizeof (msg), "%s: %s", op, what);
360}
361
362
368static size_t
369fz_round (size_t n)
370{
371 return (n + (FZ_ALIGN_SIZE - 1)) / FZ_ALIGN_SIZE * FZ_ALIGN_SIZE;
372}
373
374
378static uint8_t
379fz_pat (uint8_t tag,
380 size_t idx)
381{
382 return (uint8_t) ((((unsigned int) tag) * 131u)
383 + ((unsigned int) (idx * 17u))
384 + 0x5Au);
385}
386
387
391static void
392fz_fill (uint8_t *ptr,
393 uint8_t tag,
394 size_t from,
395 size_t to)
396{
397 size_t i;
398
399 if (to > FZ_PAT_MAX)
400 to = FZ_PAT_MAX;
401 for (i = from; i < to; i++)
402 ptr[i] = fz_pat (tag, i);
403}
404
405
412static void
413fz_verify (const uint8_t *ptr,
414 size_t size,
415 uint8_t tag,
416 const char *op,
417 const char *what)
418{
419 size_t n = (size < FZ_PAT_MAX) ? size : (size_t) FZ_PAT_MAX;
420 uint8_t *expect;
421 size_t i;
422
423 if (0 == n)
424 return;
425 expect = (uint8_t *) malloc (n);
426 if (NULL == expect)
427 abort ();
428 for (i = 0; i < n; i++)
429 expect[i] = fz_pat (tag, i);
430 if (0 != memcmp (expect, ptr, n))
431 fz_report (op, what);
432 free (expect);
433}
434
435
439static void
440fz_verify_all (struct fz_pool *st,
441 const char *op)
442{
443 unsigned int i;
444
445 for (i = 0; i < st->nblk; i++)
446 fz_verify (st->blk[i].ptr,
447 st->blk[i].size,
448 st->blk[i].tag,
449 op,
450 "the contents of a live allocation changed");
451}
452
453
459static void
460fz_check_ptr (struct fz_pool *st,
461 void *p,
462 size_t size,
463 const char *op)
464{
465 const uint8_t *up = (const uint8_t *) p;
466 size_t off;
467 unsigned int i;
468
469 if ( (up < st->base) ||
470 (up > st->base + st->cap) )
471 {
472 fz_report (op, "returned a pointer outside of the pool");
473 return;
474 }
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");
479 if (0 != (off % FZ_ALIGN_SIZE))
480 fz_report (op, "returned a misaligned pointer");
481 if (0 == size)
482 return;
483 for (i = 0; i < st->nblk; i++)
484 {
485 const uint8_t *q = st->blk[i].ptr;
486
487 if (0 == st->blk[i].size)
488 continue;
489 if ( (up < q + st->blk[i].size) &&
490 (q < up + size) )
491 {
492 fz_report (op, "returned a block overlapping another live allocation");
493 return;
494 }
495 }
496}
497
498
502static void
503fz_check_invariants (struct fz_pool *st,
504 const char *op)
505{
506 size_t total = 0;
507 size_t freem;
508 unsigned int i;
509
510 freem = MHD_pool_get_free (st->pool);
511 if (freem > st->cap)
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;
515 if (total > st->cap)
516 fz_report (op, "the live allocations alone exceed the size of the pool");
517 else if (total + freem > st->cap)
518 fz_report (op,
519 "the live allocations plus the free space exceed the size "
520 "of the pool");
521 if (st->paranoid)
522 fz_verify_all (st, op);
523}
524
525
526static struct fz_block *
527fz_add (struct fz_pool *st,
528 void *ptr,
529 size_t size,
530 bool from_end)
531{
532 struct fz_block *b = &st->blk[st->nblk++];
533
534 b->ptr = (uint8_t *) ptr;
535 b->size = size;
536 b->tag = st->next_tag++;
537 b->from_end = from_end;
538 fz_fill (b->ptr, b->tag, 0, size);
539 return b;
540}
541
542
543static void
544fz_del (struct fz_pool *st,
545 struct fz_block *b)
546{
547 *b = st->blk[--st->nblk];
548}
549
550
559static struct fz_block *
560fz_pick (struct fz_pool *st,
561 uint8_t sel,
562 bool front_only)
563{
564 unsigned int i;
565 unsigned int n = 0;
566 unsigned int idx;
567
568 for (i = 0; i < st->nblk; i++)
569 {
570 if ( (! front_only) ||
571 (! st->blk[i].from_end) )
572 n++;
573 }
574 if (0 == n)
575 return NULL;
576 idx = ((unsigned int) sel) % n;
577 for (i = 0; i < st->nblk; i++)
578 {
579 if ( (front_only) &&
580 (st->blk[i].from_end) )
581 continue;
582 if (0 == idx)
583 return &st->blk[i];
584 idx--;
585 }
586 return NULL; /* unreachable */
587}
588
589
597static size_t
598fz_size (uint8_t sel,
599 size_t cap,
600 size_t freem)
601{
602 size_t d;
603
604 switch (sel & 0x03)
605 {
606 case 0:
607 return (size_t) (sel >> 2); /* 0 .. 63 */
608 case 1:
609 return (((size_t) ((sel >> 2) + 1)) * cap) / 64u;
610 case 2:
611 d = (size_t) ((sel >> 2) & 0x07u);
612 if (0 != (sel & 0x20))
613 return freem + d;
614 return (freem > d) ? (freem - d) : 0;
615 default:
616 return SIZE_MAX - (size_t) (sel >> 2);
617 }
618}
619
620
621static void
622fz_pool_close (struct fz_pool *st)
623{
624 MHD_pool_destroy (st->pool);
625 st->pool = NULL;
626 st->nblk = 0;
627}
628
629
635static bool
636fz_pool_open (struct fz_pool *st,
637 uint8_t sel)
638{
639 size_t max = fz_pool_sizes[((size_t) sel) % FZ_NUM_POOL_SIZES];
640 void *base;
641
642 st->nblk = 0;
643 st->pool = MHD_pool_create (max);
644 if (NULL == st->pool)
645 return false;
646 st->cap = MHD_pool_get_free (st->pool) + FZ_RED_ZONE_SIZE;
647 if (st->cap != fz_round (max))
648 fz_report ("MHD_pool_create",
649 "a fresh pool does not offer the requested size rounded "
650 "up to the alignment");
651 /* MHD_pool_reset() with nothing to keep returns the start of the
652 pool; connection.c:3021 relies on exactly this call. It is the
653 only way to learn the base address through the public interface. */
654 base = MHD_pool_reset (st->pool, NULL, 0, 0);
655 if (NULL == base)
656 {
657 fz_report ("MHD_pool_reset", "returned NULL for an empty pool");
658 fz_pool_close (st);
659 return false;
660 }
661 st->base = (uint8_t *) base;
662 return true;
663}
664
665
666/* ------------------------------------------------------------------ */
667/* The individual operations */
668/* ------------------------------------------------------------------ */
669
673static void
674fz_op_alloc (struct fz_pool *st,
675 const uint8_t *op,
676 bool prefer_end)
677{
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];
682 size_t freem;
683 size_t after;
684 size_t size;
685 void *p;
686
687 if (st->nblk >= FZ_MAX_BLOCKS)
688 return;
689 freem = MHD_pool_get_free (st->pool);
690 size = fz_size (op[2], st->cap, freem);
691 p = MHD_pool_allocate (st->pool, size, from_end);
692 after = MHD_pool_get_free (st->pool);
693 if (NULL == p)
694 {
696 if (after != freem)
697 fz_report (name, "a failed allocation changed the amount of free space");
698 if ( (0 != fz_round (size)) &&
699 (fz_round (size) <= freem) )
700 fz_report (name,
701 "allocation failed although MHD_pool_get_free() reported "
702 "room for it");
703 return;
704 }
706 if (after > freem)
707 fz_report (name, "MHD_pool_get_free() increased across an allocation");
708 else if (freem - after < size)
709 fz_report (name,
710 "MHD_pool_get_free() dropped by less than the allocated size");
711 fz_check_ptr (st, p, size, name);
712 (void) fz_add (st, p, size, from_end);
713}
714
715
721static void
722fz_op_alloc_all (struct fz_pool *st,
723 const uint8_t *op)
724{
725 static const char name[] = "MHD_pool_allocate (all free)";
726 const bool from_end = (0 != (op[1] & 0x01));
727 size_t freem;
728 void *p;
729
730 if (st->nblk >= FZ_MAX_BLOCKS)
731 return;
732 freem = MHD_pool_get_free (st->pool);
733 if (0 == freem)
734 return;
735 p = MHD_pool_allocate (st->pool, freem, from_end);
736 if (NULL == p)
737 {
739 fz_report (name,
740 "allocating exactly MHD_pool_get_free() bytes failed");
741 return;
742 }
744 fz_check_ptr (st, p, freem, name);
745 if (0 != MHD_pool_get_free (st->pool))
746 fz_report (name,
747 "the pool still reports free space after all of it was "
748 "allocated");
749 (void) fz_add (st, p, freem, from_end);
750}
751
752
756static void
757fz_op_try_alloc (struct fz_pool *st,
758 const uint8_t *op)
759{
760 static const char name[] = "MHD_pool_try_alloc";
761 size_t freem;
762 size_t after;
763 size_t size;
764 size_t need;
765 void *p;
766
767 if (st->nblk >= FZ_MAX_BLOCKS)
768 return;
769 freem = MHD_pool_get_free (st->pool);
770 size = fz_size (op[2], st->cap, freem);
771 need = 0x5A5A5A5Au; /* poor man's "was it written at all" */
772 p = MHD_pool_try_alloc (st->pool, size, &need);
773 after = MHD_pool_get_free (st->pool);
774 if (NULL == p)
775 {
777 if (after != freem)
778 fz_report (name, "a failed allocation changed the amount of free space");
779 if (0 == need)
780 fz_report (name,
781 "the allocation failed but no additional memory is "
782 "reported to be required");
783 else if ( (SIZE_MAX != need) &&
784 (need > st->cap) )
785 fz_report (name,
786 "more memory is reported to be required than the pool "
787 "has in total");
788 if ( (0 != fz_round (size)) &&
789 (fz_round (size) <= freem) )
790 fz_report (name,
791 "allocation failed although MHD_pool_get_free() reported "
792 "room for it");
793 return;
794 }
796 if (0 != need)
797 fz_report (name,
798 "the allocation succeeded but required_bytes was not "
799 "cleared");
800 if (after > freem)
801 fz_report (name, "MHD_pool_get_free() increased across an allocation");
802 else if (freem - after < size)
803 fz_report (name,
804 "MHD_pool_get_free() dropped by less than the allocated size");
805 fz_check_ptr (st, p, size, name);
806 /* try_alloc always allocates "from the end" */
807 (void) fz_add (st, p, size, true);
808}
809
810
819static void
820fz_op_squeeze (struct fz_pool *st,
821 const uint8_t *op)
822{
823 static const char name[] = "MHD_pool_try_alloc (squeeze)";
824 size_t size;
825 size_t need = 0;
826 size_t need2 = 0;
827 void *p;
828 unsigned int i;
829 struct fz_block *victim = NULL;
830
831 if (st->nblk >= FZ_MAX_BLOCKS)
832 return;
833 size = fz_size (op[2], st->cap, MHD_pool_get_free (st->pool));
834 p = MHD_pool_try_alloc (st->pool, size, &need);
835 if (NULL != p)
836 {
837 fz_check_ptr (st, p, size, name);
838 (void) fz_add (st, p, size, true);
839 return;
840 }
841 if ( (0 == need) ||
842 (SIZE_MAX == need) )
843 return;
844 for (i = 0; i < st->nblk; i++)
845 {
846 if (st->blk[i].from_end)
847 continue;
848 if (st->blk[i].size < need)
849 continue;
850 if (! MHD_pool_is_resizable_inplace (st->pool,
851 st->blk[i].ptr,
852 st->blk[i].size))
853 continue;
854 victim = &st->blk[i];
855 break;
856 }
857 if (NULL == victim)
858 return;
859 {
860 const size_t new_size = victim->size - need;
861 void *shrunk = MHD_pool_reallocate (st->pool,
862 victim->ptr,
863 victim->size,
864 new_size);
865
866 if (NULL == shrunk)
867 {
868 fz_report (name,
869 "shrinking a block that is resizable in-place failed");
870 return;
871 }
872 if (shrunk != victim->ptr)
873 fz_report (name,
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");
879 }
880 p = MHD_pool_try_alloc (st->pool, size, &need2);
881 if (NULL == p)
882 {
883 fz_report (name,
884 "the allocation still fails after freeing the number of "
885 "bytes that required_bytes asked for");
886 return;
887 }
888 fz_check_ptr (st, p, size, name);
889 (void) fz_add (st, p, size, true);
890}
891
892
899static void
900fz_op_realloc (struct fz_pool *st,
901 const uint8_t *op)
902{
903 static const char name[] = "MHD_pool_reallocate";
904 struct fz_block *b = fz_pick (st, op[1], true);
905 struct fz_block saved;
906 size_t freem;
907 size_t after;
908 size_t new_size;
909 bool inplace;
910 void *p;
911
912 if (NULL == b)
913 return;
914 freem = MHD_pool_get_free (st->pool);
915 new_size = fz_size (op[2], st->cap, freem);
916 if ( (0 == b->size) &&
917 (new_size > SIZE_MAX - FZ_ALIGN_SIZE) &&
919 return; /* open finding F2, see above */
920 inplace = MHD_pool_is_resizable_inplace (st->pool, b->ptr, b->size);
921 saved = *b;
922 p = MHD_pool_reallocate (st->pool, b->ptr, b->size, new_size);
923 after = MHD_pool_get_free (st->pool);
924 if (NULL == p)
925 {
926 /* "old continues to be valid for old_size" */
927 if (after != freem)
928 fz_report (name,
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");
932 if ( (inplace) &&
933 (new_size <= saved.size + freem) )
934 fz_report (name,
935 "reallocation failed although the block is resizable "
936 "in-place and the pool has the required free space");
937 return;
938 }
939 if ( (inplace) &&
940 (p != saved.ptr) )
941 fz_report (name,
942 "a block that MHD_pool_is_resizable_inplace() accepted was "
943 "moved");
944 if ( (new_size >= saved.size) &&
945 (after > freem) )
946 fz_report (name,
947 "MHD_pool_get_free() increased across a growing "
948 "reallocation");
949 /* the old location is gone as far as the model is concerned */
950 fz_del (st, b);
951 if (p != saved.ptr)
953 fz_check_ptr (st, p, new_size, name);
954 fz_verify ((const uint8_t *) p,
955 (new_size < saved.size) ? new_size : saved.size,
956 saved.tag,
957 name,
958 "reallocation did not preserve the contents of the block");
959 b = &st->blk[st->nblk++];
960 b->ptr = (uint8_t *) p;
961 b->size = new_size;
962 b->tag = saved.tag;
963 b->from_end = false;
964 if (new_size > saved.size)
965 fz_fill (b->ptr, b->tag, saved.size, new_size);
966}
967
968
974static void
975fz_op_realloc_new (struct fz_pool *st,
976 const uint8_t *op)
977{
978 static const char name[] = "MHD_pool_reallocate (fresh)";
979 size_t freem;
980 size_t size;
981 void *p;
982
983 if (st->nblk >= FZ_MAX_BLOCKS)
984 return;
985 freem = MHD_pool_get_free (st->pool);
986 size = fz_size (op[2], st->cap, freem);
987 p = MHD_pool_reallocate (st->pool, NULL, 0, size);
988 if (NULL == p)
989 {
991 if ( (0 != fz_round (size)) &&
992 (fz_round (size) <= freem) )
993 fz_report (name,
994 "allocation failed although MHD_pool_get_free() reported "
995 "room for it");
996 return;
997 }
999 if (MHD_pool_get_free (st->pool) > freem)
1000 fz_report (name, "MHD_pool_get_free() increased across an allocation");
1001 fz_check_ptr (st, p, size, name);
1002 (void) fz_add (st, p, size, false);
1003}
1004
1005
1012static void
1013fz_op_dealloc (struct fz_pool *st,
1014 const uint8_t *op)
1015{
1016 static const char name[] = "MHD_pool_deallocate";
1017 struct fz_block *b = fz_pick (st, op[1], false);
1018 size_t freem;
1019 size_t after;
1020
1021 freem = MHD_pool_get_free (st->pool);
1022 if ( (NULL != b) &&
1023 (b->from_end) &&
1024 (0 != b->size) &&
1025 (0 == freem) &&
1027 {
1028 /* See the comment on full_dealloc_enabled: this is an open finding,
1029 not a precondition of MHD_pool_deallocate(). The lowest-addressed
1030 live "from the end" block of non-zero size starts exactly at
1031 pool->end, which for a full pool is also pool->pos -- the
1032 ambiguous case. Any block above it is unaffected, so only that
1033 one block is spared. Zero-sized blocks do not count: they consume
1034 nothing, so they can sit below pool->end once a later
1035 deallocation has moved pool->end back up past them. */
1036 unsigned int i;
1037
1038 for (i = 0; i < st->nblk; i++)
1039 {
1040 if ( (st->blk[i].from_end) &&
1041 (0 != st->blk[i].size) &&
1042 (st->blk[i].ptr < b->ptr) )
1043 break;
1044 }
1045 if (i == st->nblk)
1046 return;
1047 }
1048 if (NULL == b)
1049 {
1050 MHD_pool_deallocate (st->pool, NULL, 0);
1051 }
1052 else
1053 {
1054 fz_verify (b->ptr, b->size, b->tag, name,
1055 "the contents of the block changed before it was freed");
1056 MHD_pool_deallocate (st->pool, b->ptr, b->size);
1057 fz_del (st, b);
1058 }
1059 after = MHD_pool_get_free (st->pool);
1060 if (after < freem)
1061 fz_report (name, "deallocation reduced the amount of free space");
1062}
1063
1064
1070static void
1071fz_op_reset (struct fz_pool *st,
1072 const uint8_t *op)
1073{
1074 static const char name[] = "MHD_pool_reset";
1075 struct fz_block *b = fz_pick (st, (uint8_t) (op[1] & 0x0F), false);
1076 size_t new_size;
1077 size_t copy;
1078 uint8_t tag = 0;
1079 void *p;
1080
1081 new_size = fz_size (op[2], st->cap, MHD_pool_get_free (st->pool));
1082 if (new_size > st->cap)
1083 new_size = st->cap;
1084 copy = 0;
1085 if (NULL != b)
1086 {
1087 copy = (b->size * ((size_t) (op[1] >> 4))) / 15u;
1088 if (copy > b->size)
1089 copy = b->size;
1090 if (copy > new_size)
1091 copy = new_size;
1092 tag = b->tag;
1093 fz_verify (b->ptr, b->size, b->tag, name,
1094 "the contents of the kept block changed before the reset");
1095 }
1096 p = MHD_pool_reset (st->pool,
1097 (NULL != b) ? b->ptr : NULL,
1098 copy,
1099 new_size);
1100 stat_resets++;
1101 /* every allocation is gone now */
1102 st->nblk = 0;
1103 if (NULL == p)
1104 {
1105 fz_report (name, "returned NULL");
1106 return;
1107 }
1108 fz_check_ptr (st, p, new_size, name);
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);
1112 /* fz_add() has just re-tagged and re-filled the whole block */
1113}
1114
1115
1119static void
1120fz_op_resizable (struct fz_pool *st,
1121 const uint8_t *op)
1122{
1123 static const char name[] = "MHD_pool_is_resizable_inplace";
1124 struct fz_block *b = fz_pick (st, op[1], false);
1125 bool r;
1126
1127 if ( (NULL == b) ||
1128 (0 != (op[1] & 0x80)) )
1129 {
1130 if (MHD_pool_is_resizable_inplace (st->pool, NULL, 0))
1131 fz_report (name, "an unallocated block is reported as resizable");
1132 return;
1133 }
1134 r = MHD_pool_is_resizable_inplace (st->pool, b->ptr, b->size);
1135 if ( (r) &&
1136 (b->from_end) &&
1137 (0 != b->size) )
1138 fz_report (name,
1139 "a block allocated from the end is reported as resizable "
1140 "in-place");
1141 if (! r)
1142 return;
1143 /* A block that is resizable in-place must survive a resize to its own
1144 size without moving; connection.c asserts this after every such
1145 reallocation. */
1146 {
1147 void *p = MHD_pool_reallocate (st->pool, b->ptr, b->size, b->size);
1148
1149 if (NULL == p)
1150 fz_report (name,
1151 "reallocating a resizable block to its own size failed");
1152 else if (p != b->ptr)
1153 fz_report (name,
1154 "reallocating a resizable block to its own size moved it");
1155 }
1156}
1157
1158
1159static void
1160fz_do_op (struct fz_pool *st,
1161 const uint8_t *op,
1162 bool prefer_end)
1163{
1164 const char *name = "operation";
1165
1166 stat_ops++;
1167 switch ((enum fz_op) (op[0] % (uint8_t) FZ_OP_COUNT))
1168 {
1169 case FZ_OP_ALLOC:
1170 fz_op_alloc (st, op, prefer_end);
1171 break;
1172 case FZ_OP_ALLOC_ALL:
1173 fz_op_alloc_all (st, op);
1174 break;
1175 case FZ_OP_TRY_ALLOC:
1176 fz_op_try_alloc (st, op);
1177 break;
1178 case FZ_OP_SQUEEZE:
1179 fz_op_squeeze (st, op);
1180 break;
1181 case FZ_OP_REALLOC:
1182 fz_op_realloc (st, op);
1183 break;
1184 case FZ_OP_REALLOC_NEW:
1185 fz_op_realloc_new (st, op);
1186 break;
1187 case FZ_OP_DEALLOC:
1188 fz_op_dealloc (st, op);
1189 break;
1190 case FZ_OP_RESET:
1191 fz_op_reset (st, op);
1192 break;
1193 case FZ_OP_GET_FREE:
1194 name = "MHD_pool_get_free";
1195 break;
1196 case FZ_OP_RESIZABLE:
1197 fz_op_resizable (st, op);
1198 break;
1199 case FZ_OP_VERIFY:
1200 name = "verify";
1201 fz_verify_all (st, name);
1202 break;
1203 case FZ_OP_RECREATE:
1204 fz_pool_close (st);
1205 if (! fz_pool_open (st, op[1]))
1206 return;
1207 break;
1208 case FZ_OP_COUNT:
1209 default:
1210 break;
1211 }
1212 fz_check_invariants (st, name);
1213}
1214
1215
1216int
1218 size_t size)
1219{
1220 static bool inited = false;
1221 struct fz_pool st;
1222 size_t nops;
1223 size_t i;
1224
1225 if (size < 5)
1226 return 0;
1227 if (! inited)
1228 {
1229 inited = true;
1230 /* Sets the page size used by MHD_pool_create(); MHD does this once
1231 from MHD_start_daemon(). */
1233 (void) atexit (&print_stats);
1234 }
1235 if (! known_bugs_read)
1236 {
1237 const char *e;
1238
1239 known_bugs_read = 1;
1240 e = getenv ("MHD_FUZZ_POOL_FULL_DEALLOC");
1241 if (NULL != e)
1242 full_dealloc_enabled = (0 != atoi (e));
1243 e = getenv ("MHD_FUZZ_POOL_WRAP_REALLOC");
1244 if (NULL != e)
1245 wrap_realloc_enabled = (0 != atoi (e));
1246 }
1247 memset (&st, 0, sizeof (st));
1248 st.paranoid = (0 != (data[1] & 0x01));
1249 if (! fz_pool_open (&st, data[0]))
1250 return 0;
1251 nops = (size - 2) / 3;
1252 if (nops > FZ_MAX_OPS)
1253 nops = FZ_MAX_OPS;
1254 for (i = 0; i < nops; i++)
1255 {
1256 if (NULL == st.pool)
1257 break;
1258 fz_do_op (&st, data + 2 + 3 * i, (0 != (data[1] & 0x02)));
1259 }
1260 fz_verify_all (&st, "final");
1261 fz_pool_close (&st); /* MHD_pool_destroy() tolerates a NULL pool */
1262 return 0;
1263}
1264
1265
1266/* ------------------------------------------------------------------ */
1267/* Generator */
1268/* ------------------------------------------------------------------ */
1269
1290
1291
1297static uint8_t
1299{
1300 const uint32_t k = fuzz_below (rng, 100);
1301 uint32_t d;
1302 uint32_t sign;
1303
1304 if (k < 35) /* tiny */
1305 return (uint8_t) ((fuzz_below (rng, 64) << 2) | 0u);
1306 if (k < 60) /* fraction of the pool */
1307 return (uint8_t) ((fuzz_below (rng, 64) << 2) | 1u);
1308 if (k < 95)
1309 { /* around the free space */
1310 /* Two statements, not one expression: the order in which the
1311 operands of '|' are evaluated is unspecified, and both calls
1312 advance the PRNG, so a single expression would make the generated
1313 stream compiler-dependent. */
1314 d = fuzz_below (rng, 8);
1315 sign = fuzz_below (rng, 2);
1316 return (uint8_t) ((d << 2) | (sign << 5) | 2u);
1317 }
1318 return (uint8_t) ((fuzz_below (rng, 64) << 2) | 3u); /* value wrap */
1319}
1320
1321
1322static size_t
1324 uint8_t *buf,
1325 size_t cap)
1326{
1327 size_t len = 0;
1328 unsigned int nops;
1329 unsigned int i;
1330 unsigned int psel;
1331 uint8_t flags = 0;
1332
1333 if (cap < 8)
1334 return 0;
1335 /* Small pools are where the interesting paths are, so bias towards
1336 them, but keep the whole table reachable. */
1337 if (fuzz_chance (rng, 3))
1338 psel = fuzz_below (rng, (uint32_t) FZ_NUM_POOL_SIZES);
1339 else
1340 psel = fuzz_below (rng, 16);
1341 buf[len++] = (uint8_t) psel;
1342 /* One PRNG call per statement, see gen_size_sel(). */
1343 if (fuzz_chance (rng, 4))
1344 flags |= 0x01;
1345 if (fuzz_chance (rng, 8))
1346 flags |= 0x02;
1347 buf[len++] = flags;
1348 nops = 1 + fuzz_below (rng, FZ_MAX_OPS);
1349 for (i = 0; i < nops; i++)
1350 {
1351 if (len + 3 > cap)
1352 break;
1353 buf[len++] = gen_ops[fuzz_below (rng, (uint32_t) (sizeof (gen_ops)))];
1354 buf[len++] = fuzz_byte (rng);
1355 buf[len++] = gen_size_sel (rng);
1356 }
1357 return len;
1358}
1359
1360
1361/* ------------------------------------------------------------------ */
1362/* Seed corpus */
1363/* ------------------------------------------------------------------ */
1364
1365/* Size selectors, see fz_size() */
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)
1372
1373/* Pool size selectors, indices into fz_pool_sizes[] */
1374#define PS_1 0
1375#define PS_16 2
1376#define PS_32 4
1377#define PS_64 6
1378#define PS_128 8
1379#define PS_256 11
1380#define PS_512 14
1381#define PS_1024 16
1382#define PS_1500 18
1383#define PS_32768 23
1384
1385#define OPR(o,b,s) ((uint8_t) (o)), ((uint8_t) (b)), (s)
1386
1387static const uint8_t seed_grow_shrink[] = {
1388 PS_512, 0x01,
1389 OPR (FZ_OP_ALLOC, 0x00, SZ_TINY (32)),
1390 OPR (FZ_OP_REALLOC, 0x00, SZ_TINY (63)),
1391 OPR (FZ_OP_REALLOC, 0x00, SZ_TINY (8)),
1392 OPR (FZ_OP_REALLOC, 0x00, SZ_FRAC (32)),
1393 OPR (FZ_OP_VERIFY, 0x00, SZ_TINY (0)),
1394 OPR (FZ_OP_REALLOC, 0x00, SZ_TINY (1)),
1395 OPR (FZ_OP_DEALLOC, 0x00, SZ_TINY (0))
1396};
1397
1398static const uint8_t seed_two_blocks_realloc[] = {
1399 PS_256, 0x01,
1400 OPR (FZ_OP_ALLOC, 0x00, SZ_TINY (17)),
1401 OPR (FZ_OP_ALLOC, 0x00, SZ_TINY (23)),
1402 /* the first block is no longer the last one: it has to move */
1403 OPR (FZ_OP_REALLOC, 0x00, SZ_TINY (60)),
1404 OPR (FZ_OP_VERIFY, 0x00, SZ_TINY (0)),
1405 OPR (FZ_OP_REALLOC, 0x01, SZ_TINY (40)),
1406 OPR (FZ_OP_VERIFY, 0x00, SZ_TINY (0))
1407};
1408
1409static const uint8_t seed_from_end[] = {
1410 PS_128, 0x01,
1411 OPR (FZ_OP_ALLOC, 0x01, SZ_TINY (16)),
1412 OPR (FZ_OP_ALLOC, 0x01, SZ_TINY (1)),
1413 OPR (FZ_OP_ALLOC, 0x00, SZ_TINY (16)),
1414 OPR (FZ_OP_RESIZABLE, 0x00, SZ_TINY (0)),
1415 OPR (FZ_OP_DEALLOC, 0x00, SZ_TINY (0)),
1416 OPR (FZ_OP_ALLOC, 0x01, SZ_TINY (16))
1417};
1418
1419static const uint8_t seed_fill_exactly[] = {
1420 PS_128, 0x01,
1421 OPR (FZ_OP_ALLOC, 0x01, SZ_TINY (16)),
1422 OPR (FZ_OP_ALLOC_ALL, 0x00, SZ_TINY (0)),
1423 OPR (FZ_OP_GET_FREE, 0x00, SZ_TINY (0)),
1424 OPR (FZ_OP_ALLOC, 0x00, SZ_TINY (1)),
1425 OPR (FZ_OP_TRY_ALLOC, 0x00, SZ_TINY (1))
1426};
1427
1428static const uint8_t seed_squeeze[] = {
1429 PS_512, 0x01,
1430 OPR (FZ_OP_ALLOC, 0x00, SZ_FREE),
1431 OPR (FZ_OP_SQUEEZE, 0x00, SZ_TINY (40)),
1432 OPR (FZ_OP_SQUEEZE, 0x00, SZ_TINY (7)),
1433 OPR (FZ_OP_VERIFY, 0x00, SZ_TINY (0)),
1434 OPR (FZ_OP_SQUEEZE, 0x00, SZ_FRAC (8))
1435};
1436
1437static const uint8_t seed_squeeze_small[] = {
1438 PS_128, 0x01,
1439 OPR (FZ_OP_REALLOC_NEW, 0x00, SZ_FREE_M (2)),
1440 OPR (FZ_OP_SQUEEZE, 0x00, SZ_TINY (17)),
1441 OPR (FZ_OP_SQUEEZE, 0x00, SZ_TINY (17)),
1442 OPR (FZ_OP_SQUEEZE, 0x00, SZ_TINY (17))
1443};
1444
1445static const uint8_t seed_reset_keep[] = {
1446 PS_1500, 0x01,
1447 OPR (FZ_OP_ALLOC, 0x00, SZ_TINY (60)),
1448 OPR (FZ_OP_ALLOC, 0x01, SZ_TINY (12)),
1449 OPR (FZ_OP_RESET, 0xF0, SZ_FRAC (31)),
1450 OPR (FZ_OP_VERIFY, 0x00, SZ_TINY (0)),
1451 OPR (FZ_OP_RESET, 0xF0, SZ_TINY (4)),
1452 OPR (FZ_OP_RESET, 0x00, SZ_TINY (0))
1453};
1454
1455static const uint8_t seed_reset_full[] = {
1456 PS_256, 0x01,
1457 OPR (FZ_OP_ALLOC, 0x00, SZ_FRAC (63)),
1458 OPR (FZ_OP_RESET, 0xF0, SZ_FRAC (63)),
1459 OPR (FZ_OP_RESET, 0xF0, SZ_FREE_P (1)),
1460 OPR (FZ_OP_VERIFY, 0x00, SZ_TINY (0))
1461};
1462
1463static const uint8_t seed_boundary[] = {
1464 PS_64, 0x01,
1465 OPR (FZ_OP_ALLOC, 0x00, SZ_FREE_M (1)),
1466 OPR (FZ_OP_ALLOC, 0x00, SZ_FREE),
1467 OPR (FZ_OP_ALLOC, 0x01, SZ_FREE_P (1)),
1468 OPR (FZ_OP_TRY_ALLOC, 0x00, SZ_FREE),
1469 OPR (FZ_OP_DEALLOC, 0x00, SZ_TINY (0)),
1470 OPR (FZ_OP_ALLOC, 0x00, SZ_FREE)
1471};
1472
1473static const uint8_t seed_wrap[] = {
1474 PS_256, 0x00,
1475 OPR (FZ_OP_ALLOC, 0x00, SZ_HUGE),
1476 OPR (FZ_OP_ALLOC, 0x01, SZ_HUGE),
1477 OPR (FZ_OP_TRY_ALLOC, 0x00, SZ_HUGE),
1478 OPR (FZ_OP_REALLOC_NEW, 0x00, SZ_HUGE),
1479 OPR (FZ_OP_ALLOC, 0x00, SZ_TINY (16)),
1480 OPR (FZ_OP_REALLOC, 0x00, SZ_HUGE),
1481 OPR (FZ_OP_VERIFY, 0x00, SZ_TINY (0))
1482};
1483
1484static const uint8_t seed_tiny_pool[] = {
1485 PS_1, 0x01,
1486 OPR (FZ_OP_ALLOC, 0x00, SZ_TINY (1)),
1487 OPR (FZ_OP_ALLOC, 0x01, SZ_TINY (1)),
1488 OPR (FZ_OP_GET_FREE, 0x00, SZ_TINY (0)),
1489 OPR (FZ_OP_RESET, 0xF0, SZ_TINY (1)),
1490 OPR (FZ_OP_DEALLOC, 0x00, SZ_TINY (0))
1491};
1492
1493static const uint8_t seed_zero_sizes[] = {
1494 PS_32, 0x01,
1495 OPR (FZ_OP_ALLOC, 0x00, SZ_TINY (0)),
1496 OPR (FZ_OP_ALLOC, 0x01, SZ_TINY (0)),
1497 OPR (FZ_OP_REALLOC, 0x00, SZ_TINY (0)),
1498 OPR (FZ_OP_REALLOC, 0x00, SZ_TINY (4)),
1499 OPR (FZ_OP_DEALLOC, 0x00, SZ_TINY (0)),
1500 OPR (FZ_OP_RESET, 0x00, SZ_TINY (0))
1501};
1502
1503static const uint8_t seed_many_small[] = {
1504 PS_1500, 0x01,
1505 OPR (FZ_OP_ALLOC, 0x00, SZ_TINY (5)),
1506 OPR (FZ_OP_ALLOC, 0x01, SZ_TINY (5)),
1507 OPR (FZ_OP_ALLOC, 0x00, SZ_TINY (5)),
1508 OPR (FZ_OP_ALLOC, 0x01, SZ_TINY (5)),
1509 OPR (FZ_OP_ALLOC, 0x00, SZ_TINY (5)),
1510 OPR (FZ_OP_ALLOC, 0x01, SZ_TINY (5)),
1511 OPR (FZ_OP_REALLOC, 0x00, SZ_TINY (33)),
1512 OPR (FZ_OP_REALLOC, 0x01, SZ_TINY (33)),
1513 OPR (FZ_OP_DEALLOC, 0x02, SZ_TINY (0)),
1514 OPR (FZ_OP_VERIFY, 0x00, SZ_TINY (0)),
1515 OPR (FZ_OP_ALLOC, 0x00, SZ_TINY (5))
1516};
1517
1518static const uint8_t seed_recreate[] = {
1519 PS_32768, 0x00,
1520 OPR (FZ_OP_ALLOC, 0x00, SZ_FRAC (60)),
1522 OPR (FZ_OP_ALLOC, 0x00, SZ_FREE),
1524 OPR (FZ_OP_ALLOC, 0x01, SZ_TINY (24)),
1525 OPR (FZ_OP_RESET, 0xF0, SZ_FRAC (2))
1526};
1527
1528/* The read-buffer life cycle of a connection: allocate the read buffer,
1529 grow it to everything that is free, put the parsed headers "at the
1530 end", shrink the read buffer to what was actually received, then
1531 reset the pool keeping the received bytes -- connection.c does
1532 exactly this for every keep-alive request. */
1533static const uint8_t seed_connection_cycle[] = {
1534 PS_1500, 0x01,
1535 OPR (FZ_OP_REALLOC_NEW, 0x00, SZ_FRAC (31)),
1536 OPR (FZ_OP_REALLOC, 0x00, SZ_FREE),
1537 OPR (FZ_OP_TRY_ALLOC, 0x00, SZ_TINY (12)),
1538 OPR (FZ_OP_TRY_ALLOC, 0x00, SZ_TINY (20)),
1539 OPR (FZ_OP_SQUEEZE, 0x00, SZ_TINY (40)),
1540 OPR (FZ_OP_REALLOC, 0x00, SZ_TINY (60)),
1541 OPR (FZ_OP_VERIFY, 0x00, SZ_TINY (0)),
1542 OPR (FZ_OP_RESET, 0xF0, SZ_FRAC (31)),
1543 OPR (FZ_OP_REALLOC, 0x00, SZ_FREE),
1544 OPR (FZ_OP_VERIFY, 0x00, SZ_TINY (0))
1545};
1546
1547
1548/* The reproducer of the open finding described at full_dealloc_enabled:
1549 a 128 byte pool, one 16 byte block "from the end", the whole rest of
1550 the pool allocated from the front, then that first block released.
1551 Inert unless MHD_FUZZ_POOL_FULL_DEALLOC=1 is set. */
1552static const uint8_t seed_dealloc_end_full[] = {
1553 PS_128, 0x01,
1554 OPR (FZ_OP_ALLOC, 0x01, SZ_TINY (16)),
1555 OPR (FZ_OP_ALLOC_ALL, 0x00, SZ_TINY (0)),
1556 OPR (FZ_OP_DEALLOC, 0x00, SZ_TINY (0))
1557};
1558
1559
1560/* The reproducer of the open finding F2: MHD_pool_reset() with nothing
1561 to keep leaves a zero-length block at the front boundary, and
1562 reallocating that to SIZE_MAX wraps. Inert unless
1563 MHD_FUZZ_POOL_WRAP_REALLOC=1 is set. */
1564static const uint8_t seed_realloc_wrap[] = {
1565 PS_1024, 0x01,
1566 OPR (FZ_OP_RESET, 0x00, SZ_TINY (0)),
1567 OPR (FZ_OP_REALLOC, 0x00, SZ_HUGE)
1568};
1569
1570
1571struct mp_seed
1572{
1573 const uint8_t *bytes;
1574 size_t len;
1575};
1576
1577#define MSEED(a) { (a), sizeof (a) }
1578
1598
1599
1600static size_t
1602{
1603 return sizeof (mp_seeds) / sizeof (mp_seeds[0]);
1604}
1605
1606
1607static const uint8_t *
1608fuzz_seed_get (size_t idx,
1609 size_t *len)
1610{
1611 *len = mp_seeds[idx].len;
1612 return mp_seeds[idx].bytes;
1613}
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)
#define PS_512
static uint8_t gen_size_sel(struct fuzz_rng *rng)
#define PS_1500
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[]
#define PS_256
static void fz_op_resizable(struct fz_pool *st, const uint8_t *op)
#define PS_32
#define SZ_FREE_P(d)
#define SZ_FRAC(k)
static const uint8_t seed_recreate[]
static void fz_do_op(struct fz_pool *st, const uint8_t *op, bool prefer_end)
#define SZ_HUGE
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)
#define PS_1024
static const uint8_t * fuzz_seed_get(size_t idx, size_t *len)
static const uint8_t seed_dealloc_end_full[]
#define FZ_ALIGN_SIZE
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)
#define SZ_FREE
static void fz_check_invariants(struct fz_pool *st, const char *op)
#define PS_128
static const uint8_t seed_connection_cycle[]
#define FZ_PAT_MAX
int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
static const uint8_t seed_reset_full[]
#define FZ_MAX_OPS
#define MSEED(a)
#define PS_32768
#define FZ_MAX_BLOCKS
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)
#define PS_16
static void print_stats(void)
static const uint8_t seed_zero_sizes[]
#define OPR(o, b, s)
#define SZ_TINY(n)
static struct fz_block * fz_pick(struct fz_pool *st, uint8_t sel, bool front_only)
static unsigned long stat_alloc_fail
@ FZ_OP_REALLOC_NEW
@ FZ_OP_DEALLOC
@ FZ_OP_RECREATE
@ FZ_OP_ALLOC_ALL
@ FZ_OP_RESIZABLE
@ FZ_OP_COUNT
@ FZ_OP_TRY_ALLOC
@ FZ_OP_SQUEEZE
@ FZ_OP_VERIFY
@ FZ_OP_ALLOC
@ FZ_OP_RESET
@ FZ_OP_GET_FREE
@ FZ_OP_REALLOC
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)
#define PS_64
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[]
#define FZ_RED_ZONE_SIZE
#define PS_1
#define SZ_FREE_M(d)
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)
Definition memorypool.c:229
void * MHD_pool_reallocate(struct MemoryPool *pool, void *old, size_t old_size, size_t new_size)
Definition memorypool.c:553
void MHD_pool_destroy(struct MemoryPool *pool)
Definition memorypool.c:361
bool MHD_pool_is_resizable_inplace(struct MemoryPool *pool, void *block, size_t block_size)
Definition memorypool.c:460
void MHD_pool_deallocate(struct MemoryPool *pool, void *block, size_t block_size)
Definition memorypool.c:678
void * MHD_pool_try_alloc(struct MemoryPool *pool, size_t size, size_t *required_bytes)
Definition memorypool.c:501
size_t MHD_pool_get_free(struct MemoryPool *pool)
Definition memorypool.c:394
void * MHD_pool_reset(struct MemoryPool *pool, void *keep, size_t copy_bytes, size_t new_size)
Definition memorypool.c:798
struct MemoryPool * MHD_pool_create(size_t max)
Definition memorypool.c:290
void * MHD_pool_allocate(struct MemoryPool *pool, size_t size, bool from_end)
Definition memorypool.c:419
memory pool; mostly used for efficient (de)allocation for each connection and bounding memory use for...
#define SIZE_MAX
Definition mhd_limits.h:111
#define NULL
void * data