Skip to content
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

ufuzz failure #4598

Closed
alexlamsl opened this issue Jan 30, 2021 · 18 comments · Fixed by #4599
Closed

ufuzz failure #4598

alexlamsl opened this issue Jan 30, 2021 · 18 comments · Fixed by #4599
Labels

Comments

@alexlamsl
Copy link
Collaborator

// original code
// (beautified)
var _calls_ = 10, a = 100, b = 10, c = 0;

function f0(b_1) {
    {
        var expr1 = ([] == 0 & "object" ** [ , 0 ][1]) > (NaN <= ([ 3n ][0] > 2) ^ 22 + 3);
        L28280: for (var key1 in expr1) {
            c = 1 + c;
            var a_2 = expr1[key1];
            if (~((a_2 && (a_2[b_1 && typeof b_1.c == "function" && --_calls_ >= 0 && b_1.c((c = 1 + c, 
            ((NaN ^ 38..toString()) >= (-5 && 2)) << ("bar" / undefined >>> (25 & -2))))] |= Number(0xdeadn << 16n | 0xbeefn) <= 5 ^ -3 <= "foo")) === this % 23..toString() << ("a" > "c"))) {
                switch (a_2 && a_2.length) {
                  case --b + (b = a):
                    {
                        var expr4 = (c = c + 1) + ("" in [ (c = c + 1) + (typeof bar == "number"), b_1, ...[], [ (c = 1 + c, 
                        (("b" <= 38..toString()) << ("function" ^ "number")) - (("a" || 0) && (!0o644n, 
                        [ , 0 ].length === 2))), (c = 1 + c, (c = c + 1, [] % NaN) >> (22 * -3 << (0 !== {}))), (c = 1 + c, 
                        a_2 && (a_2[a++ + +function a_2() {
                            c = 1 + c, a_2 && (a_2[!({} - Infinity > 1 * 0 & ([] ^ -3) != ([ 3n ][0] > 2, ""))] |= ((a_2 /= "b" !== 4) >= -3 + 38..toString()) - (a_2 && (a_2[a_2 && a_2.null] += (a_2 && (a_2[c = 1 + c, 
                            ((-3 & true) > (this != "bar")) / ("function" < !0o644n | /[a2][^e]+$/ <= [ , 0 ][1])] = "a" / "function")) / ([ , 0 ].length === 2 ^ {}))));
                            c = 1 + c, c = c + 1, (5 & 3) <= (a_2 && (a_2.NaN = NaN - -5));
                            c = 1 + c, "c" ^ 2 && 5 <= 4, ("a" !== "foo") * (2 === false);
                            c = 1 + c, a_2 = (/[a2][^e]+$/ % (-42n).toString(), Number(0xdeadn << 16n | 0xbeefn) / "foo") == ([ 3n ][0] > 2 != false) * (22 >> "a");
                        }()] *= 0 % 25 % (Number(0xdeadn << 16n | 0xbeefn) + /[a2][^e]+$/) >> ("" >>> "" & ("number" | 38..toString())))), (c = 1 + c, 
                        (25 ^ 23..toString()) & (!0o644n ^ Number(0xdeadn << 16n | 0xbeefn)) ^ (a_2 && (a_2["c" in [ (c = 1 + c, 
                        ((NaN || -2) ^ (a_2 && (a_2[c = 1 + c, ("b" ^ [ , 0 ][1]) < (c = c + 1, 4) !== (38..toString() >> -5 & ("bar", 
                        -5))] -= -5 == 38..toString()))) << ((a_2 && ([ a_2[c = 1 + c, !0o644n - 5 <= (/[a2][^e]+$/ < -4) < ("a" % "c") ** (!0o644n % "bar")] ] = [ 22 / "b" ])) << (b_1 && (b_1[c = 1 + c, 
                        (a_2 && ([ a_2.NaN ] = [ 25 * -4 != ("function" != this) ])) <= 0 % [] - ("a" << ([ 3n ][0] > 2))] <<= -0 / /[a2][^e]+$/)))), ...[ (c = 1 + c, 
                        b_1 && (b_1[b++] += "b" >= this > (3 === ([ , 0 ].length === 2)) == (true ^ 22) + (-1, 
                        0))), (c = 1 + c, ((a_2 = "undefined" >> 25) & "number" >> "c") < (a_2 = (-1 & 24..toString()) < 0 << NaN)) ], (c = 1 + c, 
                        (c = c + 1, 0) >>> "bar" % /[a2][^e]+$/ !== ("number" || (-42n).toString()) << ("bar" & 4)), (c = 1 + c, 
                        (([ , 0 ].length === 2) + 5, 2 !== "foo") - ((c = c + 1, [ , 0 ][1]) === + -4)) ]] = 2 / -4 << 4 * 5))) ][[ (c = 1 + c, 
                        (b_1 && (b_1.c = (38..toString() ^ -2) < -0 << true)) + ("bar" >> 25 >= 2 << "undefined")), (c = 1 + c, 
                        !0o644n >>> "foo" | -2 ^ Number(0xdeadn << 16n | 0xbeefn) && (b_1 && (b_1[(c = c + 1) + ((38..toString() >= []) / (-1 < NaN) ^ (-1 && "function", 
                        [ 3n ][0] > 2 < "number"))] &= -"object" * (-3 * "number")))), (c = 1 + c, ("object" < 5 || null == 3) - (0 ^ "c") / ([ 3n ][0] > 2 <= 2)), (c = 1 + c, 
                        a_2 && (a_2.a += {} % -0 % (b_1 && (b_1[c = 1 + c, (-4 << Infinity | 25 ^ -0) << (-5 > -2 || "undefined" | [ 3n ][0] > 2)] += 23..toString() ^ undefined)) - (undefined ^ 3, 
                        1 | 23..toString()))) ][c = 1 + c, (a_2 = (24..toString() || []) % ("" <= "function")) & ([] && "c" && "function" % -3)]], typeof b_1 != "object" ]);
                        for (var key4 in expr4) {
                            if (--b + {}) {
                                L28281: {
                                    {
                                    }
                                    c = c + 1;
                                    {
                                        var brake13 = 5;
                                        L28282: do {
                                            c = 1 + c, (NaN - 3 && true | 2) >>> (b_1 = (c = c + 1, "object") ^ (!0o644n, "function"));
                                        } while ((c = 1 + c, (-42n).toString() > -5 & [ , 0 ][1] * [ , 0 ][1] ^ (b_1 %= -1 > 2 >= (-4 || true))) && --brake13 > 0);
                                    }
                                }
                            } else {
                                -4 in [];
                            }
                        }
                    }
                    var a_2 = --b + (typeof f0 == "function" && --_calls_ >= 0 && f0(a++ + (a_2 && a_2.null), 24..toString()));
                    break;

                  case --b:
                    break;

                  case (c = c + 1) + (a_2 && typeof a_2.length == "function" && --_calls_ >= 0 && a_2.length(((c = c + 1) + (a_2 = (c = c + 1) + (((a_2 && (a_2[c = 1 + c, 
                    (-1 >>> (-42n).toString() > !0o644n / -5) - ("function" != -4, -5 / -4)] &= /[a2][^e]+$/ * 0)) == (/[a2][^e]+$/ === [ , 0 ][1])) >>> (("a" <= -2) >>> this * null))) || 5).toString()[null], "bar", 23..toString())):
                    if (--b + /[abc4]/g.exec(((--b + [ (c = 1 + c, ([ 3n ][0] > 2 == 24..toString()) / ("undefined" << "") >>> "undefined" % "" % (-2 >> [])), (c = 1 + c, 
                    ((a_2 && (a_2[c = 1 + c, (true >> 2 | "" > /[a2][^e]+$/) >= ("a" <= ([ 3n ][0] > 2) ^ {} - null)] = "c" == 23..toString())) == Infinity >>> 38..toString()) >= /[a2][^e]+$/ % "function" / (5 && -0)) ].NaN ? --b + ("undefined" in [ (c = 1 + c, 
                    (-2 == [ 3n ][0] > 2) < ("object" != !0o644n) <= (a_2 && (a_2[1 === 1 ? a : b] = (c = c + 1, 
                    25) >> (a_2 && (a_2.NaN = -5 && "b"))))), (c = 1 + c, ({} + "foo") / (-1 != 5) << (38..toString() !== {} === -0 - {})), (c = 1 + c, 
                    (-1 ^ NaN | undefined >>> -2) >= ("foo" & -2, 5 / -4)) ]) : --b) || b || 5).toString())) {
                        return b ^= a;
                    } else {
                        {
                            c = 1 + c, ("foo" == -0) >> ("a" >>> 25) | (-2 ^ [ , 0 ][1], 3 >> undefined);
                        }
                    }
                    break;

                  case a_2:
                    break;
                }
            }
        }
    }
    {
        {
            var a_1 = function f1(foo, a_2) {
                async function f2(a_2, foo_1, b) {
                    {
                        var brake36 = 5;
                        do {
                            c = 1 + c, (b_1 = -2 <= NaN ^ (c = c + 1, 3)) >= (("b" & 4) === (23..toString() ^ undefined));
                        } while ((c = 1 + c, foo_1 += (Infinity - /[a2][^e]+$/ | (-1 && 1)) >>> (c = c + 1, 
                        "undefined" !== "function")) && --brake36 > 0);
                    }
                    if (c = 1 + c, (5 != 4) + ("bar" >>> (-42n).toString()) <= (25 & [ , 0 ].length === 2) * ("function" | -5)) {
                        c = 1 + c, (null >>> 0) + (38..toString() > NaN) << (-{} ^ "" + "undefined");
                    }
                }
                var foo = f2("number", --b + (typeof f2 == "function" && --_calls_ >= 0 && f2((c = 1 + c, 
                "foo" < 5 >= (null ^ 5) != (5 == false) % (Infinity ^ null)))), --b + (a_2 && typeof a_2.var == "function" && --_calls_ >= 0 && a_2.var((c = 1 + c, 
                (-4 + "function") * ("number" & [ 3n ][0] > 2) == (Infinity <= false != -0 > [])), /[a2][^e]+$/, "a")));
            }(1 === 1 ? a : b, !function b_2() {
                switch (a++ + (b = a)) {
                  default:
                    L28283: {
                    }

                  case function a(a_1, a_2_2, c) {
                        c = 1 + c, (1 << "function") / (3 & false) >= ("number" >> -2 == -5 * -5);
                        c = 1 + c, (24..toString() !== "number" | 2 << -5) ^ ("function" && "undefined") - 1 * -4;
                        c = 1 + c, c = c + 1, (a_1 && (a_1.c += -4 || "function")) >>> (true | 23..toString());
                    }((c = 1 + c, (this & []) / ([ , 0 ][1] != 24..toString()) | 5 >> 0 >> (([ , 0 ].length === 2) >> 3))):
                    break;

                  case delete (void 0 % (-0 * 4) !== (c = c + 1, b_1 && (b_1.var |= "object" === [ , 0 ][1]))):
                    var b_2_2 = (c = 1 + c, (38..toString() !== -3 != ("" & "c")) >= (("function" === false) >= (undefined ^ 5)));
                    break;

                  case b_1 |= {
                        foo: (c = 1 + c, (undefined ^ 1) !== ([ , 0 ].length === 2 === "foo") === (b_1 && ({
                            [b_2 && b_2.a]: b_1.in
                        } = {
                            0: (Infinity !== ([ , 0 ].length === 2)) >>> (b_1 && (b_1.null += Number(0xdeadn << 16n | 0xbeefn) == NaN))
                        }))),
                        b: (c = 1 + c, (b_1 = (38..toString(), [])) <= ([ 3n ][0] > 2) % Number(0xdeadn << 16n | 0xbeefn) | undefined * [] === (-0, 
                        NaN)),
                        "-2": (c = 1 + c, ("number" & NaN) >= "undefined" % 25 | (25 != 38..toString()) > (b_2_2 && ({
                            b: b_2_2[c = 1 + c, undefined << 23..toString() & !0o644n << Number(0xdeadn << 16n | 0xbeefn) || [ , 0 ][1] ^ -1 ^ -1 < 38..toString()]
                        } = {
                            b: 25 - 1
                        }))),
                        "-2": (c = 1 + c, NaN > 38..toString() || this >= 38..toString() || [] ^ 24..toString() ^ "function" === true)
                    }.null:
                    ;
                    break;
                }
                --b + (a++ || 9).toString()[(c = c + 1) + b_2_2];
                {
                    var expr32 = a++ + (typeof f2 == "function" && --_calls_ >= 0 && f2((c = 1 + c, 
                    void (-4 * 38..toString()) >= (c = c + 1, b_2_2 = "c" * 3)), false, (c = 1 + c, 
                    (c = c + 1, "number" && 24..toString()) * ({} / 1 && NaN % "function"))));
                    L28284: for (var key32 in expr32) {
                        {
                            var brake33 = 5;
                            L28285: do {
                                for (var brake34 = 5; (c = 1 + c, void "b" < ([ 3n ][0] > 2) / -1 ^ ("function" != this || NaN > "")) && brake34 > 0; --brake34) {
                                    c = 1 + c, -4 <= -0 & !0o644n >> 25 ^ (Number(0xdeadn << 16n | 0xbeefn) == "number" ^ Number(0xdeadn << 16n | 0xbeefn) <= 3);
                                }
                            } while (a++ + (1 === 1 ? a : b) && --brake33 > 0);
                        }
                    }
                }
            }());
        }
        {
            var brake40 = 5;
            while (--b + (typeof f2 == "function" && --_calls_ >= 0 && f2(23..toString(), false)) && --brake40 > 0) {
                var foo = a++ + (typeof b_2 == "function" && --_calls_ >= 0 && b_2(1)), b_2 = (c = c + 1) + [][{
                    "-2": typeof arguments,
                    in: a++ + (Number(0xdeadn << 16n | 0xbeefn) in {
                        NaN: (c = 1 + c, (a_2 = [ , 0 ][1] & 22) * ([ 3n ][0] > 2 | true) % ([] * {} >>> (a_1 && (a_1.foo >>>= 24..toString() === 25)))),
                        foo: (c = 1 + c, (a_1 && (a_1[a++ + (c = 1 + c, ([ 3n ][0] > 2 | -1, false || {}) * ((Infinity >>> -4) / (-4 + [])))] <<= (NaN === 5) < (-2, 
                        true))) | 1 / 0 !== 23..toString() * 5),
                        "-2": (c = 1 + c, (Number(0xdeadn << 16n | 0xbeefn) <= 38..toString()) * (3 / 5) !== NaN * -5 >>> "bar" + 1),
                        undefined: (c = 1 + c, (!0o644n << !0o644n !== (a_1 >>>= 0 % "foo")) >= ((undefined & 5) !== "" << ([ , 0 ].length === 2)))
                    }),
                    "-2": [ (c = 1 + c, void (b_2 += (1 ^ "number") === (22 || Number(0xdeadn << 16n | 0xbeefn)))), (c = 1 + c, 
                    c = c + 1, b_1 && ([ b_1[a_2 && typeof a_2.var == "function" && --_calls_ >= 0 && a_2.var((c = 1 + c, 
                    ((1 || 2) <= ~"number") - ((NaN && [ 3n ][0] > 2) !== (a_2 = -5 >>> 5))))] ] = [ (a_2 && (a_2[c = 1 + c, 
                    ("a" === 38..toString()) >>> (24..toString() != 1) ^ (0 >>> 23..toString() || ~25)] = 4 >>> 23..toString())) ^ (5 || "bar") ])), (c = 1 + c, 
                    NaN != ([ , 0 ].length === 2) ^ false < 5 && (a_1 && (a_1.a /= Infinity * -4)) ^ -4 + !0o644n) ]
                }];
            }
        }
        {
            switch (b++) {
              default:
                {
                    var brake44 = 5;
                    do {
                        L28286: {
                            c = 1 + c, a_1 && (a_1[(c = c + 1) + function() {
                                c = 1 + c, foo && (foo[a++ + foo] = undefined <= "undefined" !== 0 >= null ^ NaN != -3 & "foo" + "number");
                                c = 1 + c, ("foo" >> true >> (a_2 += [ , 0 ][1] << 4)) - (-2 * /[a2][^e]+$/ >>> (3 | "b"));
                                c = 1 + c, (c = c + 1, "bar" << "") !== (3 % "bar" ^ "b" << ([ 3n ][0] > 2));
                            }()] = (null & "foo" ^ "b" ** 2) == (("foo" | "bar") == 3 <= Number(0xdeadn << 16n | 0xbeefn)));
                            c = 1 + c, a_2 && (a_2[foo && foo[void a]] += ("foo" === "foo" | !0o644n << 23..toString()) % ("undefined" && [ , 0 ].length === 2 && 5 >>> NaN));
                            c = 1 + c, 3 - "number" <= ((-42n).toString() == {}), undefined >>> !0o644n << (!0o644n != -4);
                        }
                    } while ({
                        "\t": (c = 1 + c, b_2 && (b_2.undefined = (c = c + 1, 38..toString()) * (2 !== [ 3n ][0] > 2) >= (a_1 && (a_1[--b + (-5 in [])] += ([ , 0 ].length === 2) - "b" + ([] ^ [ , 0 ][1]))))),
                        "-2": (c = 1 + c, 5 << undefined > (5 != 3) || (c = c + 1, 1) <= ("a" != "a")),
                        c: (c = 1 + c, (2 ^ 0 || this | {}) >> ("bar" % 4 >> (false || 38..toString())))
                    }[a++ + ((true >>> {} ^ ((-42n).toString() ^ 5)) >= (this || 24..toString()) % (c = c + 1, 
                    2))] && --brake44 > 0);
                }
                var a_2_2 = --b + (typeof f0 == "function" && --_calls_ >= 0 && f0("b", (c = 1 + c, 
                (null / 2 | "foo" << -2) ^ (a_2 = (a_1 && (a_1[c = 1 + c, ((b_2 = Infinity >> "foo") ^ "function" == ([ , 0 ].length === 2)) <= ((-1 != -1) > ("c", 
                0))] = NaN % !0o644n)) & 24..toString() - -4)), 25));

              case typeof b_2 == "function" && --_calls_ >= 0 && b_2(--b + (b += a)):
                break;

              case typeof f2 == "function" && --_calls_ >= 0 && f2(-4):
                switch ([ ...[ (c = 1 + c, {} + "foo" << !this <= (a_2_2 <<= 25 != "object" & null << 0)) ] ].null) {
                  case [ (c = 1 + c, ("c" !== 23..toString()) - (a_2 && (a_2.NaN += "b" - Infinity)) <= ((-42n).toString() <= {}) ** (-2 != 5)) ][/[abc4]/g.exec(((c = 1 + c, 
                    a_2 && (a_2[typeof a_1 == "function"] += 4 * Number(0xdeadn << 16n | 0xbeefn) * (c = c + 1, 
                    [ , 0 ].length === 2) / ({} * "c" + (-5 !== 3)))) || b || 5).toString())]:
                    break;

                  default:
                    if (c = 1 + c, (c = c + 1, -4) <= (a_2_2 && (a_2_2[c = 1 + c, b_2 = ("number" | "undefined", 
                    ([ , 0 ].length === 2) < "") || delete 3 + (Infinity === (-42n).toString())] *= Infinity - {})) != ("function" - [] | /[a2][^e]+$/ & undefined)) {
                        c = 1 + c, a_2 && (a_2.foo += (4 & 25) << ("" != undefined) === ((b_1 += -3 >>> "c") ^ 23..toString() % 22));
                    } else {
                        c = 1 + c, (!0o644n ^ 22) - ([ , 0 ][1] < "c") > ([ , 0 ][1] - ([ 3n ][0] > 2) < (2 <= "c"));
                    }
                    switch (c = 1 + c, a_2_2 && (a_2_2.Infinity = null <= -5 || -4 >> /[a2][^e]+$/) || (1 || 24..toString()) === (a_2_2 && (a_2_2.a *= "bar" || 25))) {
                      case c = 1 + c, (/[a2][^e]+$/ > 24..toString()) - (24..toString() - [ , 0 ][1]) | delete ("bar" ^ [ , 0 ][1]):
                        ;

                      case c = 1 + c, -0 === null || false & "a" || NaN >= "number" > -4 << 0:
                        ;
                        break;

                      case c = 1 + c, (a_2 && (a_2.NaN = 22 !== "foo")) != ([ , 0 ].length === 2) / "bar" & ("bar" >= 25) * ("b" | "bar"):
                        ;
                        break;

                      case c = 1 + c, a_2_2 && (a_2_2[--b + (a_2_2 && typeof a_2_2.c == "function" && --_calls_ >= 0 && a_2_2.c(..."" + a_2_2))] |= (-4 !== 0) > (-5 || [ 3n ][0] > 2) & (c = c + 1, 
                        a_2 && (a_2.null += "foo" !== [ , 0 ][1]))):
                        ;
                        break;
                    }

                  case a++ + b_1:
                    c = c + 1;
                    {
                    }

                  case {
                        foo: foo,
                        [(c = 1 + c, (-2 * 4 && -2 + "foo") > ([] | 4) + 24..toString() * undefined)]: (c = 1 + c, 
                        foo && (foo[(c = c + 1) + (1 === 1 ? a : b)] += (2 !== -2 !== ([ 3n ][0] > 2 & 22)) > (Number(0xdeadn << 16n | 0xbeefn) | (-42n).toString()) / (25 + 5))),
                        length: (c = 1 + c, !true > -4 % 1 | (b_1 = "a" / -0) == "c" % /[a2][^e]+$/)
                    }[c = 1 + c, ([] ^ "b") <= "number" / "function" <= (a_1 && (a_1[a--] = null === "foo" === 38..toString() / -4))]:
                    {
                        var brake60 = 5;
                        do {
                            c = 1 + c, "" >= ([ , 0 ].length === 2) < (this != [ , 0 ][1]) == (3 < /[a2][^e]+$/ === ([ , 0 ].length === 2 !== -4));
                        } while ((c = 1 + c, ("foo" === /[a2][^e]+$/ | 5 & Number(0xdeadn << 16n | 0xbeefn)) - (3 != 22 && -0 < null)) && --brake60 > 0);
                    }
                    break;
                }
                {
                    var brake62 = 5;
                    do {
                        {
                            var expr63 = ++b;
                            for (var key63 in expr63) {
                                c = 1 + c;
                                var NaN_2 = expr63[key63];
                                c = 1 + c, ("b" < "object") + (38..toString() === -3) === 5 % "number" > (3 & 1);
                            }
                        }
                    } while (a++ + (/[a2][^e]+$/ * (-42n).toString() + (this < "a")) / (23..toString() - NaN >>> (c = c + 1, 
                    "bar")) && --brake62 > 0);
                }
                break;

              case foo && typeof foo.in == "function" && --_calls_ >= 0 && foo.in([ , 0 ].length === 2, ..."" + a_1):
                c = c + 1;
                break;
            }
            {
                var expr66 = b <<= a;
                L28287: for (var {
                    length: key66
                } in expr66) {
                    c = 1 + c;
                    var NaN = expr66[key66];
                    switch ([ a_2_2 && a_2_2[c = 1 + c, ({} === "bar" || !0o644n - undefined) / ((b_2 && (b_2.NaN = [] > "bar")) < (22 < {}))], a++ + ((c = 1 + c, 
                    "bar" ^ "object" || 25 ^ NaN || (this === []) > (22 | "")) || a || 3).toString() ][a++ + [ (c = 1 + c, 
                    (c = c + 1, 23..toString() > "object") >= "bar" * "c" >> ("c" !== true)), (c = 1 + c, 
                    delete (b_1 = ("b" < "foo", 22 >= 2))) ][a++ + --b]]) {
                      case (c = c + 1) + (true in {}):
                        break;

                      case --b:
                        break;

                      case a_2_2:
                        try {
                            {
                                return c = 1 + c, (a_2_2 && (a_2_2[--b + typeof (c = 1 + c, +((b_2 = (-42n).toString() - !0o644n) - ("number" - "")))] -= ("c" == Number(0xdeadn << 16n | 0xbeefn)) - (38..toString() !== "bar"))) * (/[a2][^e]+$/ <= 4 == -0 << "function");
                            }
                        } catch {
                            c = 1 + c, (+(-42n).toString() | Infinity & []) / ((a_2 && (a_2.b &= 4 << -0)) % (true << /[a2][^e]+$/));
                            c = 1 + c, b_1 && (b_1.b = (("a" == /[a2][^e]+$/) >= (!0o644n ^ "")) * (([] ^ /[a2][^e]+$/) >> (false >>> Infinity)));
                        } finally {
                            c = 1 + c, ([ , 0 ].length === 2) << (-42n).toString() | [] === -1 && {} / 24..toString() & -5 << this;
                            c = 1 + c, (foo && (foo.a += "" - -2 < (false, -0))) >= (NaN && [ , 0 ][1]) * (-1 & NaN);
                        }
                        {
                            return [];
                        }
                        break;

                      default:
                        (c = c + 1) + ("a" in {
                            "": (c = 1 + c, (5 && "foo", true ^ 25) - (c = c + 1, -0 % 25)),
                            var: (c = 1 + c, (-4 > /[a2][^e]+$/ != ("number", 2)) - (5 - 2 - (undefined >>> {})))
                        });
                        c = c + 1;
                    }
                }
            }
            if (0 === 1 ? a : b) {
                void function a_2() {
                }();
            } else {
                c = c + 1;
            }
            switch (--b + [ , (c = c + 1) + a--, a++ + (null in {
                b_1: b_1,
                undefined: (c = 1 + c, undefined << "b" || "" & [ 3n ][0] > 2 || 1 ^ -1 ^ "" <= "function")
            }), a++ + 5 ].a) {
              case typeof (typeof f0 == "function" && --_calls_ >= 0 && f0("", --b + (c = c + 1, 
                ("" == "foo") <= (Infinity <= 1)), !((foo += ("c" || "number") % (24..toString() + -4)) > (Number(0xdeadn << 16n | 0xbeefn) > 1 <= (a_2 && (a_2.NaN ^= "bar" >= undefined)))))):
                {
                    var brake83 = 5;
                    do {
                    } while (--b + (typeof f3 == "function" && --_calls_ >= 0 && f3()) && --brake83 > 0);
                }

              case b++:
                if ((c = c + 1) + (typeof f3 == "function" && --_calls_ >= 0 && f3((c = 1 + c, (NaN == 1 & 3 <= -5) != (foo && (foo[-(c = c + 1, 
                ((-42n).toString() & this) + (-3 === "function"))] = "a" > ([ , 0 ].length === 2) & -0 << 22))), (c = 1 + c, 
                (undefined >>> -1) / ({} !== -3) % ((foo = 38..toString() < undefined) << (this >= 2))), ..."" + a_2_2))) {
                    a++ + (foo && typeof foo.NaN == "function" && --_calls_ >= 0 && foo.NaN((c = 1 + c, 
                    (NaN && ({
                        "\t": NaN[c = 1 + c, (("b", 23..toString()) & "foo" >> "bar") !== (-2 & 23..toString()) >> (a_2 = 22 * Number(0xdeadn << 16n | 0xbeefn))]
                    } = {
                        "\t": -0 || this
                    }) || a_1 && (a_1.Infinity = "foo" * 1)) ^ (this ^ "b" | (NaN && (NaN.in += 25 && true)))), (c = 1 + c, 
                    (-0 === 5) > ([ , 0 ][1] >= {}) > ((-5 ^ -1) === "b" - 3)), -4));
                }

              default:
                ;

              case function(bar_2, undefined_1, a_1) {
                    {
                        var a = function f3(b, foo_2) {
                        }();
                    }
                }(--b + ((c = c + 1) + [ (c = 1 + c, !("bar" - -0) | "" + 5 === ([ 3n ][0] > 2 & "foo")), (c = 1 + c, 
                ("function" != "number") >= ("c" === "object") == ~("number" + !0o644n)), (c = 1 + c, 
                b_2 = (false < 3 >= (4 != NaN)) / !(foo && (foo[c = 1 + c, (null != -1 ^ (a_1 && (a_1.NaN += -0 != undefined))) !== ~(false !== "undefined")] = 23..toString() || -1))), (c = 1 + c, 
                c = c + 1, 24..toString() > "c" && 22 * (-42n).toString()), (c = 1 + c, !(([] != 24..toString()) % ("foo" & "c"))) ] || 9).toString()[--b + (foo && foo[c = 1 + c, 
                23..toString() >> null << ([ 3n ][0] > 2 != -0) ^ (b_1 && ({
                    [[].NaN]: b_1[a++ + (NaN += (c = 1 + c, b_1 && (b_1[--b] -= (NaN ^ "foo") >> (5 ^ "number") | "bar" * "function" & (b_1 && (b_1.c = {} + [ , 0 ][1])))))]
                } = {
                    1.5: ("foo" || 2) & ([] && null)
                }))])], "number", a++ + ((c = c + 1, undefined) >>> (-1 && {}) >= ((c = c + 1, {}) | (a_2 <<= (-42n).toString() && -3)))):
                {
                    {
                        return c = 1 + c, (NaN = (a_2_2 && (a_2_2[c = 1 + c, 2 * 25 > -5 * {} || NaN && ({
                            Infinity: NaN[a++ + (-3 in {
                                3: (c = 1 + c, (NaN = ([ , 0 ].length === 2) / "object") / ("bar" / 3) + (1 + [ , 0 ][1] > 38..toString() >> [ , 0 ][1])),
                                "": (c = 1 + c, (23..toString(), 0, 23..toString() || 5) > (a_2_2 && (a_2_2.in |= 22 ** 25 % (-1 >> false)))),
                                [(c = 1 + c, "function" >= "" ^ 5 * 22 | (this >= -2) / (0 > "b"))]: (c = 1 + c, 
                                (Number(0xdeadn << 16n | 0xbeefn) >>> "number" ^ "c" >>> this) < "function" % -3 << (this != (-42n).toString())),
                                ...b_2
                            })]
                        } = {
                            Infinity: false ^ -5 | 1 ^ this
                        })] = [] < 5)) ^ (-5 ^ 2)) * ("a" > 38..toString() >= (-1 || [ 3n ][0] > 2));
                    }
                    c = 1 + c, a_2_2 && (a_2_2.c += (3 == !0o644n) % (24..toString() || "a") & (a_2_2 && ([ a_2_2.null ] = [ true - 5 ])) < ("undefined" ^ "foo"));
                    {
                        return c = 1 + c, (NaN >>> 38..toString()) * (-0 / 2) ^ -5 > false > (Number(0xdeadn << 16n | 0xbeefn) > Number(0xdeadn << 16n | 0xbeefn));
                    }
                    {
                    }
                }
                var b_2 = [ (c = 1 + c, (c = c + 1, 38..toString() / "b") != (([] | 23..toString()) ^ (foo = -0 ^ "object"))), (c = 1 + c, 
                -2 + -0 != (-42n).toString() >= [ , 0 ][1] & (undefined & !0o644n) !== (a_2 && (a_2[c = 1 + c, 
                (c = c + 1, "bar" <= 2) <= ((!0o644n ^ !0o644n) != -true)] = "function" && this))), (c = 1 + c, 
                Number(0xdeadn << 16n | 0xbeefn) >> "c" >>> (NaN_2 *= [ , 0 ][1] << NaN) >>> (null << -4 > (a_1 && (a_1.foo = 0 !== 3)))), (c = 1 + c, 
                (b_2 = {} & "bar") / (-5 == null) >>> (null <= [ , 0 ][1]) * (38..toString() + 38..toString())), (c = 1 + c, 
                ((-5 == Infinity) <= ("foo" !== "c")) >>> ("undefined" >= false !== !0o644n > 5)) ][a++ + (b = a)];
                break;
            }
        }
        {
            var brake95 = 5;
            while (--b + (typeof f5 == "function" && --_calls_ >= 0 && f5()) && --brake95 > 0) {
                return;
                typeof f3 == "function" && --_calls_ >= 0 && f3();
            }
        }
    }
}

console.log(null, a, b, c, Infinity, NaN, undefined);
// uglified code
//
var _calls_=10,a=100,b=10,c=0;function f0(g){var n,t,o=(y<=(2<3n)^25)<(0==[]&1);for(n in o)if(c=1+c,~(((e=o[n])&&(e[g&&"function"==typeof g.c&&0<=--_calls_&&g.c((c=1+c,(2<=(y^38..toString()))<<0))]|=Number(0xdeadn<<16n|0xbeefn)<=5^!1))===this%23..toString()<<!1))switch(e&&e.length){case--b+(b=a):for(t in(c+=1)+(""in[(c+=1)+("number"==typeof bar),g,[(c=1+c,(("b"<=38..toString())<<0)-(2===[,0].length)),(c=1+c,[]%y>>(-66<<(0!=={}))),(c=1+(c+=1),e&&(e[a+++ +function n(){c=1+c,n&&(n[!(0<{}-1/0&""!=(-3^[]))]|=(n/!0>=-3+38..toString())-(n&&(n[n&&n.null]+=(n&&(n[c=1+c,(("bar"!=this)<1)/("function"<!0o644n|!1)]=NaN))/(2===[,0].length^{})))),c=1+c,c+=1,n&&(n.NaN=y- -5),c=1+(c=1+c),(-42n).toString(),Number(0xdeadn<<16n|0xbeefn)}()]*=0%(Number(0xdeadn<<16n|0xbeefn)+/[a2][^e]+$/)>>(0&("number"|38..toString())))),(c=1+c,(25^23..toString())&(!0o644n^Number(0xdeadn<<16n|0xbeefn))^(e&&(e["c"in[(c=1+c,((y||-2)^(e&&(e[c=1+c,0<(c+=1,4)!==(38..toString()>>-5&-5)]-=-5==38..toString())))<<((e&&([e[c=1+c,!0o644n-5<=!1<NaN**(!0o644n%"bar")]]=[NaN]))<<(g&&(g[c=1+c,(e&&([e.NaN]=[-100!=("function"!=this)]))<=0%[]-("a"<<(2<3n))]<<=NaN)))),(c=1+c,g&&(g[b++]+=(3===(2===[,0].length))<(this<="b")==23)),(c=1+c,(0&(e=0))<(e=(-1&24..toString())<0<<y)),(c=1+c,0!=0),(c=1+(c+=1),!0-(-4==(c+=1,0)))]]=0)))][[(c=1+c,(g&&(g.c=(-2^38..toString())<0))+!1),(c=1+c,!0o644n>>>"foo"|-2^Number(0xdeadn<<16n|0xbeefn)&&g&&(g[(c+=1)+((38..toString()>=[])/(-1<y)^2<3n<"number")]&=NaN)),!1-0/(2<3n<=2),(c=1+(c=1+c),e&&(e.a+={}%-0%(g&&(g[c=1+c,-3<<("undefined"|2<3n)]+=void 0^23..toString()))-(1|23..toString())))][c=1+c,NaN&(e=(24..toString()||[])%!0)]],"object"!=typeof g]))if(--b+{}){c+=1;for(var i=5;c=1+c,g="function"^(c+=1,"object"),c=1+c,-5<(-42n).toString()&0^(g%=!0)&&0<--i;);}var e=--b+("function"==typeof f0&&0<=--_calls_&&f0(a+++(e&&e.null),24..toString()));break;case--b:break;case(c+=1)+(e&&"function"==typeof e.length&&0<=--_calls_&&e.length(((c+=1)+(e=(c+=1)+((0==(e&&(e[c=1+c,(-1>>>(-42n).toString()>!0o644n/-5)-1.25]&=NaN)))>>>(!1>>>null*this)))||5).toString().null,"bar",23..toString())):if(--b+/[abc4]/g.exec(((--b+[(c=1+c,(2<3n==24..toString())/0>>>NaN%(-2>>[])),(c=1+c,NaN<=((e&&(e[c=1+c,("a"<=(2<3n)^{}-null)<=0]="c"==23..toString()))==1/0>>>38..toString()))].NaN?--b+("undefined"in[(c=1+c,(-2==2<3n)<("object"!=!0o644n)<=(e&&(e[a]=(c+=1,25>>(e&&(e.NaN="b")))))),(c=1+c,({}+"foo")/!0<<(38..toString()!=={}===-0-{})),(c=1+c,5/-4<=(-1^y|0))]):--b)||b||5).toString()))return b^=a;c=1+c}for(var r=(p=!function n(){switch(a+++(b=a)){default:case c=1+c,o=(this&[])/(0!=24..toString())|5>>((2===[,0].length)>>3),i=1+(i=1+i),24..toString(),i=1+i,i+=1,o&&(o.c+=-4),void 23..toString():break;case c+=1,g&&(g.var|=!1),!0:var t=(c=1+c,!1<=(-3!==38..toString()!=0));break;case g|={foo:(c=1+c,1!==(2===[,0].length==="foo")===(g&&({[n.a]:g.in}={0:(1/0!==(2===[,0].length))>>>(g&&(g.null+=Number(0xdeadn<<16n|0xbeefn)==y))}))),b:(c=1+c,38..toString(),(g=[])<=(2<3n)%Number(0xdeadn<<16n|0xbeefn)|void 0*[]===y),"-2":(c=1+c,NaN<=("number"&y)|(25!=38..toString())>(t&&({b:t[c=1+c,void 0<<23..toString()&!0o644n<<Number(0xdeadn<<16n|0xbeefn)||-1^-1<38..toString()]}={b:24}))),"-2":(c=1+c,y>38..toString()||this>=38..toString()||[]^24..toString()^!1)}.null:}var o,i,e;for(e in--b,(a++||9).toString()[(c+=1)+t],a+++("function"==typeof f2&&0<=--_calls_&&f2((c=1+c,void 38..toString()>=(t=NaN)),!1,(c=1+(c+=1),c+=1,24..toString()*(+{}&&y%"function"))))){var r=5;do{for(var f=5;c=1+c,void 0<(2<3n)/-1^("function"!=this||""<y)&&0<f;--f)c=1+c,Number(0xdeadn<<16n|0xbeefn),Number(0xdeadn<<16n|0xbeefn)}while(a+++a&&0<--r)}}(),void w(0,--b+(0<=--_calls_&&w(c=1+c)),(--b,p&&"function"==typeof p.var&&0<=--_calls_&&p.var((c=1+c,"-4function"*("number"&2<3n)==(0!=[]<-0)),/[a2][^e]+$/,"a")))),f=5;--b+("function"==typeof f2&&0<=--_calls_&&f2(23..toString(),!1))&&0<--f;)var l=a+++("function"==typeof S&&0<=--_calls_&&S(1)),S=((c+=1)+[][{"-2":typeof arguments,in:a+++(Number(0xdeadn<<16n|0xbeefn)in{NaN:(c=1+c,(e=0)*(2<3n|!0)%([]*{}>>>(r&&(r.foo>>>=25===24..toString())))),foo:(c=1+c,(r&&(r[a+++(c=1+c,{}*(0/(-4+[])))]<<=(5===y)<!0))|1/0!=5*23..toString()),"-2":(c=1+c,.6*(Number(0xdeadn<<16n|0xbeefn)<=38..toString())!=-5*y>>>"bar1"),undefined:(!0o644n<<!0o644n!=(r>>>=NaN))>=(0!=""<<(2===[,0].length))}),"-2":[void(S+=!1),(c=1+(c=1+(c=1+c)),c+=1,g&&([g[e&&"function"==typeof e.var&&0<=--_calls_&&e.var((c=1+c,!1-((y&&2<3n)!==(e=-5>>>5))))]]=[5^(e&&(e[c=1+c,("a"===38..toString())>>>(1!=24..toString())^(0>>>23..toString()||-26)]=4>>>23..toString()))])),(c=1+c,y!=(2===[,0].length)^!0&&(r&&(r.a/=-1/0))^-4+!0o644n)]}]);switch(b++){default:for(var N=5;c=1+c,r&&(r[(c+=1)+(c=1+c,l&&(l[a+++l]=!0^-3!=y&"foonumber"),e+=0,c=1+(1+c),void(c+=1))]=0==(0==3<=Number(0xdeadn<<16n|0xbeefn))),c=1+c,e&&(e[l&&l[void 0]]+=(!0|!0o644n<<23..toString())%(2===[,0].length&&5>>>y)),c=1+c,(-42n).toString(),{"\t":(c=1+c,S&&(S.undefined=(c+=1,38..toString()*(2!==2<3n)>=(r&&(r[--b+(-5 in[])]+=(2===[,0].length)-"b"+(0^[])))))),"-2":(c=1+c,!0),c:(c=1+c,2>>(NaN>>38..toString()))}[a+++((!0>>>{}^5^(-42n).toString())>=(this||24..toString())%(c+=1,2))]&&0<--N;);var u=--b+("function"==typeof f0&&0<=--_calls_&&f0("b",(c=1+c,0^(e=(r&&(r[c=1+c,((S=0)^"function"==(2===[,0].length))<=!1]=y%!0o644n))&24..toString()- -4)),25));case"function"==typeof S&&0<=--_calls_&&S(--b+(b+=a)):break;case"function"==typeof f2&&0<=--_calls_&&f2(-4):switch([{}+"foo"<<!this<=(u<<=0)].null){case[(c=1+(c=1+c),("c"!==23..toString())-(e&&(e.NaN+=NaN))<=((-42n).toString()<={})**!0)][/[abc4]/g.exec((c=1+c,(e&&(e["function"==typeof r]+=4*Number(0xdeadn<<16n|0xbeefn)*(c+=1,2===[,0].length)/("c"*{}+!0))||b||5).toString()))]:break;default:switch(c=1+c,c+=1,-4<=(u&&(u[c=1+c,S=(2===[,0].length)<""||!0+(1/0===(-42n).toString())]*=1/0-{}))!=("function"-[]|0)?(c=1+c,e&&(e.foo+=0==((g+=-3>>>"c")^23..toString()%22))):c=1+c,c=1+c,u?u.Infinity=-4:1===(u&&(u.a*="bar"))){case c=1+c,(/[a2][^e]+$/>24..toString())-+24..toString()|!0:case c=1+c,-4<("number"<=y):case c=1+c,(e&&(e.NaN=!0))!=(2===[,0].length)/"bar"&0:case c=1+c,u&&(u[--b+(u&&"function"==typeof u.c&&0<=--_calls_&&u.c(...""+u))]|=!0&(c+=1,e&&(e.null+=!0))):}case a+++g:c+=1;case{foo:l,[(c=1+c,(4|[])+void 0*24..toString()<"-2foo")]:(c=1+c,l&&(l[(c+=1)+a]+=(!0!==(2<3n&22))>(Number(0xdeadn<<16n|0xbeefn)|(-42n).toString())/30)),length:!1|NaN==(g=NaN)}[c=1+(c=1+c),("b"^[])<=NaN<=(r&&(r[a--]=!1===38..toString()/-4))]:for(var d=5;c=1+c,c=1+c,(!1|5&Number(0xdeadn<<16n|0xbeefn))-!1&&0<--d;);}var s=5;do{var h,x=++b;for(h in x)c=1+(c=1+c),38..toString()}while(a+++(/[a2][^e]+$/*(-42n).toString()+(this<"a"))/(23..toString()-y>>>(c+=1,"bar"))&&0<--s);break;case l&&"function"==typeof l.in&&0<=--_calls_&&l.in(2===[,0].length,...""+r):c+=1}var _,v=b<<=a;for({length:_}in v){c=1+c;var y=v[_];switch([u&&u[c=1+c,("bar"==={}||!0o644n-void 0)/((S&&(S.NaN="bar"<[]))<(22<{}))],a+++(c=1+c,(25^y||22<(this===[])||a||3).toString())][a+++[(c=1+c,c+=1,0<=("object"<23..toString())),(c=1+c,g=!0)][a+++--b]]){case(c+=1)+(!0 in{}):case--b:break;case u:try{return c=1+c,!0*(u&&(u[--b+(c=1+c,typeof+((S=(-42n).toString()-!0o644n)-NaN))]-=("c"==Number(0xdeadn<<16n|0xbeefn))-("bar"!==38..toString())))}catch{c=1+c,(-42n).toString(),e&&(e.b&=4),c=1+c,g&&(g.b=((!0o644n^"")<=!1)*(([]^/[a2][^e]+$/)>>0))}finally{c=1+c,(2===[,0].length)<<(-42n).toString()|-1===[]&&24..toString(),c=1+c,l&&(l.a+=!1)}return[];default:c=1+(c+=1),c=1+(c+=1),c+=1}}switch(b||(c+=1),--b+[,(c+=1)+a--,a+++(null in{b_1:g,undefined:(c=1+c,""&2<3n||-1)}),5+a++].a){case typeof("function"==typeof f0&&0<=--_calls_&&f0("",--b+(c+=1,!0),!((l+="c"%(24..toString()+-4))>(1<Number(0xdeadn<<16n|0xbeefn)<=(e&&(e.NaN^=!1)))))):for(var m=5;--b+("function"==typeof f3&&0<=--_calls_&&f3())&&0<--m;);case b++:(c+=1)+("function"==typeof f3&&0<=--_calls_&&f3((c=1+c,(1==y&!1)!=(l&&(l[c+=1,-(((-42n).toString()&this)+!1)]=(2===[,0].length)<"a"&0))),(c=1+c,0/(-3!=={})%((l=38..toString()<void 0)<<(2<=this))),...""+u))&&(a++,l&&"function"==typeof l.NaN&&0<=--_calls_&&l.NaN((c=1+c,(y?({"\t":y[c=1+c,(0&23..toString())!=(-2&23..toString())>>(e=22*Number(0xdeadn<<16n|0xbeefn))]}={"\t":this}):r&&(r.Infinity=NaN))^("b"^this|(y&&(y.in+=!0)))),(c=1+c,!1<({}<=0<!1)),-4));default:case--b,((c+=1)+[!0|"5"===(2<3n&"foo"),1==~("number"+!0o644n),(c=1+(c=1+(c=1+c)),S=((4!=y)<=!0)/!(l&&(l[c=1+c,-2!=(!0^(r&&(r.NaN+=!0)))]=23..toString()||-1))),(c=1+c,c+=1,"c"<24..toString()&&22*(-42n).toString()),(c=1+c,!(([]!=24..toString())%0))]||9).toString()[--b+(l&&l[c=1+c,23..toString()>>null<<(2<3n!=-0)^(g&&({[[].NaN]:g[a+++(y+=(c=1+c,g&&(g[--b]-=("foo"^y)>>5|NaN&(g&&(g.c={}+0)))))]}={1.5:0}))])],a++,c+=1,c+=1,void(e<<=(-42n).toString()&&-3):return c=1+c,(y=-7^(u&&(u[c=1+c,-5*{}<50||y&&({Infinity:y[a+++(-3 in{3:(c=1+c,(y=(2===[,0].length)/"object")/NaN+(38..toString()>>0<1)),"":(c=1+c,23..toString(),(23..toString()||5)>(u&&(u.in|=0))),[(c=1+c,111|(-2<=this)/!1)]:(c=1+c,(Number(0xdeadn<<16n|0xbeefn)>>>"number"^"c">>>this)<NaN<<(this!=(-42n).toString())),...S})]}={Infinity:-5|1^this})]=[]<5)))*(-1<=(38..toString()<"a"))}var p,p=5;if(!(--b+("function"==typeof f5&&0<=--_calls_&&f5())&&0<--p))async function w(n,t){for(var o=5;c=1+c,g=-2<=y^(c+=1,3),23..toString(),c=1+c,(t+=1>>>(c+=1,!0))&&0<--o;);c=1+c,!0+("bar">>>(-42n).toString())<=-5*(25&2===[,0].length)&&(c=1+c,38..toString())}}console.log(null,a,b,c,1/0,NaN,void 0);
original result:
null 100 10 0 Infinity NaN undefined

uglified result:
SyntaxError: Async functions can only be declared at the top level or inside a block.
    at new Script (node:vm:102:7)
    at createScript (node:vm:263:10)
    at Object.runInThisContext (node:vm:311:10)
    at node:internal/process/execution:77:19
    at [stdin]-wrapper:6:22
    at evalScript (node:internal/process/execution:76:60)
    at node:internal/main/eval_stdin:29:5
    at Socket.<anonymous> (node:internal/process/execution:205:5)
    at Socket.emit (node:events:391:22)
    at endReadableNT (node:internal/streams/readable:1307:12)
// reduced test case (output will differ)

// (beautified)
function f0() {
    {
        (function f1() {
            async function f2() {}
            f2 && f2();
        })();
        while (brake95) {
            return;
        }
    }
}
// output: 
// minify: SyntaxError: Async functions can only be declared at the top level or inside a block.
// options: {
//   "output": {
//     "v8": true
//   },
//   "validate": true
// }
minify(options):
{
  "output": {
    "v8": true
  }
}

Suspicious compress options:
  dead_code
  if_return
  inline
  loops
  unused

Suspicious options:
  rename
@alexlamsl alexlamsl added the bug label Jan 30, 2021
@alexlamsl
Copy link
Collaborator Author

@kzc another day, another spec quirk...

$ echo 'if (f) function f() {}' | node

$ echo 'if (f) async function f() {}' | node
[stdin]:1
if (f) async function f() {}
       ^^^^^

SyntaxError: Async functions can only be declared at the top level or inside a block.
    at createScript (vm.js:80:10)

alexlamsl added a commit to alexlamsl/UglifyJS that referenced this issue Jan 30, 2021
@kzc
Copy link
Contributor

kzc commented Jan 30, 2021

This is a case where the spec makes sense.

@alexlamsl
Copy link
Collaborator Author

In what way? All I see is yet another instance of disregard for consistency and compatibility.

alexlamsl added a commit that referenced this issue Jan 30, 2021
@kzc
Copy link
Contributor

kzc commented Jan 30, 2021

I thought a scoped declaration in a blockless if body by definition cannot be used...

$ echo 'if(1) let x = 2;' | acorn --ecma2020 --silent && ok
Unexpected token (1:10)

$ echo 'if(1){let x = 2;}' | acorn --ecma2020 --silent && echo ok
ok

But traditional function declarations are grandfathered due to ES3:

$ echo 'if (1) function f(){console.log("PASS")} f();' | node-v0.10.41 
PASS

$ echo 'if (1) function f(){console.log("PASS")} f();' | node-v14.3.0 
PASS

I suppose there's a case for consistency, but I think they were trying to correct an historical oversight.

@kzc
Copy link
Contributor

kzc commented Jan 30, 2021

But they did correct this mistake apparently...

$ echo 'f(); if (1) function f(){console.log("PASS")}' | node-v0.10.41 
PASS
$ echo 'f(); if (1) function f(){console.log("PASS")}' | node-v4.2.1 
PASS
$ echo 'f(); if (1) function f(){console.log("PASS")}' | node-v6.9.0 
[stdin]:1
f(); if (1) function f(){console.log("PASS")}
^
TypeError: f is not a function
$ echo 'f(); if (1) function f(){console.log("PASS")}' | node-v14.3.0 
[stdin]:1
f(); if (1) function f(){console.log("PASS")}
^
TypeError: f is not a function

@kzc
Copy link
Contributor

kzc commented Jan 30, 2021

You can see that the decl is no longer function scoped in recent V8 engines:

$ echo 'if (0) function f(){console.log("PASS")} f();' | node-v0.10.41 
PASS
$ echo 'if (0) function f(){console.log("PASS")} f();' | node-v0.12.9 
PASS
$ echo 'if (0) function f(){console.log("PASS")} f();' | node-v4.2.1 
PASS
$ echo 'if (0) function f(){console.log("PASS")} f();' | node-v6.9.0 
[stdin]:1
if (0) function f(){console.log("PASS")} f();
                                         ^
TypeError: f is not a function

@alexlamsl
Copy link
Collaborator Author

Thanks for confirming my suspicions 😅

Those subsequent deviation from JavaScript is why I mentioned "disregard for compatibility" earlier.

To summarise − they poked a hole, fell into it, then decided the best course of action is the keep digging.

Good times.

@kzc
Copy link
Contributor

kzc commented Jan 30, 2021

That may be true, but the latest JS engines converged on a new set of scoping rules that uglify-js is not entirely compatible with:

$ echo 'if(0)function f(){console.log(0)}try{f()}catch(x){console.log(1)}' | node-v14.3.0 
1

$ echo 'if(0)function f(){console.log(0)}try{f()}catch(x){console.log(1)}' | uglify-js -c | node-v14.3.0 
0

$ echo 'if(0){function f(){console.log(0)}}try{f()}catch(x){console.log(1)}' | uglify-js -c
function f(){console.log(0)}try{f()}catch(x){console.log(1)}

An ecma option could be used to produce different output depending on the version.

@alexlamsl
Copy link
Collaborator Author

I'm very much against fragmenting uglify-js just to accommodate for their deficiencies − I'd rather find a unified behaviour to handle ECMAScript quirks like we did with const et. al.

In this particular case, I'm currently leaning towards the fact that people almost never wrap AST_Defun in block scopes like that IRL, so supporting propert JavaScript behaviour is sufficient for the moment.

@kzc
Copy link
Contributor

kzc commented Jan 30, 2021

Not sure what "proper JavaScript behavior" means. It's an evolving standard. No browser built in the last few years supports ES5 scoping rules. I don't see a way to support old scoping rules and modern scoping rules without an ecma option of some sort - they are fundamentally incompatible.

@alexlamsl
Copy link
Collaborator Author

If you mean runtime behaviour, yes − but don't forget we aren't evaluating the input code most of the time.

Just see how we currently handle const which works for both before and after the redefinition in the specifications without any ecma switch.

@alexlamsl
Copy link
Collaborator Author

alexlamsl commented Jan 30, 2021

No browser built in the last few years supports ES5 scoping rules.

There are browsers built in the last few years, and then there are ones that people actually use. They are not necessaily correlated, especially when the former keeps evolving away useful features & functional behaviours... 😏

@kzc
Copy link
Contributor

kzc commented Jan 30, 2021

How do you propose to handle minification of cases like #4598 (comment) so they work in both old ES5 browsers and in modern ES6+ browsers when they produce different output? Leave the AST as is? An ecma option would be a lot easier.

@alexlamsl
Copy link
Collaborator Author

I think we are considering this from different angles − you see it as each code paths being simpler, whereas I see the permutations of code paths is now multiplied by at least a factor of two.

@kzc
Copy link
Contributor

kzc commented Jan 30, 2021

If the ecma target is unknown then you cannot drop unused code in certain cases.

Hypothetical example:

$ echo 'if(0)function f(){console.log(0)}try{f()}catch(x){console.log(1)}' | uglify-js --ecma 6 -c
try{f()}catch(x){console.log(1)}
$ echo 'if(0)function f(){console.log(0)}try{f()}catch(x){console.log(1)}' | uglify-js --ecma 5 -c
function f(){console.log(0)}try{f()}catch(x){console.log(1)}

@alexlamsl
Copy link
Collaborator Author

Ultimately if we want to support the broken behaviour in ECMAScript, we'll do it just like how we handle const − so yes that would mean preserving AST_BlockStatement in certain cases.

However, there is also the function variable not being assigned until executed over − except if you are within the same block scope in which case it behaves just as expected before.

The latest ECMAScript is very broken − they've made AST_Defun behave differently to both var and let.

@alexlamsl
Copy link
Collaborator Author

The reason why this has not been worked on is a pragmatic one − a lot of the existing code will need to be modified (introducing a new flag would be way worse in terms of code churn), and it's not something that we've encountered in the wild.

If you want to have a go at it, be my guest − but it really is messy. I'd know since I tried that for uglify-es − even without concern for JavsScript compatibility, I couldn't come up with a bug-free patch.

@kzc
Copy link
Contributor

kzc commented Jan 31, 2021

These edge cases are indeed rare. It was not intended as a criticism. I was just arguing for whatever behavior the majority of browsers in use support. Whether you choose to implement it is entirely your call. I'm out of the minification game. Just an armchair spectator now.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants