New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
extend test/ufuzz.js
to inline
& reduce_funcs
#2620
Conversation
This PR will not forward call |
Oops - I forgot about those 😅 |
Okay, the patch looks familiar now. ;-) Let's see what interesting things happen with it. |
I've backed out the |
// original code
// (beautified)
var _calls_ = 10, a = 100, b = 10, c = 0;
if (a++ + [ (c = c + 1) + {}.length, b-- ]) {
var brake2 = 5;
do {
{
var brake3 = 5;
while ((~a ? (c = c + 1) + (a && (a[typeof f0 == "function" && --_calls_ >= 0 && f0((c = 1 + c,
(-4 - Infinity) * (-5 / -4) != (a && (a[(c = c + 1) + ((c = 1 + c, (-5 - 24..toString()) / delete 23..toString() <= (3 || -2) + (NaN !== 22)) ? (c = 1 + c,
a && (a[1 === 1 ? a : b] = NaN >>> false >= (24..toString() || 38..toString()) == ([ , 0 ].length === 2 & 24..toString()) < (a && (a[(c = 1 + c,
(c = c + 1, 25 + "function") >>> (-4 && {}) * (22 == /[a2][^e]+$/))] %= "undefined" == "number")))) : (c = 1 + c,
(c = c + 1, [] && -4) == (a && (a[(c = 1 + c, ([] && 38..toString() || [ , 0 ][1] == 2) << (24..toString() < 22 || undefined >> -3))] >>>= 2 == false)) >= ([] >= [])))] /= "" >> {} !== (c = c + 1,
this)))), (c = 1 + c, (a && (a.var += (a && (a.c += "undefined" / null)) >= 38..toString() - 23..toString())) > (c = c + 1,
c = c + 1, 38..toString())))] *= ((1 ^ 22) == (a && (a[(c = 1 + c, 1 >>> [ , 0 ][1] <= null << -0 >= (25 && "") << ("undefined" !== 3))] += "function" >> "undefined"))) > ("function" << 25 !== this % ([ , 0 ].length === 2)))) : --b + (a && a[{
undefined: (c = c + 1) + (this - null >= (22 || "undefined") >= (0 != []) >>> ([ , 0 ].length === 2) * []),
length: a++ + typeof c_1,
"\t": [ a++ + {
c: (c = 1 + c, (undefined & "number") * (4 | -3) === 3 + "" <= (Infinity, 24..toString())),
3: (c = 1 + c, -5 >= {} ^ 22 >= -1 ^ (24..toString() + ([ , 0 ].length === 2) ^ -4 + -5)),
0: (c = 1 + c, (25 << ([ , 0 ].length === 2) ^ (0 | -1)) % (("bar", {}) >> (0 >> 24..toString())))
}[(c = 1 + c, "function" % 0 - (true != undefined) & 38..toString() > 4 !== "number" * Infinity)], a++ + [ (c = 1 + c,
(a && (a.Infinity += NaN != "object" ^ /[a2][^e]+$/ === "function")) > ((-0 && undefined) !== {} + -1)), (c = 1 + c,
([ , 0 ].length === 2 != [ , 0 ][1] & (22 ^ -2)) << ((/[a2][^e]+$/ ^ "bar") < (Infinity < 2))), (c = 1 + c,
+(/[a2][^e]+$/ ^ 23..toString()) >> (-1 * this || (c = c + 1, false))) ].c ]
}.b]) ? --b + (b-- ? typeof (a++ + [ 0 === 1 ? a : b, a++ + 3, a++ + {
3: (c = 1 + c, -("" % "undefined" <= (25 & 24..toString()))),
1.5: (c = 1 + c, !(("function" & -3) <= (a && (a[(c = 1 + c, (-4 >> {} != (a = "number" & "undefined")) * (("object" !== /[a2][^e]+$/) << ("object" << -5)))] += "foo" >> null)))),
1.5: (c = 1 + c, -1 ^ -3 ^ 2 != -1 ^ (a = [] % [ , 0 ][1] && -0 + 24..toString())),
undefined: (c = 1 + c, (23..toString() === "function") << "foo" % 1 || (3 && -4) >>> (/[a2][^e]+$/ && 22)),
"\t": (c = 1 + c, a = ({} <= 1) << (undefined || "function") ^ (-2 == "") * (true & {}))
} ][++a]) : --b + {
in: (c = c + 1) + {
Infinity: a--
}.length,
1.5: a++ + ~b,
0: (c = c + 1) + function() {
var bar = (c = 1 + c, ((23..toString() !== 22) >= (false ^ 0)) + ((-0 & 4) !== "bar" <= NaN)), Infinity_2 = (c = 1 + c,
c = c + 1, (38..toString() < null) * (Infinity_2 && (Infinity_2[(c = 1 + c, Infinity_2 |= (-0 == 22 != (c = c + 1,
0)) % (5 >> 0 == "object" * "number"))] += 22 * 23..toString())));
}()
}[--b + {
set undefined(arguments_2) {
c = c + 1;
this.b >>= arguments_2 && (arguments_2.undefined = (-3 ^ -2) !== (-4 & -1)) || arguments_2 && (arguments_2[a++ + a++] = "bar" - Infinity < (NaN ^ true));
},
in: --b + (1 === 1 ? a : b),
b: (c = c + 1) + a--,
0: (a || 7).toString()[~(((5, this) ^ "function" != -5) >= (("undefined", this) != 22 % 25))],
var: --b + (a && a.foo)
}]) : a++) && --brake3 > 0) {
var brake6 = 5;
L10038: do {
for (var brake7 = 5; --b + {
1.5: ((--b + [ (c = 1 + c, (a && (a.a += 5 >= undefined)) + ("" + 0) | ((a && (a[(c = 1 + c,
(this % "undefined" === "object" % 38..toString()) > (([ , 0 ][1] ^ "foo") >= this / -5))] += -1 ^ "undefined")) | -3 > "")), (c = 1 + c,
(-4 >= -5 || (a = "foo" % 2)) * ((a = "function" | 0) + (a && (a.a = this * 24..toString())))), (c = 1 + c,
((a && (a.b = "undefined" - -0)) ^ (a += [] ^ null)) / (~-4 & NaN >>> 5)) ] || a || 3).toString() || 8).toString()[--b + (--b + (a++ + [ , (c = 1 + c,
("object" ^ -1) >>> (a += (null, 5)) === ((5, -4) !== ("undefined" & 22))), (c = 1 + c,
(null !== 22 ^ [ , 0 ][1] % 0) & (a *= -3 > {}) << (c = c + 1, 23..toString())), (c = 1 + c,
c = c + 1, (a && (a[(c = 1 + c, ((/[a2][^e]+$/ < "undefined") >> (24..toString() <= -2)) - (a && (a.NaN = (a && (a[(c = 1 + c,
(-1 != -4) * ("object" <= "number") % (([] >> 3) / (5 | -4)))] = -0 << 3)) !== (-3 ^ [ , 0 ][1]))))] = "object" == -2)) < ([ , 0 ][1] ^ 25)), (c = 1 + c,
("" <= -1 ^ -0 < 4) * ({} >> 0, "bar" & 5)) ][(c = 1 + c, (a = (-3 === 38..toString()) >> (null >= "bar")) <= ((4 && 0) == 1 - false))] || 4).toString()[({} / 25 !== (NaN || 1)) > ((a += 22 || {}) >= (38..toString() > "object"))] ? 0 === 1 ? a : b : --b + ((1 === 1 ? a : b) || 9).toString()[(c = c + 1,
true >> 2) || (-2 <= null) / (23..toString() < "bar")])],
0: (c = c + 1) + /[abc4]/.test((a++ + (typeof Math_1 != "object") || b || 5).toString())
} && brake7 > 0; --brake7) {
var a_1;
if (b++) {} else {
function f0(arguments_1, Infinity_1, a_2) {
c = 1 + c, 2 <= 25 != [ , 0 ][1] * "foo" | (c = c + 1, delete -2);
c = 1 + c, ({} <= 22 && 2 >>> 25) === (0 <= 2, 4 % 23..toString());
}
}
}
} while ((c = c + 1) + (typeof a_1 == "function" && --_calls_ >= 0 && a_1(-4)) && --brake6 > 0);
}
}
} while ((b = a) && --brake2 > 0);
} else {
var a_2;
}
if (-0 / ("bar" && 1) / ((NaN, 5) + (NaN !== undefined))) {
c = c + 1;
} else {
var brake19 = 5;
L10039: do {
{
var brake20 = 5;
L10040: do {
for (var brake21 = 5; +(("" && "function") / ({} % "number") - (c = c + 1, 1 == "number")) && brake21 > 0; --brake21) {
(c = c + 1) + void (c = c + 1, 22 >= 3 > (a_1 && (a_1.b = "foo" >> 3)));
}
} while (a_2 && a_2.c && --brake20 > 0);
}
} while (!b && --brake19 > 0);
}
console.log(null, a, b, c); // uglified code
// (beautified)
function f0(arguments_1, Infinity_1, a_2) {
c = 1 + c, c = 1 + (c += 1), 23..toString();
}
var _calls_ = 10, a = 100, b = 10, c = 0;
if (a++ + [ (c += 1) + {}.length, b-- ]) {
var brake2 = 5;
do {
for (var brake3 = 5; (~a ? (c += 1) + (a && (a["function" == typeof f0 && --_calls_ >= 0 && f0((c = 1 + c,
-1 / 0 != (a && (a[(c += 1) + (c = 1 + c, (-5 - 24..toString()) / (23..toString(),
!0) <= 4 ? (c = 1 + c, a && (a[a] = 0 >= (24..toString() || 38..toString()) == (2 === [ , 0 ].length & 24..toString()) < (a && (a[(c = 1 + c,
c += 1, "25function" >>> !1 * {})] %= !1)))) : (c = 1 + c, c += 1, ([] && -4) == (a && (a[(c = 1 + c,
([] && 38..toString() || !1) << (24..toString() < 22 || 0))] >>>= !1)) >= ([] >= [])))] /= "" >> {} !== (c += 1,
this)))), (c = 1 + c, (a && (a.var += (a && (a.c += NaN)) >= 38..toString() - 23..toString())) > (c += 1,
c += 1, 38..toString())))] *= (23 == (a && (a[(c = 1 + c, !0)] += 0))) > (0 != this % (2 === [ , 0 ].length)))) : --b + (a && a[{
undefined: (c += 1) + (this - null >= 22 >= (0 != []) >>> (2 === [ , 0 ].length) * []),
length: a++ + typeof c_1,
"\t": [ a++ + {
c: (c = 1 + c, -0 === "3" <= 24..toString()),
3: (c = 1 + c, -5 >= {} ^ !0 ^ 24..toString() + (2 === [ , 0 ].length) ^ -9),
0: (c = 1 + c, (25 << (2 === [ , 0 ].length) ^ -1) % ({} >> (0 >> 24..toString())))
}[(c = 1 + c, NaN & 38..toString() > 4 !== NaN)], a++ + [ (c = 1 + c, (a && (a.Infinity += 1)) > (-0 !== {} + -1)), (c = 1 + c,
(2 === [ , 0 ].length != 0 & -24) << !1), (c = 1 + c, +(/[a2][^e]+$/ ^ 23..toString()) >> (-1 * this || (c += 1,
!1))) ].c ]
}.b]) ? --b + (b-- ? typeof (a++ + [ b, 3 + a++, a++ + {
3: (c = 1 + c, -(NaN <= (25 & 24..toString()))),
1.5: (c = 1 + c, !(0 <= (a && (a[(c = 1 + c, 1 * (-4 >> {} != (a = 0)))] += 0)))),
1.5: (c = 1 + c, 3 ^ (a = [] % 0 && -0 + 24..toString())),
undefined: (c = 1 + c, ("function" === 23..toString()) << NaN || 1023),
"\t": (c = 1 + c, a = ({} <= 1) << "function" ^ !1 * (!0 & {}))
} ][++a]) : --b + {
in: (c += 1) + {
Infinity: a--
}.length,
1.5: a++ + ~b,
0: (c += 1) + function() {
c = 1 + c, 23..toString();
var Infinity_2 = (c = 1 + c, c += 1, (38..toString() < null) * (Infinity_2 && (Infinity_2[(c = 1 + c,
Infinity_2 |= (0 != (c += 1, 0)) % !1)] += 22 * 23..toString())));
}()
}[--b + {
set undefined(arguments_2) {
c += 1, this.b >>= arguments_2 && (arguments_2.undefined = !0) || arguments_2 && (arguments_2[a++ + a++] = !1);
},
in: --b + a,
b: (c += 1) + a--,
0: (a || 7).toString()[~((!0 ^ this) >= (22 != this))],
var: --b + (a && a.foo)
}]) : a++) && --brake3 > 0; ) {
var brake6 = 5;
do {
for (var brake7 = 5; --b + {
1.5: ((--b + [ (c = 1 + c, (a && (a.a += !1)) + "0" | !1 | (a && (a[(c = 1 + c,
(this % "undefined" == "object" % 38..toString()) > (0 >= this / -5))] += -1))), (c = 1 + c,
!0 * ((a = 0) + (a && (a.a = this * 24..toString())))), (c = 1 + c, ((a && (a.b = NaN)) ^ (a += null ^ [])) / 0) ] || a || 3).toString() || 8).toString()[--b + (--b + (a++ + [ , (c = 1 + c,
-1 >>> (a += 5) === !0), (c = 1 + c, 1 & (a *= -3 > {}) << (c += 1, 23..toString())), (c = 1 + c,
c += 1, (a && (a[(c = 1 + c, (!0 >> (24..toString() <= -2)) - (a && (a.NaN = -3 !== (a && (a[(c = 1 + c,
0 % (([] >> 3) / -3))] = 0)))))] = !1)) < 25), (c = 1 + c, 0) ][(c = 1 + c, (a = (-3 === 38..toString()) >> !1) <= !1)] || 4).toString()[({} / 25 != 1) > ((a += 22) >= (38..toString() > "object"))] ? b : --b + (a || 9).toString()[(c += 1,
!0 / (23..toString() < "bar"))])],
0: (c += 1) + /[abc4]/.test((a++ + ("object" != typeof Math_1) || b || 5).toString())
} && brake7 > 0; --brake7) {
var a_1;
b++;
}
} while ((c += 1) + ("function" == typeof a_1 && --_calls_ >= 0 && a_1(-4)) && --brake6 > 0);
}
} while ((b = a) && --brake2 > 0);
} else {
var a_2;
}
var brake19 = 5;
do {
var brake20 = 5;
do {
for (var brake21 = 5; +("" / ({} % "number") - (c += 1, !1)) && brake21 > 0; --brake21) {
c += 1, c += 1, a_1 && (a_1.b = 0);
}
} while (a_2 && a_2.c && --brake20 > 0);
} while (!b && --brake19 > 0);
console.log(null, a, b, c); original result:
null 101 101 12
uglified result:
null 101 101 77
minify(options):
{
"mangle": false
}
Suspicious compress options:
hoist_funs |
Is it a legitimate fuzz failure? |
I thnk so - |
That's a good question. I suspect if a function is declared within a block in ES6 then it's limited to that block, but I'm not sure. |
$ echo 'if (1) { f(); } else { function f(){console.log(2)} }' | node800
[stdin]:1
if (1) { f(); } else { function f(){console.log(2)} }
^
TypeError: f is not a function $ echo 'if (1) { f(); } else { function f(){console.log(2)} }' | bin/uglifyjs -c | node
2 I think we ran into this problem when the fuzzer was first created: #1666 The thing is that no browser implements ES5 scoping rules any longer - it's all ES6 now. |
fyi... $ echo 'if (1) { f(); } else { function f(){console.log(2)} }' | node0_12_9
2 $ echo '"use strict"; if (1) { f(); } else { function f(){console.log(2)} }' | node0_12_9
[stdin]:1
"use strict"; if (1) { f(); } else { function f(){console.log(2)} }
^^^^^^^^
SyntaxError: In strict mode code, functions can only be declared at top level or immediately within another function. |
Looks like ES6 adopted the ES5 strict mode behavior by default. |
So |
I guess one way around this is to make |
I think even
Perhaps function declarations could still be hoisted so long as every symbol reference could see it in ES6 scope rules. That way all the existing tests will still work. |
All the existing |
It doesn't work anyway with all the other optimizations in place... $ echo 'if (1) { f(); } else { function f(){console.log(2)} }' | bin/uglifyjs -c hoist_funs=0 -b
function f() {
console.log(2);
}
f(); |
That's |
No one has ever really complained about this hoisting behavior in the wild. No one writes code like that. But it certainly impacts fuzzing. |
On the topic of |
Not even for job interview questions? 😈 |
No one would get the job. :-) |
|
I thnk the best course of action is for OTOH compression ratio seems to be better with |
Judging by the numbers it's fine to disable
Declaring and calling functions between scopes is a legitimate test scenario. What if we only generate AST_Defuns at top level or top of functions - i.e. never in blocks? |
Fair point - let me try and do it that way. |
The old node 0.12 error says as much:
|
Right, let's see if 0da91e5 does what it says on the tin... |
50kFuzz // original code
// (beautified)
var _calls_ = 10, a = 100, b = 10, c = 0;
function f0(foo_2, Math_1, undefined_2) {
function f1() {
c = c + 1;
{
var expr2 = (typeof Math || 7).toString()[foo_2 && foo_2[(c = 1 + c, (Math_1 && (Math_1.b >>>= 2 === ([ , 0 ].length === 2))) * ({} >>> "object") ^ (([ , 0 ][1] | undefined) ^ 23..toString() * 5))]] ? foo_2 && foo_2.c : --b + (1 === 1 ? a : b);
for (var key2 in expr2) {
}
}
}
var foo_2 = f1((c = c + 1) + [ a++ + [ (c = 1 + c, (undefined_2 && (undefined_2.in ^= (24..toString() === 24..toString()) >> (undefined == 23..toString()))) !== ((Math_1 && (Math_1[(c = 1 + c,
(Math_1 && (Math_1[(c = 1 + c, (0 + -5 ^ -1 > 1) !== (foo_2 = [] + -3) >> (false == [ , 0 ][1]))] += true || 1)) != (undefined_2 && (undefined_2.in = 22 + 38..toString())) | 5 << /[a2][^e]+$/ ^ "" - 38..toString())] += [ , 0 ][1] ^ 3)) & {} << "bar")), (c = 1 + c,
(Math_1 && (Math_1.b = (c = c + 1, 2) * (null && NaN))) / ({} - true < ([ , 0 ][1] === [ , 0 ][1]))), (c = 1 + c,
Math_1 = (Math_1 && (Math_1[a++ + -((foo_2 = 2 === "") / (-2 + -2) % ((false <= true) / (22 <= 23..toString())))] >>>= "" < -2 | 1 <= this)) >> ([ , 0 ][1] > 23..toString() < 4 << -4)) ].in, 24..toString() ][(c = c + 1) + (a++ + (typeof f1 == "function" && --_calls_ >= 0 && f1()))], undefined, {}[a++ + (b *= a)]);
function f2(a_2, a_2, Math_2) {
{
var NaN = function NaN_2(a_2) {
{
}
c = 1 + c, (-3 >> "function") - (-0 !== NaN) | (a_2 && (a_2.Infinity ^= "number" && 22)) ^ 23..toString() !== [];
}(a_2 && a_2.b);
}
if (--b + ((a_2 || 2).toString()[typeof undefined_2 == "function" && --_calls_ >= 0 && undefined_2(3, (c = 1 + c,
"object" / -1 / (5 < "function") & (a_2 = 25 << -0) - (-4 ^ [])), (c = 1 + c, ((Math_2 && (Math_2.a = Infinity > -5)) & (undefined_2 && (undefined_2[(c = 1 + c,
foo_2 && (foo_2.in /= !(25 || 1) == (23..toString() == 25 !== (22 ^ [ , 0 ][1]))))] += "" && -1))) >> (a_2 = (2 || -0) <= (23..toString() <= /[a2][^e]+$/))))] ? [ (c = 1 + c,
(null | -4) + (foo_2 && (foo_2.c = 22 - 3)) & (a_2 && (a_2.null *= (2 && this) != (undefined == 3)))), (c = 1 + c,
(-5 != {}) / (-4 << 5) / (0 * 5 - (3 <= 1))), (c = 1 + c, (1 == "") << (-3 || -3) === ("" - 0 ^ {} > "")), (c = 1 + c,
undefined !== false == 22 % undefined, (Math_2 = (5, 5)) !== (24..toString() | 22)), (c = 1 + c,
foo_2 && (foo_2[--b] = (-0 - -5 | (22 && 0)) === (-2 ^ 38..toString()) << ([ , 0 ][1] === "foo"))) ][a++ + (undefined_2 && undefined_2[(c = 1 + c,
(-1 + 5) % (22 | 2), (a_2 = {} || 22) != (25 === -5))])] : (c = c + 1) + a_2)) {
try {
L15638: {
c = 1 + c, ("" * -5 !== 2 % "number") % ((a_2.var = 25 << "number") ^ false === -1);
c = 1 + c, (delete 4 | void true) & (-5 && "bar") >= (-4 | Infinity);
}
} catch (Infinity) {
c = c + 1;
} finally {
L15639: {
}
{
var expr15 = (c = 1 + c, false > Infinity <= -5 % -5 === 1 <= 24..toString() < "bar" * []);
for (var key15 in expr15) {
c = 1 + c, -3 * "object" > 5 + "function", -0 == ([ , 0 ].length === 2) || "" >>> -5;
}
}
}
}
}
var a_1 = f2(/[abc4]/.test(("undefined" || b || 5).toString()), 22, --b + a++);
}
var NaN = f0(1);
console.log(null, a, b, c); // uglified code
// (beautified)
function f0(foo_2, Math_1, undefined_2) {
function f1() {
c += 1;
var expr2 = (typeof Math || 7).toString()[foo_2 && foo_2[(c = 1 + c, (Math_1 && (Math_1.b >>>= 2 === (2 === [ , 0 ].length))) * ({} >>> "object") ^ 0 ^ 5 * 23..toString())]] ? foo_2 && foo_2.c : --b + a;
for (var key2 in expr2) {}
}
var a_2;
foo_2 = f1((c += 1, a++, c = 1 + c, undefined_2 && (undefined_2.in ^= (24..toString() == 24..toString()) >> (void 0 == 23..toString())),
Math_1 && (Math_1[(c = 1 + c, (Math_1 && (Math_1[(c = 1 + c, -5 != (foo_2 = [] + -3) >> !0)] += !0)) != (undefined_2 && (undefined_2.in = 22 + 38..toString())) | 5 ^ "" - 38..toString())] += 3),
c = 1 + c, Math_1 && (Math_1.b = null * (c += 1, 2)), c = 1 + c, Math_1 = (Math_1 && (Math_1[a++ + -(foo_2 = !1) / -4 % (!0 / (22 <= 23..toString()))] >>>= !1 | 1 <= this)) >> (0 > 23..toString() < 4 << -4),
24..toString(), c += 1, a++, --_calls_ >= 0 && f1()), (a++, b *= a)), function(a_2, a_2, Math_2) {
if (a_2 = a_2 && a_2.b, c = 1 + c, a_2 && (a_2.Infinity ^= 22), 23..toString(),
--b + ((a_2 || 2).toString()["function" == typeof undefined_2 && --_calls_ >= 0 && undefined_2(3, (c = 1 + c,
0 / 0 & (a_2 = 25) - (-4 ^ [])), (c = 1 + c, ((Math_2 && (Math_2.a = !0)) & (undefined_2 && (undefined_2[(c = 1 + c,
foo_2 && (foo_2.in /= 0 == (25 == 23..toString() !== 22)))] += ""))) >> (a_2 = 2 <= (23..toString() <= /[a2][^e]+$/))))] ? [ (c = 1 + c,
-4 + (foo_2 && (foo_2.c = 19)) & (a_2 && (a_2.null *= 0 != this))), (c = 1 + c,
(-5 != {}) / -128 / 0), (c = 1 + c, 0 == (0 ^ {} > "")), (c = 1 + c, (Math_2 = 5) != (22 | 24..toString())), (c = 1 + c,
foo_2 && (foo_2[--b] = 5 == (-2 ^ 38..toString()) << !1)) ][a++ + (undefined_2 && undefined_2[(c = 1 + c,
0 != (a_2 = {} || 22))])] : (c += 1) + a_2)) {
try {
c = 1 + c, a_2.var = 25, c = 1 + c;
} catch (Infinity) {
c += 1;
} finally {
var expr15 = (c = 1 + c, 1 == 1 <= 24..toString() < "bar" * []);
for (var key15 in expr15) {
c = 1 + c;
}
}
}
}(/[abc4]/.test("undefined".toString()), 22, --b + a++);
}
var _calls_ = 10, a = 100, b = 10, c = 0, NaN = f0(1);
console.log(null, a, b, c); original result:
null 104 924 14
uglified result:
null 104 924 11
minify(options):
{
"mangle": false
}
Suspicious compress options:
inline
reduce_vars
sequences
side_effects
unused |
Fuzz failure above wasn't a cross-scope call. Were nested |
I notice the But then of course, |
So the problem here is |
The problem is that the variable |
Perhaps if a function redefines one of the triad of evil ( |
Unless it's overridden. $ echo 'console.log(NaN===NaN); !function(NaN){console.log(NaN===NaN);}();' | node
false
true |
We aren't using The parser doesn't ever generates Your suggestion of skipping any functions with argument names of |
Checking the function args alone are insufficient. Even local variables of the same name would present a problem.
|
I know. And that's what the compressor did with |
...which is why |
Ah, I see where we differ - I treat |
d92f1ba
to
8565cde
Compare
Rebased and restarted |
Regarding the fuzzer changes in this PR... are all |
AFAICT, only With this PR, the only time the call gets omitted is when there exists a prior In both previous and current cases, an |
My real question with this PR is whether it is possible to potentially generate pairs of AST_Defuns (either sibling or nested) that can call each other (directly or indirectly). |
In theory the following can be generated: var _calls_ = 10, a = 100, b = 10, c = 0;
function f0() {
function f1() {
typeof f2 == "function" && --_calls_ >= 0 && f2();
}
var a_1 = f1();
function f2() {
typeof f1 == "function" && --_calls_ >= 0 && f1();
}
}
var a_2 = f0();
console.log(null, a, b, c); |
Perfect. Will bump up odds of calls to see if we can generate such a case. |
I've seen fuzzed examples of successful recursion and forward calls. Although I haven't seen backward calls, there's no reason why they can't be generated. |
@@ -754,6 +758,16 @@ function _createExpression(recurmax, noComma, stmtDepth, canThrow) { | |||
case p++: | |||
var name = getVarName(); | |||
return name + ' && ' + name + '.' + getDotKey(); | |||
case p++: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think the odds of calls being generated should be bumped up by repeating case p++:
a few times.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done in 1200833
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think 1200833 is what we want. I meant to merely repeat the case p++:
statement many times.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh wait - I now see you doubled the odds. I'd quadruple it at least.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Keep in mind 99% of call attempts never execute, so you need a lot of them.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Doubled again in 19db723
Something I use to hunt interesting test cases: --- a/test/ufuzz.js
+++ b/test/ufuzz.js
@@ -329,6 +329,7 @@ function createTopLevelCode() {
rng(2) == 0
? createStatements(3, MAX_GENERATION_RECURSION_DEPTH, CANNOT_THROW, CANNOT_BREAK, CANNOT_CONTINUE, CANNOT_RETURN, 0)
: createFunctions(rng(MAX_GENERATED_TOPLEVELS_PER_RUN) + 1, MAX_GENERATION_RECURSION_DEPTH, DEFUN_OK, CANNOT_THROW, 0),
+'if (_calls_ < 10 && _calls_ >= 0) throw new Error(_calls_);',
'console.log(null, a, b, c);' // preceding `null` makes for a cleaner output (empty string still shows up etc)
].join('\n');
} |
When the odds of generating calls was increased by 8 times the following ( $ cat fuzz.js
// original code
// (beautified and annotated)
var _calls_ = 10, a = 100, b = 10, c = 0;
function f0() {
console.log("*** function f0, _calls_ =", _calls_);
function f1(c_1, parseInt_1, b_2) {
console.log("*** function f1, _calls_ =", _calls_);
c = c + 1;
c = c + 1;
}
var c = f1(5);
function f2(bar_1, b_1) {
console.log("*** function f2, _calls_ =", _calls_);
function f3(b, Infinity) {
console.log("*** function f3, _calls_ =", _calls_);
var Infinity;
try {
c = 1 + c, b_1 && (b_1.Infinity = ("" != Infinity) >> ("undefined" != -2) & (3 ^ -1) <= [ , 0 ][1] >>> "undefined");
} catch (Infinity_2) {
}
}
var a_1 = f3(22);
function f4(a, undefined_1) {
console.log("*** function f4, _calls_ =", _calls_);
function f5(arguments) {
console.log("*** function f5, _calls_ =", _calls_);
}
var bar = f5((c = 1 + c, +(0 + this && 3 & "function")), (c = 1 + c, (-5 == /[a2][^e]+$/ ^ 25 == 3) < ("foo" != "function" && -0 !== 22)), (c = 1 + c,
(bar_1 && (bar_1[typeof b_1 == "function" && --_calls_ >= 0 && (console.log("*** calling b_1, _calls_ =", _calls_), b_1())] = -4 >>> -3 >> (false !== 22))) <= (22 % [ , 0 ][1] !== (22 && [ , 0 ].length === 2))));
}
var b_2 = f4(b -= a, void function() {
}());
function f6(b_2, bar_1, bar_2) {
console.log("*** function f6, _calls_ =", _calls_);
if (c = 1 + c, (-1 === -4) * (0 / "object") == (([ , 0 ].length === 2) >>> null | 3 + "foo")) {
c = 1 + c, (false != {}, 2 && []) < (2 >> -4 ^ 5 >> "bar");
} else {
c = 1 + c, (bar_1 && (bar_1.null = NaN !== 2)) == (/[a2][^e]+$/ | 1) == "function" << "function" << ("undefined" > 4);
}
{
}
}
var undefined_2 = f6();
}
var bar = f2();
function f7() {
console.log("*** function f7, _calls_ =", _calls_);
return a++ + -((a && (a.foo &= (/[a2][^e]+$/ == NaN) - undefined / /[a2][^e]+$/)) <= (a && (a[typeof f0 == "function" && --_calls_ >= 0 && (console.log("*** calling f0, _calls_ =", _calls_), f0((c = 1 + c,
delete (true !== "undefined") + (a && (a[(c = c + 1) + (typeof a == "function" && --_calls_ >= 0 && (console.log("*** calling a, _calls_ =", _calls_), a([ , 0 ].length === 2)))] += (a += 5 | undefined) > (1 ^ [])))), -4, (c = 1 + c,
(c = c + 1, 1) << ("" != 1), a && (a.null += ([ , 0 ][1] ^ "object") & 3 == 4))))] += (0 > 25) + (c = c + 1,
22))));
}
var arguments_2 = f7((c = c + 1) + typeof bar_1, --b + ((NaN < -1) >> undefined / undefined | [ , 0 ][1] >> [] << (24..toString(),
23..toString())));
function f8(a_1, foo_1) {
console.log("*** function f8, _calls_ =", _calls_);
{
var expr12 = (c = c + 1) + b++;
for (var key12 in expr12) {
c = 1 + c;
var parseInt_1 = expr12[key12];
{
var brake13 = 5;
do {
for (var brake14 = 5; --b + parseInt_1 && brake14 > 0; --brake14) {
var brake15 = 5;
while ((c = 1 + c, (Infinity - -0) / -true | (a_1 && (a_1[(c = 1 + c, (-0 ^ 4) * (0 ^ [ , 0 ][1]) === ([ , 0 ][1] & -1) << (a_1 && (a_1[(c = 1 + c,
24..toString() % "foo" / delete "bar" == ([ , 0 ][1] % -4 | ([ , 0 ].length === 2 && -0)))] = 38..toString() <= "bar")))] = (-5,
[ , 0 ].length === 2))) + +"function") && --brake15 > 0) {
c = 1 + c, c = c + 1, (Infinity, "undefined") << (NaN, -3);
}
}
} while ((0 === 1 ? a : b) && --brake13 > 0);
}
}
}
return [ , a++ + Infinity, typeof parseInt_1 == "function" && --_calls_ >= 0 && (console.log("*** calling parseInt_1, _calls_ =", _calls_), parseInt_1("number", (c = 1 + c,
(foo_1 && (foo_1.a = ("function" && "") << (this < -1))) & (parseInt_1 && (parseInt_1[typeof f10 == "function" && --_calls_ >= 0 && (console.log("*** calling f10, _calls_ =", _calls_), f10())] = NaN * this + ("foo" !== "foo")))), (c = 1 + c,
(24..toString() >>> "function" || 23..toString() != "undefined") >> (38..toString() - 25 << (Infinity || -2))))), a++ + void function b_1() {
}() ].NaN;
}
var arguments = f8();
}
var Infinity_1 = f0((c = c + 1) + /[abc4]/.test((typeof a_1 == "function" || b || 5).toString()), 38..toString());
console.log(null, a, b, c);
|
LGTM |
- forward call `fN()` - allow forward call functions to be single-use - avoid generating `AST_Defun` within blocks
19db723
to
49d1577
Compare
Commits squashed - pending 1MFuzz before merge... 🤖 @kzc thanks for the help, as usual 💯 |
Do you still plan to disable |
Thanks for the reminder - yes, I think it makes sense judging from the statisitics. I'll scan through the actual diffs to make sure nothing funky is happening, but otherwise it'll be off by default from Hopefully I'll get some hints for your hypothesis on |
#2533 (comment)
@kzc I've also adjusted
test/ufuzz.json
, the highlight beingunsafe
asrename
should now circumvent any corner cases regardingInfinity
,NaN
orundefined
.