Bug 972961 - Fix a stack overflow in FoldConstants.cpp. r=luke.

This commit is contained in:
Jason Orendorff 2014-03-10 16:28:44 -05:00
Родитель d815f8827e
Коммит ce5a3686f3
2 изменённых файлов: 100 добавлений и 29 удалений

Просмотреть файл

@ -28,46 +28,68 @@ using mozilla::NegativeInfinity;
using mozilla::PositiveInfinity;
using JS::GenericNaN;
static ParseNode *
ContainsVarOrConst(ParseNode *pn)
static bool
ContainsVarOrConst(ExclusiveContext *cx, ParseNode *pn, ParseNode **resultp)
{
if (!pn)
return nullptr;
if (pn->isKind(PNK_VAR) || pn->isKind(PNK_CONST))
return pn;
JS_CHECK_RECURSION(cx, return false);
if (!pn) {
*resultp = nullptr;
return true;
}
if (pn->isKind(PNK_VAR) || pn->isKind(PNK_CONST)) {
*resultp = pn;
return true;
}
switch (pn->getArity()) {
case PN_LIST:
for (ParseNode *pn2 = pn->pn_head; pn2; pn2 = pn2->pn_next) {
if (ParseNode *pnt = ContainsVarOrConst(pn2))
return pnt;
if (!ContainsVarOrConst(cx, pn2, resultp))
return false;
if (*resultp)
return true;
}
break;
case PN_TERNARY:
if (ParseNode *pnt = ContainsVarOrConst(pn->pn_kid1))
return pnt;
if (ParseNode *pnt = ContainsVarOrConst(pn->pn_kid2))
return pnt;
return ContainsVarOrConst(pn->pn_kid3);
if (!ContainsVarOrConst(cx, pn->pn_kid1, resultp))
return false;
if (*resultp)
return true;
if (!ContainsVarOrConst(cx, pn->pn_kid2, resultp))
return false;
if (*resultp)
return true;
return ContainsVarOrConst(cx, pn->pn_kid3, resultp);
case PN_BINARY:
case PN_BINARY_OBJ:
/*
* Limit recursion if pn is a binary expression, which can't contain a
* var statement.
*/
if (!pn->isOp(JSOP_NOP))
return nullptr;
if (ParseNode *pnt = ContainsVarOrConst(pn->pn_left))
return pnt;
return ContainsVarOrConst(pn->pn_right);
// Limit recursion if pn is a binary expression, which can't contain a
// var statement.
if (!pn->isOp(JSOP_NOP)) {
*resultp = nullptr;
return true;
}
if (!ContainsVarOrConst(cx, pn->pn_left, resultp))
return false;
if (*resultp)
return true;
return ContainsVarOrConst(cx, pn->pn_right, resultp);
case PN_UNARY:
if (!pn->isOp(JSOP_NOP))
return nullptr;
return ContainsVarOrConst(pn->pn_kid);
if (!pn->isOp(JSOP_NOP)) {
*resultp = nullptr;
return true;
}
return ContainsVarOrConst(cx, pn->pn_kid, resultp);
case PN_NAME:
return ContainsVarOrConst(pn->maybeExpr());
return ContainsVarOrConst(cx, pn->maybeExpr(), resultp);
default:;
}
return nullptr;
*resultp = nullptr;
return true;
}
/*
@ -409,8 +431,17 @@ Fold(ExclusiveContext *cx, ParseNode **pnp,
switch (pn->getKind()) {
case PNK_IF:
if (ContainsVarOrConst(pn2) || ContainsVarOrConst(pn3))
break;
{
ParseNode *decl;
if (!ContainsVarOrConst(cx, pn2, &decl))
return false;
if (decl)
break;
if (!ContainsVarOrConst(cx, pn3, &decl))
return false;
if (decl)
break;
}
/* FALL THROUGH */
case PNK_CONDITIONAL:

Просмотреть файл

@ -0,0 +1,40 @@
// Bug 972961 - Test compiler with very long chains of property accesses
// Return true if we can compile a chain of n property accesses,
// false if we cannot. Throw if compilation fails in an unexpected way.
function test(n) {
print("testing " + n);
try {
eval('if (false) {' + Array(n).join(("a.")) + 'a}');
} catch (exc) {
// Expected outcome if the expression is too deeply nested is an InternalError.
if (!(exc instanceof InternalError))
throw exc;
print(exc.message);
return false;
}
print("no exception");
return true;
}
// Find out how long a chain is enough to break the compiler.
var n = 4, LIMIT = 0x000fffff;
var lo = 1, hi = 1;
while (n <= LIMIT && test(n)) {
lo = n;
n *= 4;
}
// Using binary search, find a pass/fail boundary (in order to
// test the edge case).
if (n <= LIMIT) {
hi = n;
while (lo !== hi) {
var mid = Math.floor((lo + hi) / 2);
if (test(mid))
lo = mid + 1;
else
hi = mid;
}
print((lo - 1) + " attributes should be enough for anyone");
}