[asterisk-bugs] [Asterisk 0006176]: [patch] Segfault in pbx_builtin_setvar_helper. Looks like the channel is being closed down underneath us

Asterisk Bug Tracker noreply at bugs.digium.com
Sun Aug 23 09:39:11 CDT 2009


The following issue has been set as RELATED TO issue 0015623. 
====================================================================== 
https://issues.asterisk.org/view.php?id=6176 
====================================================================== 
Reported By:                stevedavies
Assigned To:                tilghman
====================================================================== 
Project:                    Asterisk
Issue ID:                   6176
Category:                   Applications/app_macro
Reproducibility:            random
Severity:                   crash
Priority:                   normal
Status:                     closed
Asterisk Version:           SVN 
Regression:                 No 
SVN Branch (only for SVN checkouts, not tarball releases): trunk 
SVN Revision (number only!): 9156 
Request Review:              
Resolution:                 fixed
Fixed in Version:           
====================================================================== 
Date Submitted:             2006-01-09 04:09 CST
Last Modified:              2009-08-23 09:39 CDT
====================================================================== 
Summary:                    [patch] Segfault in pbx_builtin_setvar_helper. 
Looks like the channel is being closed down underneath us
Description: 
Site had a segfault.  gdb backtraces attached.

I had a look at what happened...

Segfault was in pbx_builtin_setvar_helper, whilst executing in the
AST_LIST_REMOVE macro.

pbx_builtin_setvar_helper was called by macro_exec, which was trying to
set MACRO_DEPTH on the channel.

Guilty code at pbx.c around line 5751 (SVN trunk, r7839):

        AST_LIST_TRAVERSE (headp, newvariable, entries) {
                if (strcasecmp(ast_var_name(newvariable), nametail) == 0)
{
                        /* there is already such a variable, delete it */
                        AST_LIST_REMOVE(headp, newvariable, entries);
                        ast_var_delete(newvariable);
                        break;
                }
        } 

headp here points at varshead in the channel structure.

Apparently at the time the list was traversed, there must have been
variables on the channel - given that an existing MACRO_DEPTH was found to
delete.

However, by the time we got into the AST_LIST_REMOVE code, curelm was null
(which comes from (head)->first, i.e. varshead.first).

(gdb) frame 0
https://issues.asterisk.org/view.php?id=0  0x080900a2 in
pbx_builtin_setvar_helper (chan=0x88d8a30, name=0x72734e
"MACRO_DEPTH", value=0xb79ee2b0 "1") at pbx.c:5941
5941                            AST_LIST_REMOVE(headp, newvariable,
entries);
(gdb) p curelm
$2 = (struct ast_var_t *) 0x0

Here's AST_LIST_REMOVE:

#define AST_LIST_REMOVE(head, elm, field) do {                          \
        if ((head)->first == (elm)) {                                   \
                (head)->first = (elm)->field.next;                      \
        }                                                               \
        else {                                                          \
                typeof(elm) curelm = (head)->first;                     \
                while (curelm->field.next != (elm))                     \
                        curelm = curelm->field.next;                    \
                curelm->field.next = (elm)->field.next;                 \
        }                                                               \
        if ((head)->last == elm)                                        \
                (head)->last = NULL;                                    \
} while (0)

So my theory is that the channel was busy being dismantled as we tried to
remove the variable.

Here's the channel at the time of the segfault:

(gdb) frame 1
https://issues.asterisk.org/view.php?id=1  0x00726701 in macro_exec
(chan=0x88d8a30, data=0xb79f27e0) at
app_macro.c:253
253             pbx_builtin_setvar_helper(chan, "MACRO_DEPTH", depthc);
(gdb) p *chan
$3 = {name = "Parking/Local/91001 at from-internal-74b8,2<ZOMBIE>", '\0'
<repeats 31 times>, tech = 0x80f4600, tech_pvt = 0x0, 
  language = "en", '\0' <repeats 17 times>, type = 0x7ee627 "Local", fds =
{-1, -1, -1, -1, -1, -1, 172, -1}, 
  musicclass = '\0' <repeats 19 times>, music_state = 0xb6602dd8,
generatordata = 0x0, generator = 0x0, _bridge = 0x0, masq = 0x0, 
  masqr = 0x0, cdrflags = 0, _softhangup = 1, whentohangup = 0, blocker =
3080698800, lock = {__m_reserved = 0, __m_count = 0, 
    __m_owner = 0x0, __m_kind = 1, __m_lock = {__status = 0, __spinlock =
0}}, blockproc = 0x80f4a24 "ast_waitfor_nandfds", 
  appl = 0xb7b437b0 "Macro", data = 0xb79f27e0 "dial|30|tTrh|91001", fdno
= 6, sched = 0x8a3f2c8, streamid = -1, stream = 0x0, 
  vstreamid = 0, vstream = 0x0, oldwriteformat = 64, timingfd = 172,
timingfunc = 0, timingdata = 0x0, _state = 0, rings = 0, 
  nativeformats = 8, readformat = 8, writeformat = 8, cid = {cid_dnid =
0x0, cid_num = 0x0, cid_name = 0x0, cid_ani = 0x0, 
    cid_rdnis = 0x0, cid_pres = 0, cid_ani2 = 0, cid_ton = 0, cid_tns =
0}, 
  context = "macro-dial\000-vm\000able", '\0' <repeats 60 times>,
macrocontext = "from-internal", '\0' <repeats 66 times>, 
  macroexten = "91001", '\0' <repeats 74 times>, macropriority = 1, exten
= "s\000001", '\0' <repeats 74 times>, priority = 10, 
  dtmfq = '\0' <repeats 79 times>, dtmff = {frametype = 0, subclass = 0,
datalen = 0, samples = 0, mallocd = 0, offset = 0, src = 0x0, 
    data = 0x0, delivery = {tv_sec = 0, tv_usec = 0}, prev = 0x0, next =
0x0}, pbx = 0x890bcf8, amaflags = 3, 
  accountcode = '\0' <repeats 19 times>, cdr = 0x88f6bc0, adsicpe = 0,
call_forward = '\0' <repeats 79 times>, zone = 0x0, 
  monitor = 0x0, insmpl = 0, outsmpl = 0, fin = 2969, fout = 1174,
uniqueid = "1136789367.968", '\0' <repeats 17 times>, 
  hangupcause = 16, varshead = {first = 0x0, last = 0x0}, callgroup = 0,
pickupgroup = 0, flags = 528, transfercapability = 0, 
  readq = 0x88a7a58, alertpipe = {-1, -1}, writetrans = 0x0, readtrans =
0x0, rawreadformat = 0, rawwriteformat = 0, spies = 0x88d9560, 
  next = 0x88ad3c0}

Notice the name.  Notice, also, that the varshead.first is null.  Notice,
lastly, that _softhangup == 1.

My proposed fix would be two-phase.

1) Make AST_LIST_REMOVE (and friends?) more defensive.
2) Investigate adding locking to avoid this potential race.

Regards,
Steve Davies

======================================================================
Relationships       ID      Summary
----------------------------------------------------------------------
related to          0015623 [patch] 'h' extension never reach in a ...
====================================================================== 

Issue History 
Date Modified    Username       Field                    Change               
====================================================================== 
2009-08-23 09:39 tilghman       Relationship added       related to 0015623  
======================================================================




More information about the asterisk-bugs mailing list