Skip to content

Commit 84f664b

Browse files
authored
DISPATCH-2039 Add option -DQD_DISABLE_MEMORY_POOL for CMake build (#110)
1 parent 33b2ca7 commit 84f664b

File tree

5 files changed

+37
-9
lines changed

5 files changed

+37
-9
lines changed

README.adoc

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -306,12 +306,18 @@ Existing build directory can be opened with `cmake-gui -S .. -B .`
306306
Other options include `Debug` (disables optimizations) and `Coverage`.
307307

308308
|`-DQD_ENABLE_ASSERTIONS=`
309-
|Seting this to `ON` enables asserts irrespective of `CMAKE_BUILD_TYPE`.
309+
|Setting this to `ON` enables asserts irrespective of `CMAKE_BUILD_TYPE`.
310310

311311
|`-DRUNTIME_CHECK=`
312-
|Enables C/C++ runtime checkers.See "Run Time Validation" chapter above.
312+
|Enables C/C++ runtime checkers. See "Run Time Validation" chapter above.
313313

314314
|`-DCMAKE_INTERPROCEDURAL_OPTIMIZATION=ON`
315315
|With CMake 3.9+, compiles the project with LTO (Link Time Optimization) enabled.
316316
Older CMake will only honor this option with the Intel compiler on Linux.
317+
318+
|`-DQD_DISABLE_MEMORY_POOL=ON`
319+
|Dispatch will immediately free memory, instead of returning it to memory pool.
320+
This option will *break* safe pointers, resulting in crashes, therefore is suitable only for debugging.
321+
When combined with `-DRUNTIME_CHECK=asan`, the pointer breakages are much less frequent.
322+
317323
|===

cmake/RuntimeChecks.cmake

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,16 @@
3131
# This file updates the QDROUTERD_RUNNER and CMAKE_C_FLAGS
3232
# appropriately for use when running the ctest suite.
3333

34+
# Disabling memory pool turns use-after-poison asan warnings into use-after-free warnings. The latter come with
35+
# a freeing stacktrace that makes them easier to triage.
36+
#
37+
# Safe pointers require memory pool to work (memory may never be relinquished to the OS, otherwise safe pointers may
38+
# break). Therefore, only disable memory pool for special debugging purposes. Sanitizers minimize memory reuse and
39+
# make it significantly less likely that a safe pointer breaks.
40+
set(QD_DISABLE_MEMORY_POOL OFF CACHE STRING "Disables memory pool. Should be only used with asan or msan RUNTIME_CHECK")
41+
if (QD_DISABLE_MEMORY_POOL)
42+
add_definitions(-DQD_DISABLE_MEMORY_POOL)
43+
endif()
3444

3545
# Valgrind configuration
3646
#
@@ -85,6 +95,9 @@ set(RUNTIME_CHECK ${RUNTIME_CHECK_DEFAULT} CACHE STRING "Enable runtime checks.
8595
if(CMAKE_BUILD_TYPE MATCHES "Coverage" AND RUNTIME_CHECK)
8696
message(FATAL_ERROR "Cannot set RUNTIME_CHECK with CMAKE_BUILD_TYPE=Coverage")
8797
endif()
98+
if(QD_DISABLE_MEMORY_POOL AND NOT RUNTIME_CHECK)
99+
message(FATAL_ERROR "Do not set QD_DISABLE_MEMORY_POOL without enabling RUNTIME_CHECK at the same time")
100+
endif()
88101

89102
if(RUNTIME_CHECK STREQUAL "memcheck")
90103
assert_has_valgrind()

include/qpid/dispatch/alloc_pool.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ DEQ_DECLARE(qd_alloc_pool_t, qd_alloc_pool_list_t);
4343
typedef struct {
4444
int transfer_batch_size;
4545
int local_free_list_max;
46-
int global_free_list_max;
46+
int global_free_list_max; ///< -1 means unlimited
4747
} qd_alloc_config_t;
4848

4949
/** Allocation statistics. */

src/alloc_pool.c

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -260,8 +260,9 @@ struct qd_alloc_pool_t {
260260
qd_alloc_linked_stack_t free_list;
261261
};
262262

263-
qd_alloc_config_t qd_alloc_default_config_big = {16, 32, 0};
264-
qd_alloc_config_t qd_alloc_default_config_small = {64, 128, 0};
263+
qd_alloc_config_t qd_alloc_default_config_big = {16, 32, -1};
264+
qd_alloc_config_t qd_alloc_default_config_small = {64, 128, -1};
265+
qd_alloc_config_t qd_alloc_default_config_asan = { 1, 0, 0};
265266
#define BIG_THRESHOLD 2000
266267

267268
static sys_mutex_t *init_lock = 0;
@@ -281,7 +282,11 @@ static void qd_alloc_init(qd_alloc_type_desc_t *desc)
281282
desc->config = desc->total_size > BIG_THRESHOLD ?
282283
&qd_alloc_default_config_big : &qd_alloc_default_config_small;
283284

285+
#if defined(QD_DISABLE_MEMORY_POOL)
286+
desc->config = &qd_alloc_default_config_asan;
287+
#else
284288
assert (desc->config->local_free_list_max >= desc->config->transfer_batch_size);
289+
#endif
285290

286291
desc->global_pool = NEW(qd_alloc_pool_t);
287292
DEQ_ITEM_INIT(desc->global_pool);
@@ -489,7 +494,7 @@ void qd_dealloc(qd_alloc_type_desc_t *desc, qd_alloc_pool_t **tpool, char *p)
489494
// If there's a global_free_list size limit, remove items until the limit is
490495
// not exceeded.
491496
//
492-
if (desc->config->global_free_list_max != 0) {
497+
if (desc->config->global_free_list_max != -1) {
493498
while (DEQ_SIZE(desc->global_pool->free_list) > desc->config->global_free_list_max) {
494499
item = pop_stack(&desc->global_pool->free_list);
495500
FREE_CACHE_ALIGNED(item);
@@ -500,7 +505,11 @@ void qd_dealloc(qd_alloc_type_desc_t *desc, qd_alloc_pool_t **tpool, char *p)
500505
sys_mutex_unlock(desc->lock);
501506
}
502507

503-
508+
#if defined(QD_DISABLE_MEMORY_POOL)
509+
// disabling alloc pool causes use-after-free; no way to check if memory
510+
// has been freed to the OS before accessing it from `qd_alloc_deref_safe_ptr`
511+
ATTRIBUTE_NO_SANITIZE_ADDRESS
512+
#endif
504513
uint32_t qd_alloc_sequence(void *p)
505514
{
506515
if (!p)

src/qd_asan_interface.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -81,8 +81,8 @@ void __asan_unpoison_memory_region(void const volatile *addr, size_t size);
8181
#endif // QD_HAS_ADDRESS_SANITIZER
8282

8383
// https://github.com/google/sanitizers/wiki/AddressSanitizer#turning-off-instrumentation
84-
85-
#if QD_HAS_ADDRESS_SANITIZER
84+
#if QD_HAS_ADDRESS_SANITIZER || QD_HAS_THREAD_SANITIZER
85+
// note: tsan can also detect some invalid memory accesses and that will crash the binary
8686
# define ATTRIBUTE_NO_SANITIZE_ADDRESS __attribute__((no_sanitize_address)) __attribute__((no_sanitize("address")))
8787
#else
8888
# define ATTRIBUTE_NO_SANITIZE_ADDRESS

0 commit comments

Comments
 (0)