libmicrohttpd2

HTTP server C library (MHD 2.x, alpha)
Log | Files | Refs | README | LICENSE

mempool_funcs.c (24408B)


      1 /* SPDX-License-Identifier: LGPL-2.1-or-later OR (GPL-2.0-or-later WITH eCos-exception-2.0) */
      2 /*
      3   This file is part of GNU libmicrohttpd.
      4   Copyright (C) 2007--2024 Daniel Pittman and Christian Grothoff
      5   Copyright (C) 2014--2024 Evgeny Grin (Karlson2k)
      6 
      7   GNU libmicrohttpd is free software; you can redistribute it and/or
      8   modify it under the terms of the GNU Lesser General Public
      9   License as published by the Free Software Foundation; either
     10   version 2.1 of the License, or (at your option) any later version.
     11 
     12   GNU libmicrohttpd is distributed in the hope that it will be useful,
     13   but WITHOUT ANY WARRANTY; without even the implied warranty of
     14   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     15   Lesser General Public License for more details.
     16 
     17   Alternatively, you can redistribute GNU libmicrohttpd and/or
     18   modify it under the terms of the GNU General Public License as
     19   published by the Free Software Foundation; either version 2 of
     20   the License, or (at your option) any later version, together
     21   with the eCos exception, as follows:
     22 
     23     As a special exception, if other files instantiate templates or
     24     use macros or inline functions from this file, or you compile this
     25     file and link it with other works to produce a work based on this
     26     file, this file does not by itself cause the resulting work to be
     27     covered by the GNU General Public License. However the source code
     28     for this file must still be made available in accordance with
     29     section (3) of the GNU General Public License v2.
     30 
     31     This exception does not invalidate any other reasons why a work
     32     based on this file might be covered by the GNU General Public
     33     License.
     34 
     35   You should have received copies of the GNU Lesser General Public
     36   License and the GNU General Public License along with this library;
     37   if not, see <https://www.gnu.org/licenses/>.
     38 */
     39 
     40 /**
     41  * @file src/mhd2/mempool_funcs.c
     42  * @brief memory pool
     43  * @author Christian Grothoff
     44  * @author Karlson2k (Evgeny Grin)
     45  * TODO:
     46  * + Update code style
     47  * + Detect mmap() in configure (it is purely optional!)
     48  */
     49 #include "mhd_sys_options.h"
     50 #include "mempool_funcs.h"
     51 #include "compat_calloc.h"
     52 
     53 #ifdef HAVE_STDLIB_H
     54 #  include <stdlib.h>
     55 #endif /* HAVE_STDLIB_H */
     56 #include <string.h>
     57 #include "mhd_assert.h"
     58 #ifdef HAVE_SYS_MMAN_H
     59 #  include <sys/mman.h>
     60 #endif
     61 #ifdef _WIN32
     62 #  include <windows.h>
     63 #endif
     64 #ifdef HAVE_SYSCONF
     65 #  include <unistd.h>
     66 #  if defined(_SC_PAGE_SIZE)
     67 #    define MHD_SC_PAGESIZE _SC_PAGE_SIZE
     68 #  elif defined(_SC_PAGESIZE)
     69 #    define MHD_SC_PAGESIZE _SC_PAGESIZE
     70 #  endif /* _SC_PAGESIZE */
     71 #endif /* HAVE_SYSCONF */
     72 
     73 #if defined(MHD_USE_PAGESIZE_MACRO) || defined(MHD_USE_PAGE_SIZE_MACRO)
     74 #  ifndef HAVE_SYSCONF /* Avoid duplicate include */
     75 #    include <unistd.h>
     76 #  endif /* HAVE_SYSCONF */
     77 #  ifdef HAVE_LIMITS_H
     78 #    include <limits.h>
     79 #  endif
     80 #  ifdef HAVE_SYS_PARAM_H
     81 #    include <sys/param.h>
     82 #  endif /* HAVE_SYS_PARAM_H */
     83 #endif /* MHD_USE_PAGESIZE_MACRO || MHD_USE_PAGE_SIZE_MACRO */
     84 
     85 #include "mhd_limits.h"
     86 
     87 #ifndef mhd_FALLBACK_PAGE_SIZE
     88 /**
     89  * Fallback value of page size
     90  */
     91 #  define mhd_FALLBACK_PAGE_SIZE (4096)
     92 #endif
     93 
     94 #if defined(MHD_USE_PAGESIZE_MACRO)
     95 #  define mhd_DEF_PAGE_SIZE PAGESIZE
     96 #elif defined(MHD_USE_PAGE_SIZE_MACRO)
     97 #  define mhd_DEF_PAGE_SIZE PAGE_SIZE
     98 #else  /* ! PAGESIZE */
     99 #  define mhd_DEF_PAGE_SIZE mhd_FALLBACK_PAGE_SIZE
    100 #endif /* ! PAGESIZE */
    101 
    102 
    103 #ifdef MHD_ASAN_POISON_ACTIVE
    104 #include <sanitizer/asan_interface.h>
    105 #endif /* MHD_ASAN_POISON_ACTIVE */
    106 
    107 #if defined(MAP_ANONYMOUS)
    108 #  define mhd_MAP_ANONYMOUS MAP_ANONYMOUS
    109 #endif
    110 
    111 #if ! defined(mhd_MAP_ANONYMOUS) && defined(MAP_ANON)
    112 #  define mhd_MAP_ANONYMOUS MAP_ANON
    113 #endif
    114 
    115 #if defined(mhd_MAP_ANONYMOUS) || defined(_WIN32)
    116 #  define mhd_USE_LARGE_ALLOCS 1
    117 #endif
    118 
    119 #ifdef mhd_USE_LARGE_ALLOCS
    120 #  if defined(_WIN32)
    121 #    define mhd_MAP_FAILED NULL
    122 #  elif defined(MAP_FAILED)
    123 #    define mhd_MAP_FAILED MAP_FAILED
    124 #  else
    125 #    define mhd_MAP_FAILED ((void*) -1)
    126 #  endif
    127 #endif
    128 
    129 /**
    130  * Round up 'n' to a multiple of ALIGN_SIZE.
    131  */
    132 #define mhd_ROUND_TO_ALIGN(n) \
    133         (((n) + (mhd_MEMPOOL_ALIGN_SIZE - 1)) \
    134          / (mhd_MEMPOOL_ALIGN_SIZE) * (mhd_MEMPOOL_ALIGN_SIZE))
    135 
    136 
    137 #ifndef MHD_ASAN_POISON_ACTIVE
    138 #  define mhd_NOSANITIZE_PTRS /**/
    139 #  define mhd_RED_ZONE_SIZE (0)
    140 #  define mhd_ROUND_TO_ALIGN_PLUS_RED_ZONE(n) mhd_ROUND_TO_ALIGN (n)
    141 #  define mhd_POISON_MEMORY(pointer, size) (void) 0
    142 #  define mhd_UNPOISON_MEMORY(pointer, size) (void) 0
    143 /**
    144  * Boolean 'true' if the first pointer is less or equal the second pointer
    145  */
    146 #  define mp_ptr_le_(p1,p2) \
    147         (((const uint8_t*) (p1)) <= ((const uint8_t*) (p2)))
    148 /**
    149  * The difference in bytes between positions of the first and
    150  * the second pointers
    151  */
    152 #  define mp_ptr_diff_(p1,p2) \
    153         ((size_t) (((const uint8_t*) (p1)) - ((const uint8_t*) (p2))))
    154 #else  /* MHD_ASAN_POISON_ACTIVE */
    155 #  define mhd_RED_ZONE_SIZE (mhd_MEMPOOL_ALIGN_SIZE)
    156 #  define mhd_ROUND_TO_ALIGN_PLUS_RED_ZONE(n) \
    157         (mhd_ROUND_TO_ALIGN (n) + mhd_RED_ZONE_SIZE)
    158 #  define mhd_POISON_MEMORY(pointer, size) \
    159         ASAN_POISON_MEMORY_REGION ((pointer), (size))
    160 #  define mhd_UNPOISON_MEMORY(pointer, size) \
    161         ASAN_UNPOISON_MEMORY_REGION ((pointer), (size))
    162 #  if defined(FUNC_PTRCOMPARE_CAST_WORKAROUND_WORKS)
    163 /**
    164  * Boolean 'true' if the first pointer is less or equal the second pointer
    165  */
    166 #    define mp_ptr_le_(p1,p2) \
    167         (((uintptr_t) ((const void*) (p1))) <= \
    168          ((uintptr_t) ((const void*) (p2))))
    169 /**
    170  * The difference in bytes between positions of the first and
    171  * the second pointers
    172  */
    173 #    define mp_ptr_diff_(p1,p2) \
    174         ((size_t) (((uintptr_t) ((const uint8_t*) (p1))) - \
    175                    ((uintptr_t) ((const uint8_t*) (p2)))))
    176 #elif defined(FUNC_ATTR_PTRCOMPARE_WORKS) && \
    177   defined(FUNC_ATTR_PTRSUBTRACT_WORKS)
    178 #    ifndef NDEBUG
    179 /**
    180  * Boolean 'true' if the first pointer is less or equal the second pointer
    181  */
    182 __attribute__((no_sanitize ("pointer-compare"))) static bool
    183 mp_ptr_le_ (const void *p1, const void *p2)
    184 {
    185   return (((const uint8_t *) p1) <= ((const uint8_t *) p2));
    186 }
    187 
    188 
    189 #    endif /* _DEBUG */
    190 
    191 
    192 /**
    193  * The difference in bytes between positions of the first and
    194  * the second pointers
    195  */
    196 __attribute__((no_sanitize ("pointer-subtract"))) static size_t
    197 mp_ptr_diff_ (const void *p1, const void *p2)
    198 {
    199   return (size_t) (((const uint8_t *) p1) - ((const uint8_t *) p2));
    200 }
    201 
    202 
    203 #  elif defined(FUNC_ATTR_NOSANITIZE_WORKS)
    204 #    ifndef NDEBUG
    205 /**
    206  * Boolean 'true' if the first pointer is less or equal the second pointer
    207  */
    208 __attribute__((no_sanitize ("address"))) static bool
    209 mp_ptr_le_ (const void *p1, const void *p2)
    210 {
    211   return (((const uint8_t *) p1) <= ((const uint8_t *) p2));
    212 }
    213 
    214 
    215     #endif /* _DEBUG */
    216 
    217 /**
    218  * The difference in bytes between positions of the first and
    219  * the second pointers
    220  */
    221 __attribute__((no_sanitize ("address"))) static size_t
    222 mp_ptr_diff_ (const void *p1, const void *p2)
    223 {
    224   return (size_t) (((const uint8_t *) p1) - ((const uint8_t *) p2));
    225 }
    226 
    227 
    228 #  else  /* ! FUNC_ATTR_NOSANITIZE_WORKS */
    229 #error User-poisoning cannot be used
    230 #  endif /* ! FUNC_ATTR_NOSANITIZE_WORKS */
    231 #endif /* MHD_ASAN_POISON_ACTIVE */
    232 
    233 #ifdef mhd_USE_LARGE_ALLOCS
    234 /**
    235  * Size of memory page
    236  */
    237 static size_t MHD_sys_page_size_ = (size_t)
    238 #  if defined(MHD_USE_PAGESIZE_MACRO_STATIC)
    239                                    PAGESIZE;
    240 #  elif defined(MHD_USE_PAGE_SIZE_MACRO_STATIC)
    241                                    PAGE_SIZE;
    242 #  else  /* ! MHD_USE_PAGE_SIZE_MACRO_STATIC */
    243                                    mhd_FALLBACK_PAGE_SIZE; /* Default fallback value */
    244 #  endif /* ! MHD_USE_PAGE_SIZE_MACRO_STATIC */
    245 #endif /* mhd_USE_LARGE_ALLOCS */
    246 
    247 void
    248 mhd_init_mem_pools (void)
    249 {
    250 #ifdef mhd_USE_LARGE_ALLOCS
    251 #ifdef MHD_SC_PAGESIZE
    252   long result;
    253   result = sysconf (MHD_SC_PAGESIZE);
    254   if (-1 != result)
    255     MHD_sys_page_size_ = (size_t) result;
    256   else
    257     MHD_sys_page_size_ = (size_t) mhd_DEF_PAGE_SIZE;
    258 #elif defined(_WIN32)
    259   SYSTEM_INFO si;
    260   GetSystemInfo (&si);
    261   MHD_sys_page_size_ = (size_t) si.dwPageSize;
    262 #else
    263   MHD_sys_page_size_ = (size_t) mhd_DEF_PAGE_SIZE;
    264 #endif /* _WIN32 */
    265   mhd_assert (0 == (MHD_sys_page_size_ % mhd_MEMPOOL_ALIGN_SIZE));
    266 #endif /* mhd_USE_LARGE_ALLOCS */
    267   (void) 0;
    268 }
    269 
    270 
    271 /**
    272  * Handle for a memory pool.  Pools are not reentrant and must not be
    273  * used by multiple threads.
    274  */
    275 struct mhd_MemoryPool
    276 {
    277 
    278   /**
    279    * Pointer to the pool's memory
    280    */
    281   uint8_t *memory;
    282 
    283   /**
    284    * Size of the pool.
    285    */
    286   size_t size;
    287 
    288   /**
    289    * Offset of the first unallocated byte.
    290    */
    291   size_t pos;
    292 
    293   /**
    294    * Offset of the byte after the last unallocated byte.
    295    */
    296   size_t end;
    297 
    298 #ifdef mhd_USE_LARGE_ALLOCS
    299   /**
    300    * 'false' if pool was malloc'ed, 'true' if mmapped (VirtualAlloc'ed for W32).
    301    */
    302   bool is_large_alloc;
    303 #endif
    304 
    305   /**
    306    * Memory allocation zeroing mode
    307    */
    308   enum mhd_MemPoolZeroing zeroing;
    309 };
    310 
    311 
    312 MHD_INTERNAL mhd_FN_RET_UNALIASED
    313 mhd_FN_OBJ_CONSTRUCTOR (mhd_pool_destroy)
    314 struct mhd_MemoryPool *
    315 mhd_pool_create (size_t max,
    316                  enum mhd_MemPoolZeroing zeroing)
    317 {
    318   struct mhd_MemoryPool *pool;
    319   size_t alloc_size;
    320 
    321   mhd_assert (max > 0);
    322   mhd_assert (mhd_RED_ZONE_SIZE < (max + mhd_RED_ZONE_SIZE));
    323   max += mhd_RED_ZONE_SIZE;
    324   alloc_size = 0;
    325   pool = (struct mhd_MemoryPool *) malloc (sizeof (struct mhd_MemoryPool));
    326   if (NULL == pool)
    327     return NULL;
    328   pool->zeroing = zeroing;
    329 #ifdef mhd_USE_LARGE_ALLOCS
    330   pool->is_large_alloc = false;
    331   if ( (max <= 32 * 1024) ||
    332        (max < MHD_sys_page_size_ * 4 / 3) )
    333   {
    334     pool->memory = (uint8_t *) mhd_MAP_FAILED;
    335   }
    336   else
    337   {
    338     /* Round up allocation to page granularity. */
    339     alloc_size = max + MHD_sys_page_size_ - 1;
    340     alloc_size -= alloc_size % MHD_sys_page_size_;
    341 #  if defined(mhd_MAP_ANONYMOUS)
    342     pool->memory = (uint8_t *) mmap (NULL,
    343                                      alloc_size,
    344                                      PROT_READ | PROT_WRITE,
    345                                      MAP_PRIVATE | mhd_MAP_ANONYMOUS,
    346                                      -1,
    347                                      0);
    348 #  else  /* ! mhd_MAP_ANONYMOUS */
    349     pool->memory = (uint8_t *) VirtualAlloc (NULL,
    350                                              alloc_size,
    351                                              MEM_COMMIT | MEM_RESERVE,
    352                                              PAGE_READWRITE);
    353 #  endif /* ! mhd_MAP_ANONYMOUS */
    354   }
    355   if (mhd_MAP_FAILED != pool->memory)
    356     pool->is_large_alloc = true;
    357   else
    358 #endif /* mhd_USE_LARGE_ALLOCS */
    359   if (! 0)
    360   {
    361     alloc_size = mhd_ROUND_TO_ALIGN (max);
    362     if (MHD_MEMPOOL_ZEROING_NEVER == zeroing)
    363       pool->memory = (uint8_t *) malloc (alloc_size);
    364     else
    365       pool->memory = (uint8_t *) mhd_calloc (1, alloc_size);
    366     if (((uint8_t *) NULL) == pool->memory)
    367     {
    368       free (pool);
    369       return NULL;
    370     }
    371   }
    372   mhd_assert (0 == (((uintptr_t) pool->memory) % mhd_MEMPOOL_ALIGN_SIZE));
    373   pool->pos = 0;
    374   pool->end = alloc_size;
    375   pool->size = alloc_size;
    376   mhd_assert (0 < alloc_size);
    377   mhd_POISON_MEMORY (pool->memory, pool->size);
    378   return pool;
    379 }
    380 
    381 
    382 MHD_INTERNAL void
    383 mhd_pool_destroy (struct mhd_MemoryPool *restrict pool)
    384 {
    385   if (NULL == pool)
    386     return;
    387 
    388   mhd_assert (pool->end >= pool->pos);
    389   mhd_assert (pool->size >= pool->end - pool->pos);
    390   mhd_assert (pool->pos == mhd_ROUND_TO_ALIGN (pool->pos));
    391   mhd_UNPOISON_MEMORY (pool->memory, pool->size);
    392 #ifdef mhd_USE_LARGE_ALLOCS
    393   if (pool->is_large_alloc)
    394   {
    395 #  if defined(mhd_MAP_ANONYMOUS)
    396     munmap (pool->memory,
    397             pool->size);
    398 #  else
    399     VirtualFree (pool->memory,
    400                  0,
    401                  MEM_RELEASE);
    402 #  endif
    403   }
    404   else
    405 #endif /* mhd_USE_LARGE_ALLOCS*/
    406   if (! 0)
    407     free (pool->memory);
    408 
    409   free (pool);
    410 }
    411 
    412 
    413 MHD_INTERNAL MHD_FN_PAR_NONNULL_ALL_ MHD_FN_PURE_ size_t
    414 mhd_pool_get_size (const struct mhd_MemoryPool *restrict pool)
    415 {
    416   return (pool->size - mhd_RED_ZONE_SIZE);
    417 }
    418 
    419 
    420 MHD_INTERNAL size_t
    421 mhd_pool_get_free (struct mhd_MemoryPool *restrict pool)
    422 {
    423   mhd_assert (pool->end >= pool->pos);
    424   mhd_assert (pool->size >= pool->end - pool->pos);
    425   mhd_assert (pool->pos == mhd_ROUND_TO_ALIGN (pool->pos));
    426 #ifdef MHD_ASAN_POISON_ACTIVE
    427   if ((pool->end - pool->pos) <= mhd_RED_ZONE_SIZE)
    428     return 0;
    429 #endif /* MHD_ASAN_POISON_ACTIVE */
    430   return (pool->end - pool->pos) - mhd_RED_ZONE_SIZE;
    431 }
    432 
    433 
    434 MHD_INTERNAL mhd_FN_RET_UNALIASED
    435 mhd_FN_RET_SIZED (2)
    436 mhd_FN_RET_ALIGNED (mhd_MEMPOOL_ALIGN_SIZE) void *
    437 mhd_pool_allocate (struct mhd_MemoryPool *restrict pool,
    438                    size_t size,
    439                    bool from_end)
    440 {
    441   void *ret;
    442   size_t asize;
    443 
    444   mhd_assert (pool->end >= pool->pos);
    445   mhd_assert (pool->size >= pool->end - pool->pos);
    446   mhd_assert (pool->pos == mhd_ROUND_TO_ALIGN (pool->pos));
    447   asize = mhd_ROUND_TO_ALIGN_PLUS_RED_ZONE (size);
    448   if ( (0 == asize) && (0 != size) )
    449     return NULL; /* size too close to SIZE_MAX */
    450   if (asize > pool->end - pool->pos)
    451     return NULL;
    452   if (from_end)
    453   {
    454     ret = &pool->memory[pool->end - asize];
    455     pool->end -= asize;
    456   }
    457   else
    458   {
    459     ret = &pool->memory[pool->pos];
    460     pool->pos += asize;
    461   }
    462   mhd_UNPOISON_MEMORY (ret, size);
    463   return ret;
    464 }
    465 
    466 
    467 MHD_INTERNAL bool
    468 mhd_pool_is_resizable_inplace (struct mhd_MemoryPool *restrict pool,
    469                                void *restrict block,
    470                                size_t block_size)
    471 {
    472   mhd_assert (pool->end >= pool->pos);
    473   mhd_assert (pool->size >= pool->end - pool->pos);
    474   mhd_assert (block != NULL || block_size == 0);
    475   mhd_assert (pool->size >= block_size);
    476   if (NULL != block)
    477   {
    478     const size_t block_offset = mp_ptr_diff_ (block, pool->memory);
    479     mhd_assert (mp_ptr_le_ (pool->memory, block));
    480     mhd_assert (pool->size >= block_offset);
    481     mhd_assert (pool->size >= block_offset + block_size);
    482     return (pool->pos ==
    483             mhd_ROUND_TO_ALIGN_PLUS_RED_ZONE (block_offset + block_size));
    484   }
    485   return false; /* Unallocated blocks cannot be resized in-place */
    486 }
    487 
    488 
    489 MHD_INTERNAL mhd_FN_RET_UNALIASED
    490 mhd_FN_RET_SIZED (2)
    491 mhd_FN_RET_ALIGNED (mhd_MEMPOOL_ALIGN_SIZE) void *
    492 mhd_pool_try_alloc (struct mhd_MemoryPool *restrict pool,
    493                     size_t size,
    494                     size_t *restrict required_bytes)
    495 {
    496   void *ret;
    497   size_t asize;
    498 
    499   mhd_assert (pool->end >= pool->pos);
    500   mhd_assert (pool->size >= pool->end - pool->pos);
    501   mhd_assert (pool->pos == mhd_ROUND_TO_ALIGN (pool->pos));
    502   asize = mhd_ROUND_TO_ALIGN_PLUS_RED_ZONE (size);
    503   if ( (0 == asize) && (0 != size) )
    504   { /* size is too close to SIZE_MAX, very unlikely */
    505     *required_bytes = SIZE_MAX;
    506     return NULL;
    507   }
    508   if (asize > pool->end - pool->pos)
    509   {
    510     mhd_assert ((pool->end - pool->pos) == \
    511                 mhd_ROUND_TO_ALIGN (pool->end - pool->pos));
    512     if (asize <= pool->end)
    513       *required_bytes = asize - (pool->end - pool->pos);
    514     else
    515       *required_bytes = SIZE_MAX;
    516     return NULL;
    517   }
    518   *required_bytes = 0;
    519   ret = &pool->memory[pool->end - asize];
    520   pool->end -= asize;
    521   mhd_UNPOISON_MEMORY (ret, size);
    522   return ret;
    523 }
    524 
    525 
    526 MHD_INTERNAL
    527 mhd_FN_RET_SIZED (4)
    528 void *
    529 mhd_pool_reallocate (struct mhd_MemoryPool *restrict pool,
    530                      void *restrict old,
    531                      size_t old_size,
    532                      size_t new_size)
    533 {
    534   size_t asize;
    535   uint8_t *new_blc;
    536 
    537   mhd_assert (pool->end >= pool->pos);
    538   mhd_assert (pool->size >= pool->end - pool->pos);
    539   mhd_assert (old != NULL || old_size == 0);
    540   mhd_assert (pool->size >= old_size);
    541   mhd_assert (pool->pos == mhd_ROUND_TO_ALIGN (pool->pos));
    542 #if defined(MHD_ASAN_POISON_ACTIVE) && defined(HAVE___ASAN_REGION_IS_POISONED)
    543   mhd_assert (NULL == __asan_region_is_poisoned (old, old_size));
    544 #endif /* MHD_ASAN_POISON_ACTIVE && HAVE___ASAN_REGION_IS_POISONED */
    545 
    546   if (NULL != old)
    547   {   /* Have previously allocated data */
    548     const size_t old_offset = mp_ptr_diff_ (old, pool->memory);
    549     const bool shrinking = (old_size > new_size);
    550 
    551     mhd_assert (mp_ptr_le_ (pool->memory, old));
    552     /* (pool->memory + pool->size >= (uint8_t*) old + old_size) */
    553     mhd_assert ((pool->size - mhd_RED_ZONE_SIZE) >= (old_offset + old_size));
    554     /* Blocks "from the end" must not be reallocated */
    555     /* (old_size == 0 || pool->memory + pool->pos > (uint8_t*) old) */
    556     mhd_assert ((old_size == 0) || \
    557                 (pool->pos > old_offset));
    558     mhd_assert ((old_size == 0) || \
    559                 ((pool->end - mhd_RED_ZONE_SIZE) >= (old_offset + old_size)));
    560     /* Try resizing in-place */
    561     if (shrinking)
    562     {     /* Shrinking in-place, zero-out freed part */
    563       if (MHD_MEMPOOL_ZEROING_ON_RESET < pool->zeroing)
    564         memset ((uint8_t *) old + new_size, 0, old_size - new_size);
    565       mhd_POISON_MEMORY ((uint8_t *) old + new_size, old_size - new_size);
    566     }
    567     if (pool->pos ==
    568         mhd_ROUND_TO_ALIGN_PLUS_RED_ZONE (old_offset + old_size))
    569     {     /* "old" block is the last allocated block */
    570       const size_t new_apos =
    571         mhd_ROUND_TO_ALIGN_PLUS_RED_ZONE (old_offset + new_size);
    572       if (! shrinking)
    573       {                               /* Grow in-place, check for enough space. */
    574         if ( (new_apos > pool->end) ||
    575              (new_apos < pool->pos) ) /* Value wrap */
    576           return NULL;                /* No space */
    577       }
    578       /* Resized in-place */
    579       pool->pos = new_apos;
    580       mhd_UNPOISON_MEMORY (old, new_size);
    581       return old;
    582     }
    583     if (shrinking)
    584       return old;   /* Resized in-place, freed part remains allocated */
    585   }
    586   /* Need to allocate new block */
    587   asize = mhd_ROUND_TO_ALIGN_PLUS_RED_ZONE (new_size);
    588   if ( ( (0 == asize) &&
    589          (0 != new_size) ) || /* Value wrap, too large new_size. */
    590        (asize > pool->end - pool->pos) ) /* Not enough space */
    591     return NULL;
    592 
    593   new_blc = pool->memory + pool->pos;
    594   pool->pos += asize;
    595 
    596   mhd_UNPOISON_MEMORY (new_blc, new_size);
    597   if (0 != old_size)
    598   {
    599     /* Move data to new block, old block remains allocated */
    600     memcpy (new_blc, old, old_size);
    601     /* Zero-out old block */
    602     if (MHD_MEMPOOL_ZEROING_ON_RESET < pool->zeroing)
    603       memset (old, 0, old_size);
    604     mhd_POISON_MEMORY (old, old_size);
    605   }
    606   return new_blc;
    607 }
    608 
    609 
    610 MHD_INTERNAL void
    611 mhd_pool_deallocate (struct mhd_MemoryPool *restrict pool,
    612                      void *restrict block,
    613                      size_t block_size)
    614 {
    615   mhd_assert (pool->end >= pool->pos);
    616   mhd_assert (pool->size >= pool->end - pool->pos);
    617   mhd_assert (block != NULL || block_size == 0);
    618   mhd_assert (pool->size >= block_size);
    619   mhd_assert (pool->pos == mhd_ROUND_TO_ALIGN (pool->pos));
    620 
    621   if (NULL != block)
    622   {   /* Have previously allocated data */
    623     const size_t block_offset = mp_ptr_diff_ (block, pool->memory);
    624     mhd_assert (mp_ptr_le_ (pool->memory, block));
    625     mhd_assert (block_offset <= pool->size);
    626     mhd_assert ((block_offset != pool->pos) || (block_size == 0));
    627     /* Zero-out deallocated region */
    628     if (0 != block_size)
    629     {
    630       if (MHD_MEMPOOL_ZEROING_ON_RESET < pool->zeroing)
    631         memset (block, 0, block_size);
    632       mhd_POISON_MEMORY (block, block_size);
    633     }
    634 #if ! defined(MHD_FAVOR_SMALL_CODE) && ! defined(MHD_ASAN_POISON_ACTIVE)
    635     else
    636       return; /* Zero size, no need to do anything */
    637 #endif /* ! MHD_FAVOR_SMALL_CODE && ! MHD_ASAN_POISON_ACTIVE */
    638     if (block_offset <= pool->pos)
    639     {
    640       /* "Normal" block, not allocated "from the end". */
    641       const size_t alg_end =
    642         mhd_ROUND_TO_ALIGN_PLUS_RED_ZONE (block_offset + block_size);
    643       mhd_assert (alg_end <= pool->pos);
    644       if (alg_end == pool->pos)
    645       {
    646         /* The last allocated block, return deallocated block to the pool */
    647         size_t alg_start = mhd_ROUND_TO_ALIGN (block_offset);
    648         mhd_assert (alg_start >= block_offset);
    649 #if defined(MHD_ASAN_POISON_ACTIVE)
    650         if (alg_start != block_offset)
    651         {
    652           mhd_POISON_MEMORY (pool->memory + block_offset, \
    653                              alg_start - block_offset);
    654         }
    655         else if (0 != alg_start)
    656         {
    657           bool need_red_zone_before;
    658           mhd_assert (mhd_RED_ZONE_SIZE <= alg_start);
    659 #if defined(HAVE___ASAN_REGION_IS_POISONED)
    660           need_red_zone_before =
    661             (NULL == __asan_region_is_poisoned (pool->memory
    662                                                 + alg_start
    663                                                 - mhd_RED_ZONE_SIZE,
    664                                                 mhd_RED_ZONE_SIZE));
    665 #elif defined(HAVE___ASAN_ADDRESS_IS_POISONED)
    666           need_red_zone_before =
    667             (0 == __asan_address_is_poisoned (pool->memory + alg_start - 1));
    668 #else  /* ! HAVE___ASAN_ADDRESS_IS_POISONED */
    669           need_red_zone_before = true; /* Unknown, assume new red zone needed */
    670 #endif /* ! HAVE___ASAN_ADDRESS_IS_POISONED */
    671           if (need_red_zone_before)
    672           {
    673             mhd_POISON_MEMORY (pool->memory + alg_start, mhd_RED_ZONE_SIZE);
    674             alg_start += mhd_RED_ZONE_SIZE;
    675           }
    676         }
    677 #endif /* MHD_ASAN_POISON_ACTIVE */
    678         mhd_assert (alg_start <= pool->pos);
    679         mhd_assert (alg_start == mhd_ROUND_TO_ALIGN (alg_start));
    680         pool->pos = alg_start;
    681       }
    682     }
    683     else
    684     {
    685       /* Allocated "from the end" block. */
    686       /* The size and the pointers of such block should not be manipulated by
    687          MHD code (block split is disallowed). */
    688       mhd_assert (block_offset >= pool->end);
    689       mhd_assert (mhd_ROUND_TO_ALIGN (block_offset) == block_offset);
    690       if (block_offset == pool->end)
    691       {
    692         /* The last allocated block, return deallocated block to the pool */
    693         const size_t alg_end =
    694           mhd_ROUND_TO_ALIGN_PLUS_RED_ZONE (block_offset + block_size);
    695         pool->end = alg_end;
    696       }
    697     }
    698   }
    699 }
    700 
    701 
    702 MHD_INTERNAL
    703 mhd_FN_RET_SIZED (4) mhd_FN_RET_ALIGNED (mhd_MEMPOOL_ALIGN_SIZE)
    704 void *
    705 mhd_pool_reset (struct mhd_MemoryPool *restrict pool,
    706                 void *restrict keep,
    707                 size_t copy_bytes,
    708                 size_t new_size)
    709 {
    710   mhd_assert (pool->end >= pool->pos);
    711   mhd_assert (pool->size >= pool->end - pool->pos);
    712   mhd_assert (copy_bytes <= new_size);
    713   mhd_assert (copy_bytes + mhd_RED_ZONE_SIZE <= pool->size);
    714   mhd_assert (keep != NULL || copy_bytes == 0);
    715   mhd_assert (keep == NULL || mp_ptr_le_ (pool->memory, keep));
    716   /* (keep == NULL || pool->memory + pool->size >= (uint8_t*) keep + copy_bytes) */
    717   mhd_assert ((keep == NULL) || \
    718               (pool->size >= mp_ptr_diff_ (keep, pool->memory) + copy_bytes));
    719 #if defined(MHD_ASAN_POISON_ACTIVE) && defined(HAVE___ASAN_REGION_IS_POISONED)
    720   mhd_assert (NULL == __asan_region_is_poisoned (keep, copy_bytes));
    721 #endif /* MHD_ASAN_POISON_ACTIVE && HAVE___ASAN_REGION_IS_POISONED */
    722   mhd_UNPOISON_MEMORY (pool->memory, new_size);
    723   if ( (NULL != keep) &&
    724        (keep != pool->memory) )
    725   {
    726     if (0 != copy_bytes)
    727       memmove (pool->memory,
    728                keep,
    729                copy_bytes);
    730   }
    731   if ((MHD_MEMPOOL_ZEROING_NEVER != pool->zeroing) &&
    732       (pool->size > copy_bytes))
    733   {
    734     size_t to_zero;   /** Size of area to zero-out */
    735 
    736     to_zero = pool->size - copy_bytes;
    737     mhd_UNPOISON_MEMORY (pool->memory + copy_bytes, to_zero);
    738 #if defined(mhd_USE_LARGE_ALLOCS) && defined(_WIN32)
    739     if (pool->is_large_alloc)
    740     {
    741       size_t to_recommit;     /** Size of decommitted and re-committed area. */
    742       uint8_t *recommit_addr;
    743       /* Round down to page size */
    744       to_recommit = to_zero - to_zero % MHD_sys_page_size_;
    745       recommit_addr = pool->memory + pool->size - to_recommit;
    746 
    747       /* De-committing and re-committing again clear memory and make
    748        * pages free / available for other needs until accessed. */
    749       if (VirtualFree (recommit_addr,
    750                        to_recommit,
    751                        MEM_DECOMMIT))
    752       {
    753         to_zero -= to_recommit;
    754 
    755         if (recommit_addr != VirtualAlloc (recommit_addr,
    756                                            to_recommit,
    757                                            MEM_COMMIT,
    758                                            PAGE_READWRITE))
    759           abort ();      /* Serious error, must never happen */
    760       }
    761     }
    762 #endif /* mhd_USE_LARGE_ALLOCS && _WIN32 */
    763     memset (&pool->memory[copy_bytes],
    764             0,
    765             to_zero);
    766   }
    767   pool->pos = mhd_ROUND_TO_ALIGN_PLUS_RED_ZONE (new_size);
    768   pool->end = pool->size;
    769   mhd_POISON_MEMORY (((uint8_t *) pool->memory) + new_size, \
    770                      pool->size - new_size);
    771   return pool->memory;
    772 }
    773 
    774 
    775 /* end of memorypool.c */