MINOR: pools: move pool_free_area() out of the lock in the locked version
Calling pool_free_area() inside a lock in pool_put_to_shared_cache() is
a very bad idea. Fortunately this only happens on the lowest end platforms
which almost never use threads or in very small counts.
This change consists in zeroing the pointer once already released to the
cache in the first test so that the second stage knows if it needs to
pass it to the OS or not. This has slightly reduced the length of the
diff --git a/include/haproxy/pool.h b/include/haproxy/pool.h
index a440625..8fce593 100644
--- a/include/haproxy/pool.h
+++ b/include/haproxy/pool.h
@@ -237,26 +237,31 @@
*/
static inline void pool_put_to_shared_cache(struct pool_head *pool, void *ptr)
{
-#ifndef DEBUG_UAF /* normal pool behaviour */
_HA_ATOMIC_DEC(&pool->used);
+
+#ifndef DEBUG_UAF /* normal pool behaviour */
+
HA_SPIN_LOCK(POOL_LOCK, &pool->lock);
- if (pool_is_crowded(pool)) {
- pool_free_area(ptr, pool->size + POOL_EXTRA);
- _HA_ATOMIC_DEC(&pool->allocated);
- } else {
+ if (!pool_is_crowded(pool)) {
*POOL_LINK(pool, ptr) = (void *)pool->free_list;
pool->free_list = (void *)ptr;
+ ptr = NULL;
}
- swrate_add(&pool->needed_avg, POOL_AVG_SAMPLES, pool->used);
HA_SPIN_UNLOCK(POOL_LOCK, &pool->lock);
-#else /* release the entry for real to detect use after free */
- /* ensure we crash on double free or free of a const area*/
+
+#else
+ /* release the entry for real to detect use after free */
+ /* ensure we crash on double free or free of a const area */
*(uint32_t *)ptr = 0xDEADADD4;
- pool_free_area(ptr, pool->size + POOL_EXTRA);
- _HA_ATOMIC_DEC(&pool->allocated);
- _HA_ATOMIC_DEC(&pool->used);
- swrate_add(&pool->needed_avg, POOL_AVG_SAMPLES, pool->used);
+
#endif /* DEBUG_UAF */
+
+ if (ptr) {
+ /* still not freed */
+ pool_free_area(ptr, pool->size + POOL_EXTRA);
+ _HA_ATOMIC_DEC(&pool->allocated);
+ }
+ swrate_add(&pool->needed_avg, POOL_AVG_SAMPLES, pool->used);
}
#endif /* CONFIG_HAP_LOCKLESS_POOLS */