Mittwoch, 5. Oktober 2011

bug in asterisk >= 1.8

Compared with asterisk release 1.6 1.8 release is not stable.

The same test suite:

exten => _X.,1,NoOp exten => _X.,n,Answer exten => _X.,n,Echo

Using 30 channels and middle call duration of 5 sec results runs without problems with asterisk 1.6. But results in asterisk crash if using asterisk 1.8. Crash is caused by destruction of libc memory pool of by destruction of internal asterisk structures: CDR variables.

The solution for this problem is located inside of asterisk core: Multiple channel drivers are using "ast_set_callerid" from the context of internal thread. This is OK: "ast_set_callerid" calls ast_channel_lock and all changes on the channel variables are protected. After cid update is completed "ast_set_callerid" calls:

if (chan->cdr) { ast_cdr_setcid(chan->cdr, chan); }

At same time "__ast_pbx_run" ("main/pbx.c") calls:

if (c->cdr)
ast_cdr_update(c);

This call happens in the context of pbx own thread and the access to CDR is performed without any protection.

In the most of cases problem is caused by "freeing of already freed memory" and receives real problem if "freeing of freed and allocated by other memory".

The immediate solution is to change __ast_pbx_run in main/pbx.c and protect access to CDR:

ast_channel_lock(c); /* Add this line */
if (c->cdr)
ast_cdr_update(c);
ast_channel_unlock(c); /* Add this line */

This is multiple locations (inside of "__ast_pbx_run") where "ast_cdr_update" is called. You need to protect all accesses.

The newest available version of chan_capi (chan-capi-trunk 943) includes one work around for this problem: the code of "ast_set_callerid" is partially replicated and CDR is not updated if caller id changes (for example name is received from network).

But this is still problem if you use other channel driver (for example chan_sip). In this case you should modify "__ast_pbx_run" in "main/pbx.c", build and install asterisk.

Keine Kommentare:

Kommentar veröffentlichen