Skip to content
Snippets Groups Projects
Commit 79678067 authored by Russell Bryant's avatar Russell Bryant
Browse files

Merged revisions 105409 via svnmerge from

https://origsvn.digium.com/svn/asterisk/branches/1.4

........
r105409 | russell | 2008-02-29 17:34:32 -0600 (Fri, 29 Feb 2008) | 23 lines

Fix a major bug in autoservice.  There was a race condition in the handling of
the list of channels in autoservice.  The problem was that it was possible for
a channel to get removed from autoservice and destroyed, while the autoservice
thread was still messing with the channel.  This led to memory corruption, and
caused crashes.  This explains multiple backtraces I have seen that have
references to autoservice, but do to the nature of the issue (memory corruption),
could cause crashes in a number of areas.

(fixes the crash in BE-386)
(closes issue #11694)
(closes issue #11940)

The following issues could be related.  If you are the reporter of one of these,
please update to include this fix and try again.

(potentially fixes issue #11189)
(potentially fixes issue #12107)
(potentially fixes issue #11573)
(potentially fixes issue #12008)
(potentially fixes issue #11189)
(potentially fixes issue #11993)
(potentially fixes issue #11791)

........


git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@105410 65c4cc65-6c06-0410-ace0-fbb531ad65f3
parent 7422f0ee
No related branches found
No related tags found
No related merge requests found
......@@ -60,6 +60,8 @@ static AST_RWLIST_HEAD_STATIC(aslist, asent);
static pthread_t asthread = AST_PTHREADT_NULL;
static int as_chan_list_state;
static void defer_frame(struct ast_channel *chan, struct ast_frame *f)
{
struct ast_frame *dup_f;
......@@ -83,6 +85,11 @@ static void *autoservice_run(void *ign)
int x = 0, ms = 500;
AST_RWLIST_RDLOCK(&aslist);
/* At this point, we know that no channels that have been removed are going
* to get used again. */
as_chan_list_state++;
AST_RWLIST_TRAVERSE(&aslist, as, list) {
if (!ast_check_hangup(as->chan)) {
if (x < MAX_AUTOMONS)
......@@ -207,10 +214,18 @@ int ast_autoservice_stop(struct ast_channel *chan)
struct ast_frame *f;
int removed = 0;
int orig_end_dtmf_flag = 0;
int chan_list_state;
AST_LIST_HEAD_INIT_NOLOCK(&dtmf_frames);
AST_RWLIST_WRLOCK(&aslist);
/* Save the autoservice channel list state. We _must_ verify that the channel
* list has been rebuilt before we return. Because, after we return, the channel
* could get destroyed and we don't want our poor autoservice thread to step on
* it after its gone! */
chan_list_state = as_chan_list_state;
AST_RWLIST_TRAVERSE_SAFE_BEGIN(&aslist, as, list) {
if (as->chan == chan) {
AST_RWLIST_REMOVE_CURRENT(list);
......@@ -248,5 +263,8 @@ int ast_autoservice_stop(struct ast_channel *chan)
ast_frfree(f);
}
while (chan_list_state == as_chan_list_state)
usleep(1000);
return res;
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment