]> git.ipfire.org Git - thirdparty/asterisk.git/commitdiff
astobj2: Prevent potential deadlocks with ao2_global_obj_release
authorSean Bright <sean.bright@gmail.com>
Wed, 29 Mar 2017 15:11:51 +0000 (11:11 -0400)
committerSean Bright <sean.bright@gmail.com>
Thu, 30 Mar 2017 17:57:16 +0000 (13:57 -0400)
The ao2_global_obj_release() function holds an exclusive lock on the
global object while it is being dereferenced. Any destructors that
run during this time that call ao2_global_obj_ref() will deadlock
because a read lock is required.

Instead, we make the global object inaccessible inside of the write
lock and only dereference it once we have released the lock. This
allows the affected destructors to fail gracefully.

While this doesn't completely solve the referenced issue (the error
message about not being able to create an IQ continues to be shown)
it does solve the backtrace spew that accompanied it.

ASTERISK-21009 #close
Reported by: Marcello Ceschia

Change-Id: Idf40ae136b5070dba22cb576ea8414fbc9939385

include/asterisk/astobj2.h
main/astobj2.c

index 28ae73e87edf4eed9531f50856a431cc17b093df..33e022421b5527c68dcf4b7bc45a8706217c59e7 100644 (file)
@@ -854,9 +854,9 @@ struct ao2_global_obj {
  * \return Nothing
  */
 #define ao2_t_global_obj_release(holder, tag)  \
-       __ao2_global_obj_release(&holder, (tag), __FILE__, __LINE__, __PRETTY_FUNCTION__, #holder)
+       __ao2_global_obj_replace_unref(&holder, NULL, (tag), __FILE__, __LINE__, __PRETTY_FUNCTION__, #holder)
 #define ao2_global_obj_release(holder) \
-       __ao2_global_obj_release(&holder, "", __FILE__, __LINE__, __PRETTY_FUNCTION__, #holder)
+       __ao2_global_obj_replace_unref(&holder, NULL, "", __FILE__, __LINE__, __PRETTY_FUNCTION__, #holder)
 
 void __ao2_global_obj_release(struct ao2_global_obj *holder, const char *tag, const char *file, int line, const char *func, const char *name);
 
index 71a81eacfaa87144d3a1400247ad43ff579c045f..1702f514c8a8983d89d4583571dde978d2f3ade3 100644 (file)
@@ -750,25 +750,7 @@ unsigned int ao2_options_get(void *obj)
 
 void __ao2_global_obj_release(struct ao2_global_obj *holder, const char *tag, const char *file, int line, const char *func, const char *name)
 {
-       if (!holder) {
-               /* For sanity */
-               ast_log(LOG_ERROR, "Must be called with a global object!\n");
-               ast_assert(0);
-               return;
-       }
-       if (__ast_rwlock_wrlock(file, line, func, &holder->lock, name)) {
-               /* Could not get the write lock. */
-               ast_assert(0);
-               return;
-       }
-
-       /* Release the held ao2 object. */
-       if (holder->obj) {
-               __ao2_ref(holder->obj, -1, tag, file, line, func);
-               holder->obj = NULL;
-       }
-
-       __ast_rwlock_unlock(file, line, func, &holder->lock, name);
+       __ao2_global_obj_replace_unref(holder, NULL, tag, file, line, func, name);
 }
 
 void *__ao2_global_obj_replace(struct ao2_global_obj *holder, void *obj, const char *tag, const char *file, int line, const char *func, const char *name)