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 */