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:
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;