mirror of
https://github.com/asterisk/asterisk.git
synced 2025-09-05 12:16:00 +00:00
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/branches/1.4@105409 65c4cc65-6c06-0410-ace0-fbb531ad65f3
This commit is contained in:
@@ -67,6 +67,8 @@ static AST_LIST_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;
|
||||
@@ -91,6 +93,11 @@ static void *autoservice_run(void *ign)
|
||||
int x = 0, ms = 500;
|
||||
|
||||
AST_LIST_LOCK(&aslist);
|
||||
|
||||
/* At this point, we know that no channels that have been removed are going
|
||||
* to get used again. */
|
||||
as_chan_list_state++;
|
||||
|
||||
AST_LIST_TRAVERSE(&aslist, as, list) {
|
||||
if (!as->chan->_softhangup) {
|
||||
if (x < MAX_AUTOMONS)
|
||||
@@ -215,10 +222,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_LIST_LOCK(&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_LIST_TRAVERSE_SAFE_BEGIN(&aslist, as, list) {
|
||||
if (as->chan == chan) {
|
||||
as->use_count--;
|
||||
@@ -256,5 +271,8 @@ int ast_autoservice_stop(struct ast_channel *chan)
|
||||
ast_frfree(f);
|
||||
}
|
||||
|
||||
while (chan_list_state == as_chan_list_state)
|
||||
usleep(1000);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
Reference in New Issue
Block a user