libmicrohttpd2

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

commit 9d1a39ab1400bbe2fe618d5e1c6718fe047b4c73
parent 797cfc8b8c6edae5202fd5dd4355de023c911295
Author: Evgeny Grin (Karlson2k) <k2k@drgrin.dev>
Date:   Fri, 25 Jul 2025 19:14:19 +0200

mhd_atomic_counter: aligned with stdatomic, added over-/underflow checks for all implementations

Get + increment/decrement functions return now the value before
increment/decrement.
Previously such functions returned final value.

Diffstat:
Msrc/mhd2/auth_digest.c | 4++--
Msrc/mhd2/mhd_atomic_counter.c | 21+++++++++------------
Msrc/mhd2/mhd_atomic_counter.h | 235+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--------------------
Msrc/mhd2/response_destroy.c | 6+++---
4 files changed, 189 insertions(+), 77 deletions(-)

diff --git a/src/mhd2/auth_digest.c b/src/mhd2/auth_digest.c @@ -292,7 +292,7 @@ gen_new_nonce (struct MHD_Daemon *restrict d, mhd_assert (d == c->daemon); mhd_assert (0 != d->auth_dg.cfg.nonce_tmout); - gen_num = mhd_atomic_counter_inc_wrap_get (&(d->auth_dg.num_gen_nonces)); + gen_num = mhd_atomic_counter_get_inc_wrap (&(d->auth_dg.num_gen_nonces)); expiration = mhd_monotonic_msec_counter () + d->auth_dg.cfg.nonce_tmout * (uint_fast64_t) 1000; @@ -361,7 +361,7 @@ gen_new_nonce (struct MHD_Daemon *restrict d, return false; /* One more hash, for the second part */ - gen_num = mhd_atomic_counter_inc_wrap_get (&(d->auth_dg.num_gen_nonces)); + gen_num = mhd_atomic_counter_get_inc_wrap (&(d->auth_dg.num_gen_nonces)); mhd_MD5_init_one_time (&(d_ctx.md5_ctx)); mhd_MD5_update (&(d_ctx.md5_ctx), diff --git a/src/mhd2/mhd_atomic_counter.c b/src/mhd2/mhd_atomic_counter.c @@ -1,6 +1,6 @@ /* This file is part of GNU libmicrohttpd - Copyright (C) 2024 Evgeny Grin (Karlson2k) + Copyright (C) 2024-2025 Evgeny Grin (Karlson2k) GNU libmicrohttpd is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public @@ -33,29 +33,26 @@ #include "mhd_assert.h" MHD_INTERNAL mhd_ATOMIC_COUNTER_TYPE -mhd_atomic_counter_inc_get (struct mhd_AtomicCounter *pcnt) +mhd_atomic_counter_get_inc_wrap (struct mhd_AtomicCounter *pcnt) { mhd_ATOMIC_COUNTER_TYPE ret; mhd_mutex_lock_chk (&(pcnt->lock)); - ret = ++(pcnt->count); + ret = pcnt->count++; mhd_mutex_unlock_chk (&(pcnt->lock)); - mhd_assert (0 != ret); /* check for overflow */ - return ret; } #ifndef NDEBUG + MHD_INTERNAL mhd_ATOMIC_COUNTER_TYPE -mhd_atomic_counter_inc_wrap_get (struct mhd_AtomicCounter *pcnt) +mhd_atomic_counter_get_inc (struct mhd_AtomicCounter *pcnt) { - mhd_ATOMIC_COUNTER_TYPE ret; + const mhd_ATOMIC_COUNTER_TYPE ret = mhd_atomic_counter_get_inc_wrap (pcnt); - mhd_mutex_lock_chk (&(pcnt->lock)); - ret = ++(pcnt->count); - mhd_mutex_unlock_chk (&(pcnt->lock)); + mhd_assert (mhd_ATOMIC_COUNTER_MAX != ret); /* check for overflow */ return ret; } @@ -65,12 +62,12 @@ mhd_atomic_counter_inc_wrap_get (struct mhd_AtomicCounter *pcnt) MHD_INTERNAL mhd_ATOMIC_COUNTER_TYPE -mhd_atomic_counter_dec_get (struct mhd_AtomicCounter *pcnt) +mhd_atomic_counter_get_dec (struct mhd_AtomicCounter *pcnt) { mhd_ATOMIC_COUNTER_TYPE ret; mhd_mutex_lock_chk (&(pcnt->lock)); - ret = --(pcnt->count); + ret = pcnt->count--; mhd_mutex_unlock_chk (&(pcnt->lock)); mhd_assert (mhd_ATOMIC_COUNTER_MAX != ret); /* check for underflow */ diff --git a/src/mhd2/mhd_atomic_counter.h b/src/mhd2/mhd_atomic_counter.h @@ -1,6 +1,6 @@ /* This file is part of GNU libmicrohttpd - Copyright (C) 2024 Evgeny Grin (Karlson2k) + Copyright (C) 2024-2025 Evgeny Grin (Karlson2k) GNU libmicrohttpd is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public @@ -30,6 +30,8 @@ #include "mhd_sys_options.h" +#include "mhd_assert.h" + #include "sys_sizet_type.h" /* Use 'size_t' to make sure it would never overflow when used for @@ -140,47 +142,104 @@ struct mhd_AtomicCounter # define mhd_atomic_counter_deinit(pcnt) ((void) 0) /** - * Atomically increment the value of the counter + * Get the value of the counter and atomically increment the counter. + * The value may overflow and wrap back to zero. + * @param pcnt the pointer to the counter to increment + * @return the counter value before the increment + */ +# define mhd_atomic_counter_get_inc_wrap(pcnt) \ + atomic_fetch_add_explicit (&((pcnt)->count), \ + 1, memory_order_relaxed) + +# ifdef NDEBUG +/** + * Atomically increment the value of the counter. + * Counter overflow is detected in debug builds. * @param pcnt the pointer to the counter to increment */ -# define mhd_atomic_counter_inc(pcnt) \ - do { atomic_fetch_add_explicit (&((pcnt)->count), 1, \ +# define mhd_atomic_counter_inc(pcnt) \ + do { (void) \ + atomic_fetch_add_explicit (&((pcnt)->count), 1, \ memory_order_relaxed); } while (0) /** - * Atomically increment the value of the counter and return the result + * Get the value of the counter and atomically increment the counter. + * Counter overflow is detected in debug builds. * @param pcnt the pointer to the counter to increment - * @return the final/resulting counter value + * @return the counter value before the increment */ -# define mhd_atomic_counter_inc_get(pcnt) \ - (atomic_fetch_add_explicit (&((pcnt)->count), \ - 1, memory_order_relaxed) + 1) +# define mhd_atomic_counter_get_inc(pcnt) \ + mhd_atomic_counter_get_inc_wrap ((pcnt)) /** - * Atomically decrement the value of the counter and return the result + * Get the value of the counter and atomically decrement the counter. + * Counter underflow is detected in debug builds. * @param pcnt the pointer to the counter to decrement - * @return the final/resulting counter value + * @return the counter value before the decrement */ -# define mhd_atomic_counter_dec_get(pcnt) \ - (atomic_fetch_sub_explicit (&((pcnt)->count), \ - 1, memory_order_release) - 1) +# define mhd_atomic_counter_get_dec(pcnt) \ + atomic_fetch_sub_explicit (&((pcnt)->count), \ + 1, memory_order_release) +# else /* _DEBUG */ +/** + * Atomically increment the value of the counter. + * Counter overflow is detected in debug builds. + * @param pcnt the pointer to the counter to increment + */ +# define mhd_atomic_counter_inc(pcnt) \ + do { mhd_ATOMIC_COUNTER_TYPE old_val = \ + atomic_fetch_add_explicit (&((pcnt)->count), 1, \ + memory_order_relaxed); \ + mhd_assert (mhd_ATOMIC_COUNTER_MAX != old_val); } while (0) + +/** + * Get the value of the counter and atomically increment the counter. + * Counter overflow is detected in debug builds. + * @param pcnt the pointer to the counter to increment + * @return the counter value before the increment + */ +MHD_static_inline_ mhd_ATOMIC_COUNTER_TYPE +mhd_atomic_counter_get_inc (struct mhd_AtomicCounter *pcnt) +{ + mhd_ATOMIC_COUNTER_TYPE ret; + + ret = mhd_atomic_counter_get_inc_wrap (pcnt); + + mhd_assert (mhd_ATOMIC_COUNTER_MAX != ret); + + return ret; +} + /** - * Atomically get the value of the counter + * Get the value of the counter and atomically decrement the counter. + * Counter underflow is detected in debug builds. + * @param pcnt the pointer to the counter to decrement + * @return the counter value before the decrement + */ +MHD_static_inline_ mhd_ATOMIC_COUNTER_TYPE +mhd_atomic_counter_get_dec (struct mhd_AtomicCounter *pcnt) +{ + mhd_ATOMIC_COUNTER_TYPE ret; + + ret = atomic_fetch_sub_explicit (&((pcnt)->count),1, memory_order_relaxed); + + mhd_assert (0 != ret); + + return ret; +} + + +# endif /* _DEBUG */ + +/** + * Atomically get the value of the counter. * @param pcnt the pointer to the counter to get * @return the counter value */ # define mhd_atomic_counter_get(pcnt) \ (atomic_load_explicit (&((pcnt)->count), memory_order_relaxed)) -/** - * Atomically increment the value of the counter and return the result. - * The value is allowed to overflow and get back to zero. - * @param pcnt the pointer to the counter to increment - * @return the final/resulting counter value - */ -# define mhd_atomic_counter_inc_wrap_get(pcnt) \ - mhd_atomic_counter_inc_get (pcnt) #elif defined(mhd_ATOMIC_BY_LOCKS) /** @@ -202,9 +261,20 @@ struct mhd_AtomicCounter */ # define mhd_atomic_counter_deinit(pcnt) \ mhd_mutex_destroy_chk (&((pcnt)->lock)) +/** + * Get the value of the counter and atomically increment the counter. + * The value may overflow and wrap back to zero. + * @param pcnt the pointer to the counter to increment + * @return the counter value before the increment + */ +MHD_INTERNAL mhd_ATOMIC_COUNTER_TYPE +mhd_atomic_counter_get_inc_wrap (struct mhd_AtomicCounter *pcnt); + +#ifdef NDEBUG /** - * Atomically increment the value of the counter + * Atomically increment the value of the counter. + * Counter overflow is detected in debug builds. * @param pcnt the pointer to the counter to increment */ # define mhd_atomic_counter_inc(pcnt) do { \ @@ -213,43 +283,49 @@ struct mhd_AtomicCounter mhd_mutex_unlock_chk (&((pcnt)->lock)); } while (0) /** - * Atomically increment the value of the counter and return the result + * Get the value of the counter and atomically increment the counter. + * Counter overflow is detected in debug builds. * @param pcnt the pointer to the counter to increment - * @return the final/resulting counter value + * @return the counter value before the increment */ -MHD_INTERNAL mhd_ATOMIC_COUNTER_TYPE -mhd_atomic_counter_inc_get (struct mhd_AtomicCounter *pcnt); +#define mhd_atomic_counter_get_inc(pcnt) mhd_atomic_counter_get_inc_wrap (pcnt) + +#else -#ifdef NDEBUG /** - * Atomically increment the value of the counter and return the result. - * The value is allowed to overflow and get back to zero. + * Atomically increment the value of the counter. + * Counter overflow is detected in debug builds. * @param pcnt the pointer to the counter to increment - * @return the final/resulting counter value */ -#define mhd_atomic_counter_inc_wrap_get(pcnt) mhd_atomic_counter_inc_get (pcnt) -#else +# define mhd_atomic_counter_inc(pcnt) do { \ + mhd_ATOMIC_COUNTER_TYPE old_val; \ + mhd_mutex_lock_chk (&((pcnt)->lock)); \ + old_val = (pcnt)->count++; \ + mhd_mutex_unlock_chk (&((pcnt)->lock)); \ + mhd_assert (mhd_ATOMIC_COUNTER_MAX != old_val); } while (0) + /** - * Atomically increment the value of the counter and return the result. - * The value is allowed to overflow and get back to zero. + * Get the value of the counter and atomically increment the counter. + * Counter overflow is detected in debug builds. * @param pcnt the pointer to the counter to increment - * @return the final/resulting counter value + * @return the counter value before the increment */ MHD_INTERNAL mhd_ATOMIC_COUNTER_TYPE -mhd_atomic_counter_inc_wrap_get (struct mhd_AtomicCounter *pcnt); +mhd_atomic_counter_get_inc (struct mhd_AtomicCounter *pcnt); #endif /** - * Atomically decrement the value of the counter and return the result + * Get the value of the counter and atomically decrement the counter. + * Counter underflow is detected in debug builds. * @param pcnt the pointer to the counter to decrement - * @return the final/resulting counter value + * @return the counter value before the decrement */ MHD_INTERNAL mhd_ATOMIC_COUNTER_TYPE -mhd_atomic_counter_dec_get (struct mhd_AtomicCounter *pcnt); +mhd_atomic_counter_get_dec (struct mhd_AtomicCounter *pcnt); /** - * Atomically get the value of the counter + * Atomically get the value of the counter. * @param pcnt the pointer to the counter to get * @return the counter value */ @@ -277,40 +353,79 @@ mhd_atomic_counter_get (struct mhd_AtomicCounter *pcnt); # define mhd_atomic_counter_deinit(pcnt) ((void) 0) /** - * Atomically increment the value of the counter + * Get the value of the counter and atomically increment the counter. + * The value may overflow and wrap back to zero. * @param pcnt the pointer to the counter to increment + * @return the counter value before the increment */ -# define mhd_atomic_counter_inc(pcnt) do { ++((pcnt)->count); } while (0) +# define mhd_atomic_counter_get_inc_wrap(pcnt) ((pcnt)->count++) /** - * Atomically increment the value of the counter and return the result + * Atomically increment the value of the counter. + * Counter overflow is detected in debug builds. * @param pcnt the pointer to the counter to increment - * @return the final/resulting counter value */ -# define mhd_atomic_counter_inc_get(pcnt) (++((pcnt)->count)) +# define mhd_atomic_counter_inc(pcnt) \ + do { mhd_assert (mhd_ATOMIC_COUNTER_MAX != ((pcnt)->count)); \ + ++((pcnt)->count); } while (0) +# ifdef NDEBUG /** - * Atomically decrement the value of the counter and return the result - * @param pcnt the pointer to the counter to decrement - * @return the final/resulting counter value + * Get the value of the counter and atomically increment the counter. + * Counter overflow is detected in debug builds. + * @param pcnt the pointer to the counter to increment + * @return the counter value before the increment */ -# define mhd_atomic_counter_dec_get(pcnt) (--((pcnt)->count)) +# define mhd_atomic_counter_get_inc(pcnt) \ + mhd_atomic_counter_get_inc_wrap ((pcnt)) /** - * Atomically get the value of the counter - * @param pcnt the pointer to the counter to get - * @return the counter value + * Get the value of the counter and atomically decrement the counter. + * Counter underflow is detected in debug builds. + * @param pcnt the pointer to the counter to decrement + * @return the counter value before the decrement */ -# define mhd_atomic_counter_get(pcnt) ((pcnt)->count) +# define mhd_atomic_counter_get_dec(pcnt) ((pcnt)->count--) +# else /* _DEBUG */ /** - * Atomically increment the value of the counter and return the result. - * The value is allowed to overflow and get back to zero. + * Get the value of the counter and atomically increment the counter. + * Counter overflow is detected in debug builds. * @param pcnt the pointer to the counter to increment - * @return the final/resulting counter value + * @return the counter value before the increment */ -# define mhd_atomic_counter_inc_wrap_get(pcnt) \ - mhd_atomic_counter_inc_get (pcnt) +MHD_static_inline_ mhd_ATOMIC_COUNTER_TYPE +mhd_atomic_counter_get_inc (struct mhd_AtomicCounter *pcnt) +{ + mhd_assert (mhd_ATOMIC_COUNTER_MAX != (pcnt->count)); + + return mhd_atomic_counter_get_inc_wrap (pcnt); +} + + +/** + * Get the value of the counter and atomically decrement the counter. + * Counter underflow is detected in debug builds. + * @param pcnt the pointer to the counter to decrement + * @return the counter value before the decrement + */ +MHD_static_inline_ mhd_ATOMIC_COUNTER_TYPE +mhd_atomic_counter_get_dec (struct mhd_AtomicCounter *pcnt) +{ + mhd_assert (0 != ((pcnt)->count)); + + return ((pcnt)->count--); +} + + +# endif /* _DEBUG */ + +/** + * Atomically get the value of the counter. + * @param pcnt the pointer to the counter to get + * @return the counter value + */ +# define mhd_atomic_counter_get(pcnt) ((pcnt)->count) #endif /* mhd_ATOMIC_SINGLE_THREAD */ diff --git a/src/mhd2/response_destroy.c b/src/mhd2/response_destroy.c @@ -80,7 +80,7 @@ mhd_response_dec_use_count (struct MHD_Response *restrict r) if (r->reuse.reusable) { - if (0 != mhd_atomic_counter_dec_get (&(r->reuse.counter))) + if (1 != mhd_atomic_counter_get_dec (&(r->reuse.counter))) return; /* The response is still used somewhere */ } @@ -98,7 +98,7 @@ mhd_response_inc_use_count (struct MHD_Response *restrict r) if (! r->reuse.reusable) return; - (void) mhd_atomic_counter_inc_get (&(r->reuse.counter)); + mhd_atomic_counter_inc (&(r->reuse.counter)); } @@ -117,7 +117,7 @@ MHD_response_destroy (struct MHD_Response *response) #ifndef NDEBUG /* Decrement counter to avoid triggering assert in deinit function */ if (response->reuse.reusable) - mhd_assert (0 == mhd_atomic_counter_dec_get (&(response->reuse.counter))); + mhd_assert (1 == mhd_atomic_counter_get_dec (&(response->reuse.counter))); #endif response_full_deinit (response); return;