libmicrohttpd

HTTP/1.x server C library (MHD 1.x, stable)
Log | Files | Refs | Submodules | README | LICENSE

commit edf692a61627394c26132e203857afc5237495c3
parent 95ad2a9a480435e86dfa1bbd7a6798150320d3bd
Author: Evgeny Grin (Karlson2k) <k2k@narod.ru>
Date:   Wed,  5 Apr 2023 16:48:35 +0300

Implemented and used new function MHD_pool_deallocate()

The new function has special handling for user-poison mode.

Diffstat:
Mconfigure.ac | 3+++
Msrc/microhttpd/connection.c | 27++++++++++++++++++---------
Msrc/microhttpd/memorypool.c | 103+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Msrc/microhttpd/memorypool.h | 18++++++++++++++++++
Msrc/microhttpd/response.c | 33+++++++++++++--------------------
5 files changed, 155 insertions(+), 29 deletions(-)

diff --git a/configure.ac b/configure.ac @@ -4304,6 +4304,9 @@ AS_VAR_IF([enable_sanitizers], ["no"], [:], AS_VAR_IF([ac_cv_header_sanitizer_asan_interface_h],["yes"], [ CFLAGS="${CFLAGS_ac} ${san_CFLAGS} ${san_FLAGS} ${errattr_CFLAGS} ${user_CFLAGS}" + MHD_CHECK_FUNC([__asan_address_is_poisoned],[[#include <sanitizer/asan_interface.h>]], + [[int a_var=1; i][f(__asan_address_is_poisoned((void*) &a_var)) return 3;]] + ) MHD_CHECK_FUNC([__asan_region_is_poisoned],[[#include <sanitizer/asan_interface.h>]], [[int a_var=1; i][f(((void*) 0) != __asan_region_is_poisoned((void*) &a_var, sizeof(a_var))) return 3;]] ) diff --git a/src/microhttpd/connection.c b/src/microhttpd/connection.c @@ -1597,11 +1597,20 @@ connection_shrink_read_buffer (struct MHD_Connection *connection) } mhd_assert (c->read_buffer_offset <= c->read_buffer_size); - new_buf = MHD_pool_reallocate (c->pool, c->read_buffer, c->read_buffer_size, - c->read_buffer_offset); - mhd_assert (c->read_buffer == new_buf); - c->read_buffer = new_buf; - c->read_buffer_size = c->read_buffer_offset; + if (0 == c->read_buffer_offset) + { + MHD_pool_deallocate (c->pool, c->read_buffer, c->read_buffer_size); + c->read_buffer = NULL; + c->read_buffer_size = 0; + } + else + { + new_buf = MHD_pool_reallocate (c->pool, c->read_buffer, c->read_buffer_size, + c->read_buffer_offset); + mhd_assert (c->read_buffer == new_buf); + c->read_buffer = new_buf; + c->read_buffer_size = c->read_buffer_offset; + } } @@ -2424,10 +2433,10 @@ transmit_error_response_len (struct MHD_Connection *connection, { /* Read buffer is not needed anymore, discard it * to free some space for error response. */ - connection->read_buffer = MHD_pool_reallocate (connection->pool, - connection->read_buffer, - connection->read_buffer_size, - 0); + MHD_pool_deallocate (connection->pool, + connection->read_buffer, + connection->read_buffer_size); + connection->read_buffer = NULL; connection->read_buffer_size = 0; connection->read_buffer_offset = 0; } diff --git a/src/microhttpd/memorypool.c b/src/microhttpd/memorypool.c @@ -577,6 +577,109 @@ MHD_pool_reallocate (struct MemoryPool *pool, /** + * Deallocate a block of memory obtained from the pool. + * + * If the given block is not the most recently + * (re)allocated block, the memory of the this block + * allocation may be not released until the pool is + * destroyed or reset. + * + * @param pool memory pool to use for the operation + * @param block the allocated block, the NULL is tolerated + * @param block_size the size of the allocated block + */ +void +MHD_pool_deallocate (struct MemoryPool *pool, + void *block, + size_t block_size) +{ + mhd_assert (pool->end >= pool->pos); + mhd_assert (pool->size >= pool->end - pool->pos); + mhd_assert (block != NULL || block_size == 0); + mhd_assert (pool->size >= block_size); + mhd_assert (pool->pos == ROUND_TO_ALIGN (pool->pos)); + + if (NULL != block) + { /* Have previously allocated data */ + const size_t block_offset = mp_ptr_diff_ (block, pool->memory); + mhd_assert (mp_ptr_le_ (pool->memory, block)); + mhd_assert (block_offset <= pool->size); + mhd_assert ((block_offset != pool->pos) || (block_size == 0)); + /* Zero-out deallocated region */ + if (0 != block_size) + { + memset (block, 0, block_size); + _MHD_POISON_MEMORY (block, block_size); + } +#if ! defined(MHD_FAVOR_SMALL_CODE) && ! defined(MHD_ASAN_POISON_ACTIVE) + else + return; /* Zero size, no need to do anything */ +#endif /* ! MHD_FAVOR_SMALL_CODE && ! MHD_ASAN_POISON_ACTIVE */ + if (block_offset <= pool->pos) + { + /* "Normal" block, not allocated "from the end". */ + const size_t alg_end = + ROUND_TO_ALIGN_PLUS_RED_ZONE (block_offset + block_size); + mhd_assert (alg_end <= pool->pos); + if (alg_end == pool->pos) + { + /* The last allocated block, return deallocated block to the pool */ + size_t alg_start = ROUND_TO_ALIGN (block_offset); + mhd_assert (alg_start >= block_offset); +#if defined(MHD_ASAN_POISON_ACTIVE) + if (alg_start != block_offset) + { + _MHD_POISON_MEMORY (pool->memory + block_offset, \ + alg_start - block_offset); + } + else if (0 != alg_start) + { + bool need_red_zone_before; + mhd_assert (_MHD_RED_ZONE_SIZE <= alg_start); +#if defined(HAVE___ASAN_REGION_IS_POISONED) + need_red_zone_before = + (NULL == __asan_region_is_poisoned (pool->memory + + alg_start + - _MHD_RED_ZONE_SIZE, + _MHD_RED_ZONE_SIZE)); +#elif defined(HAVE___ASAN_ADDRESS_IS_POISONED) + need_red_zone_before = + (0 == __asan_address_is_poisoned (pool->memory + alg_start - 1)); +#else /* ! HAVE___ASAN_ADDRESS_IS_POISONED */ + need_red_zone_before = true; /* Unknown, assume new red zone needed */ +#endif /* ! HAVE___ASAN_ADDRESS_IS_POISONED */ + if (need_red_zone_before) + { + _MHD_POISON_MEMORY (pool->memory + alg_start, _MHD_RED_ZONE_SIZE); + alg_start += _MHD_RED_ZONE_SIZE; + } + } +#endif /* MHD_ASAN_POISON_ACTIVE */ + mhd_assert (alg_start <= pool->pos); + mhd_assert (alg_start == ROUND_TO_ALIGN (alg_start)); + pool->pos = alg_start; + } + } + else + { + /* Allocated "from the end" block. */ + /* The size and the pointers of such block should not be manipulated by + MHD code (block split is disallowed). */ + mhd_assert (block_offset >= pool->end); + mhd_assert (ROUND_TO_ALIGN (block_offset) == block_offset); + if (block_offset == pool->end) + { + /* The last allocated block, return deallocated block to the pool */ + const size_t alg_end = + ROUND_TO_ALIGN_PLUS_RED_ZONE (block_offset + block_size); + pool->end = alg_end; + } + } + } +} + + +/** * Clear all entries from the memory pool except * for @a keep of the given @a copy_bytes. The pointer * returned should be a buffer of @a new_size where diff --git a/src/microhttpd/memorypool.h b/src/microhttpd/memorypool.h @@ -148,6 +148,24 @@ MHD_pool_get_free (struct MemoryPool *pool); /** + * Deallocate a block of memory obtained from the pool. + * + * If the given block is not the most recently + * (re)allocated block, the memory of the this block + * allocation may be not released until the pool is + * destroyed or reset. + * + * @param pool memory pool to use for the operation + * @param block the allocated block, the NULL is tolerated + * @param block_size the size of the allocated block + */ +void +MHD_pool_deallocate (struct MemoryPool *pool, + void *block, + size_t block_size); + + +/** * Clear all entries from the memory pool except * for @a keep of the given @a copy_bytes. The pointer * returned should be a buffer of @a new_size where diff --git a/src/microhttpd/response.c b/src/microhttpd/response.c @@ -2148,28 +2148,21 @@ MHD_response_execute_upgrade_ (struct MHD_Response *response, size_t avail; char *buf; - if (0 != connection->write_buffer_size) - { - mhd_assert (NULL != connection->write_buffer); - /* All data should be sent already */ - mhd_assert (connection->write_buffer_send_offset == \ - connection->write_buffer_append_offset); - (void) MHD_pool_reallocate (pool, connection->write_buffer, - connection->write_buffer_size, 0); - connection->write_buffer_append_offset = 0; - connection->write_buffer_send_offset = 0; - connection->write_buffer_size = 0; - } + /* All data should be sent already */ + mhd_assert (connection->write_buffer_send_offset == \ + connection->write_buffer_append_offset); + MHD_pool_deallocate (pool, connection->write_buffer, + connection->write_buffer_size); + connection->write_buffer_append_offset = 0; + connection->write_buffer_send_offset = 0; + connection->write_buffer_size = 0; connection->write_buffer = NULL; - if (0 != connection->read_buffer_size) - { - mhd_assert (NULL != connection->read_buffer); - (void) MHD_pool_reallocate (pool, connection->read_buffer, - connection->read_buffer_size, 0); - connection->read_buffer_offset = 0; - connection->read_buffer_size = 0; - } + /* Extra read data should be processed already by the application */ + MHD_pool_deallocate (pool, connection->read_buffer, + connection->read_buffer_size); + connection->read_buffer_offset = 0; + connection->read_buffer_size = 0; connection->read_buffer = NULL; avail = MHD_pool_get_free (pool);