From 2bae154a80e64dbfc4c7701049f223d869cab695 Mon Sep 17 00:00:00 2001 From: Mathieu Desnoyers Date: Thu, 13 Nov 2014 15:46:04 -0500 Subject: [PATCH] Detect unbalanced lock/unlock Signed-off-by: Mathieu Desnoyers --- urcu-checker.c | 27 ++++++++++++++++++++++----- urcu/static/urcu-bp.h | 6 ++++-- urcu/static/urcu-qsbr.h | 6 ++++-- urcu/static/urcu.h | 6 ++++-- 4 files changed, 34 insertions(+), 11 deletions(-) diff --git a/urcu-checker.c b/urcu-checker.c index cd4721d..97220ab 100644 --- a/urcu-checker.c +++ b/urcu-checker.c @@ -67,7 +67,7 @@ static inline pid_t gettid(void) (long) getpid(), (long) gettid(), ## args) struct urcu_debug_entry { - void *ip; + char *func; int depth; }; @@ -145,16 +145,32 @@ void print_bt(struct backtrace *bt) void rcu_read_lock_debug(void) { struct urcu_debug_stack *r = &URCU_TLS(rcu_debug_stack); + char *func = get_symbol(__builtin_return_address(0)); - r->stack[r->stackend++].ip = __builtin_return_address(0); + r->stack[r->stackend++].func = func; } void rcu_read_unlock_debug(void) { struct urcu_debug_stack *r = &URCU_TLS(rcu_debug_stack); + char *func = get_symbol(__builtin_return_address(0)); assert(r->stackend != 0); - r->stack[--r->stackend].ip = NULL; + if (r->stack[r->stackend - 1].func && func && + strcmp(r->stack[r->stackend - 1].func, + func) != 0) { + struct backtrace bt; + + err_printf("URCU lock/unlock caller mismatch: lock by <%s> unlock by <%s>\n", + r->stack[r->stackend - 1].func, func); + save_backtrace(&bt); + print_bt(&bt); + free_backtrace(&bt); + } + r->stackend--; + free(r->stack[r->stackend].func); + r->stack[r->stackend].func = NULL; + free(func); } void rcu_read_ongoing_check_debug(const char *func) @@ -163,12 +179,13 @@ void rcu_read_ongoing_check_debug(const char *func) if (r->stackend == 0) { struct backtrace bt; + char *func = get_symbol(__builtin_return_address(0)); err_printf("rcu_dereference() used outside of critical section at %p <%s>\n", - __builtin_return_address(0), - get_symbol(__builtin_return_address(0))); + __builtin_return_address(0), func); save_backtrace(&bt); print_bt(&bt); free_backtrace(&bt); + free(func); } } diff --git a/urcu/static/urcu-bp.h b/urcu/static/urcu-bp.h index 0bdefff..0ae18d6 100644 --- a/urcu/static/urcu-bp.h +++ b/urcu/static/urcu-bp.h @@ -152,7 +152,8 @@ static inline void _rcu_read_lock_update(unsigned long tmp) * intent is that this function meets the 10-line criterion in LGPL, * allowing this function to be invoked directly from non-LGPL code. */ -static inline void _rcu_read_lock(void) +static inline __attribute__((always_inline)) +void _rcu_read_lock(void) { unsigned long tmp; @@ -169,7 +170,8 @@ static inline void _rcu_read_lock(void) * 10 lines of code, and is intended to be usable by non-LGPL code, as * called out in LGPL. */ -static inline void _rcu_read_unlock(void) +static inline __attribute__((always_inline)) +void _rcu_read_unlock(void) { /* * Finish using rcu before decrementing the pointer. diff --git a/urcu/static/urcu-qsbr.h b/urcu/static/urcu-qsbr.h index 1ef830a..4092d6b 100644 --- a/urcu/static/urcu-qsbr.h +++ b/urcu/static/urcu-qsbr.h @@ -131,7 +131,8 @@ static inline enum rcu_state rcu_reader_state(unsigned long *ctr) * function meets the 10-line criterion for LGPL, allowing this function * to be invoked directly from non-LGPL code. */ -static inline void _rcu_read_lock(void) +static inline __attribute__((always_inline)) +void _rcu_read_lock(void) { rcu_read_lock_debug(); rcu_assert(URCU_TLS(rcu_reader).ctr); @@ -144,7 +145,8 @@ static inline void _rcu_read_lock(void) * function meets the 10-line criterion for LGPL, allowing this function * to be invoked directly from non-LGPL code. */ -static inline void _rcu_read_unlock(void) +static inline __attribute__((always_inline)) +void _rcu_read_unlock(void) { rcu_read_unlock_debug(); } diff --git a/urcu/static/urcu.h b/urcu/static/urcu.h index 0fe32e8..9659a2f 100644 --- a/urcu/static/urcu.h +++ b/urcu/static/urcu.h @@ -216,7 +216,8 @@ static inline void _rcu_read_lock_update(unsigned long tmp) * intent is that this function meets the 10-line criterion in LGPL, * allowing this function to be invoked directly from non-LGPL code. */ -static inline void _rcu_read_lock(void) +static inline __attribute__((always_inline)) +void _rcu_read_lock(void) { unsigned long tmp; @@ -250,7 +251,8 @@ static inline void _rcu_read_unlock_update_and_wakeup(unsigned long tmp) * helper are smaller than 10 lines of code, and are intended to be * usable by non-LGPL code, as called out in LGPL. */ -static inline void _rcu_read_unlock(void) +static inline __attribute__((always_inline)) +void _rcu_read_unlock(void) { unsigned long tmp; -- 2.34.1