Merged revisions 67716 via svnmerge from
authorRussell Bryant <russell@russellbryant.com>
Wed, 6 Jun 2007 16:58:28 +0000 (16:58 +0000)
committerRussell Bryant <russell@russellbryant.com>
Wed, 6 Jun 2007 16:58:28 +0000 (16:58 +0000)
https://origsvn.digium.com/svn/asterisk/branches/1.4

................
r67716 | russell | 2007-06-06 11:55:59 -0500 (Wed, 06 Jun 2007) | 13 lines

Merged revisions 67715 via svnmerge from
https://origsvn.digium.com/svn/asterisk/branches/1.2

........
r67715 | russell | 2007-06-06 11:40:51 -0500 (Wed, 06 Jun 2007) | 5 lines

We have some bug reports showing crashes due to a double free of a channel.
Add a sanity check to ast_channel_free() to make sure we don't go on trying
to free a channel that wasn't found in the channel list.
(issue #8850, and others...)

........

................

git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@67717 65c4cc65-6c06-0410-ace0-fbb531ad65f3

include/asterisk/linkedlists.h
main/channel.c

index 2c9a570..1bf933a 100644 (file)
@@ -729,8 +729,10 @@ struct {                                                           \
   used to link entries of this list together.
   \warning The removed entry is \b not freed nor modified in any way.
  */
-#define AST_LIST_REMOVE(head, elm, field) do {                         \
+#define AST_LIST_REMOVE(head, elm, field) ({                           \
+       __typeof(elm) __res = NULL; \
        if ((head)->first == (elm)) {                                   \
+               __res = (head)->first;                      \
                (head)->first = (elm)->field.next;                      \
                if ((head)->last == (elm))                      \
                        (head)->last = NULL;                    \
@@ -739,13 +741,15 @@ struct {                                                          \
                while (curelm && (curelm->field.next != (elm)))                 \
                        curelm = curelm->field.next;                    \
                if (curelm) { \
+                       __res = curelm; \
                        curelm->field.next = (elm)->field.next;                 \
                        if ((head)->last == (elm))                              \
                                (head)->last = curelm;                          \
                } \
        }                                                               \
-        (elm)->field.next = NULL;                                       \
-} while (0)
+       (elm)->field.next = NULL;                                       \
+       (__res); \
+})
 
 #define AST_RWLIST_REMOVE AST_LIST_REMOVE
 
index d75e983..c0aa232 100644 (file)
@@ -1082,7 +1082,10 @@ void ast_channel_free(struct ast_channel *chan)
        headp=&chan->varshead;
        
        AST_LIST_LOCK(&channels);
-       AST_LIST_REMOVE(&channels, chan, chan_list);
+       if (!AST_LIST_REMOVE(&channels, chan, chan_list)) {
+               AST_LIST_UNLOCK(&channels);
+               ast_log(LOG_ERROR, "Unable to find channel in list to free. Assuming it has already been done.\n");
+       }
        /* Lock and unlock the channel just to be sure nobody
           has it locked still */
        ast_channel_lock(chan);