зеркало из https://github.com/mozilla/gecko-dev.git
Bug 972961 - Fix a stack overflow in FoldConstants.cpp. r=luke.
This commit is contained in:
Родитель
d815f8827e
Коммит
ce5a3686f3
|
@ -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");
|
||||
}
|
Загрузка…
Ссылка в новой задаче