mirror of
https://github.com/asterisk/asterisk.git
synced 2025-09-21 04:46:29 +00:00
astobj2: assert on invalid ref and backtrace cleanup
If a reference count goes negative, instead of just logging that fact, be more helpful with a backtrace and an assert that will DO_CRASH. This patch also removes the duplicate ao2_bt() function and cleans up extraneous usage of the ast_log_backtrace() call. Review: https://reviewboard.asterisk.org/r/3765/ git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@418963 65c4cc65-6c06-0410-ace0-fbb531ad65f3
This commit is contained in:
@@ -1961,9 +1961,6 @@ void *__ao2_iterator_next(struct ao2_iterator *iter) attribute_warn_unused_resul
|
|||||||
*/
|
*/
|
||||||
void ao2_iterator_restart(struct ao2_iterator *iter);
|
void ao2_iterator_restart(struct ao2_iterator *iter);
|
||||||
|
|
||||||
/* extra functions */
|
|
||||||
void ao2_bt(void); /* backtrace */
|
|
||||||
|
|
||||||
/*! gcc __attribute__(cleanup()) functions
|
/*! gcc __attribute__(cleanup()) functions
|
||||||
* \note they must be able to handle NULL parameters because most of the
|
* \note they must be able to handle NULL parameters because most of the
|
||||||
* allocation/find functions can fail and we don't want to try to tear
|
* allocation/find functions can fail and we don't want to try to tear
|
||||||
|
@@ -97,29 +97,6 @@ struct astobj2_rwlock {
|
|||||||
struct ao2_stats ao2;
|
struct ao2_stats ao2;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef HAVE_BKTR
|
|
||||||
#include <execinfo.h> /* for backtrace */
|
|
||||||
#endif
|
|
||||||
|
|
||||||
void ao2_bt(void)
|
|
||||||
{
|
|
||||||
#ifdef HAVE_BKTR
|
|
||||||
int depth;
|
|
||||||
int idx;
|
|
||||||
#define N1 20
|
|
||||||
void *addresses[N1];
|
|
||||||
char **strings;
|
|
||||||
|
|
||||||
depth = backtrace(addresses, N1);
|
|
||||||
strings = ast_bt_get_symbols(addresses, depth);
|
|
||||||
ast_verbose("backtrace returned: %d\n", depth);
|
|
||||||
for (idx = 0; idx < depth; ++idx) {
|
|
||||||
ast_verbose("%d: %p %s\n", idx, addresses[idx], strings[idx]);
|
|
||||||
}
|
|
||||||
ast_std_free(strings);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
#define INTERNAL_OBJ_MUTEX(user_data) \
|
#define INTERNAL_OBJ_MUTEX(user_data) \
|
||||||
((struct astobj2_lock *) (((char *) (user_data)) - sizeof(struct astobj2_lock)))
|
((struct astobj2_lock *) (((char *) (user_data)) - sizeof(struct astobj2_lock)))
|
||||||
|
|
||||||
@@ -455,6 +432,9 @@ static int internal_ao2_ref(void *user_data, int delta, const char *file, int li
|
|||||||
if (current_value < 0) {
|
if (current_value < 0) {
|
||||||
ast_log(__LOG_ERROR, file, line, func,
|
ast_log(__LOG_ERROR, file, line, func,
|
||||||
"Invalid refcount %d on ao2 object %p\n", current_value, user_data);
|
"Invalid refcount %d on ao2 object %p\n", current_value, user_data);
|
||||||
|
ast_assert(0);
|
||||||
|
/* stop here even if assert doesn't DO_CRASH */
|
||||||
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* last reference, destroy the object */
|
/* last reference, destroy the object */
|
||||||
@@ -516,7 +496,6 @@ int __ao2_ref_debug(void *user_data, int delta, const char *tag, const char *fil
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (obj == NULL) {
|
if (obj == NULL) {
|
||||||
ast_log_backtrace();
|
|
||||||
ast_assert(0);
|
ast_assert(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -1759,14 +1759,14 @@ void ast_log_backtrace(void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if ((strings = ast_bt_get_symbols(bt->addresses, bt->num_frames))) {
|
if ((strings = ast_bt_get_symbols(bt->addresses, bt->num_frames))) {
|
||||||
ast_debug(1, "Got %d backtrace record%c\n", bt->num_frames, bt->num_frames != 1 ? 's' : ' ');
|
ast_verbose("Got %d backtrace record%c\n", bt->num_frames, bt->num_frames != 1 ? 's' : ' ');
|
||||||
for (i = 3; i < bt->num_frames - 2; i++) {
|
for (i = 3; i < bt->num_frames - 2; i++) {
|
||||||
ast_debug(1, "#%d: [%p] %s\n", i - 3, bt->addresses[i], strings[i]);
|
ast_verbose("#%d: [%p] %s\n", i - 3, bt->addresses[i], strings[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
ast_std_free(strings);
|
ast_std_free(strings);
|
||||||
} else {
|
} else {
|
||||||
ast_debug(1, "Could not allocate memory for backtrace\n");
|
ast_verbose("Could not allocate memory for backtrace\n");
|
||||||
}
|
}
|
||||||
ast_bt_destroy(bt);
|
ast_bt_destroy(bt);
|
||||||
#else
|
#else
|
||||||
|
@@ -2544,7 +2544,7 @@ void __ast_assert_failed(int condition, const char *condition_str, const char *f
|
|||||||
condition_str, condition, line, function, file);
|
condition_str, condition, line, function, file);
|
||||||
|
|
||||||
/* Generate a backtrace for the assert */
|
/* Generate a backtrace for the assert */
|
||||||
ao2_bt();
|
ast_log_backtrace();
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Give the logger a chance to get the message out, just in case
|
* Give the logger a chance to get the message out, just in case
|
||||||
|
@@ -992,8 +992,6 @@ int ast_sip_subscription_notify(struct ast_sip_subscription *sub, void *notify_d
|
|||||||
PJSIP_EVSUB_STATE_ACTIVE : PJSIP_EVSUB_STATE_TERMINATED;
|
PJSIP_EVSUB_STATE_ACTIVE : PJSIP_EVSUB_STATE_TERMINATED;
|
||||||
}
|
}
|
||||||
|
|
||||||
ast_log_backtrace();
|
|
||||||
|
|
||||||
if (pjsip_evsub_notify(evsub, state, NULL, NULL, &tdata) != PJ_SUCCESS) {
|
if (pjsip_evsub_notify(evsub, state, NULL, NULL, &tdata) != PJ_SUCCESS) {
|
||||||
ast_free(body_text);
|
ast_free(body_text);
|
||||||
return -1;
|
return -1;
|
||||||
|
Reference in New Issue
Block a user