Index: apps/app_macro.c =================================================================== --- apps/app_macro.c (revision 60763) +++ apps/app_macro.c (working copy) @@ -161,6 +161,14 @@ struct ast_context *c; struct ast_exten *e; + /* Approximation of log10(pow(2, n - 1)) + 3, which is the number of + * characters needed to print a signed integer of n bits, where n is the + * native pointer size. Due to integer rounding, this is good for quite + * a long time. + */ + char stackheadc[sizeof(void *) * 9999 / 4000 + 3]; + void *stackhead; + if (ast_strlen_zero(data)) { ast_log(LOG_WARNING, "Macro() requires arguments. See \"show application macro\" for help.\n"); return -1; @@ -181,6 +189,19 @@ depth = 0; } + /* Since people keep finding new ways to overflow the stack with Macro, + * here is a new approach to avoid future crashes -- just count the amount + * of stack used so far and return before we near our limit. + */ + tmp = pbx_builtin_getvar_helper(chan, "MACRO_STACKHEAD"); + if (tmp) { + sscanf(tmp, "%p", &stackhead); + } else { + stackhead = &tmp; + snprintf(stackheadc, sizeof(stackheadc), "%p", stackhead); + pbx_builtin_setvar_helper(chan, "MACRO_STACKHEAD", stackheadc); + } + /* Used for detecting whether to return when a Macro is called from another Macro after hangup */ if (strcmp(chan->exten, "h") == 0) pbx_builtin_setvar_helper(chan, "MACRO_IN_HANGUP", "1"); @@ -193,6 +214,17 @@ LOCAL_USER_REMOVE(u); return 0; } + + /* 200,000 is an arbitrary number lower than 240k, which is the current + * per-thread stack size. Also, we abs() the value, so that it doesn't + * matter which way the stack grows (per arch). + */ + if (abs((long)&tmp - (long)stackhead) > 200000L) { + ast_log(LOG_ERROR, "Macro(): you have consumed too much per-thread stack space. Returning early to avoid a possible crash.\n"); + LOCAL_USER_REMOVE(u); + return 0; + } + snprintf(depthc, sizeof(depthc), "%d", depth + 1); pbx_builtin_setvar_helper(chan, "MACRO_DEPTH", depthc);