Repository: mishoo/UglifyJS (JavaScript)

Issue:
ufuzz failure
```js
// original code
// (beautified)
var _calls_ = 10, a = 100, b = 10, c = 0;

function f0(async, arguments) {
    try {
        try {
            {
                var a_2 = async function f1(parseInt, Math, Math_2) {
                    return Math_2 = Math_2 += 0 === 1 ? a : b;
                    if (Math_2 && typeof Math_2.Infinity == "function" && --_calls_ >= 0 && Math_2.Infinity((c = c + 1) + true, -4, (c = c + 1) + (Math_2 ^= (c = 1 + c, 
                    (-38..toString() !== (Math_2 = {} || undefined)) >= ("a" % /[a2][^e]+$/ | (Math_2 && ({
                        in: Math_2[c = 1 + c, ((2 & -5) >= ([ , 0 ].length === 2) - "b") >>> (c = c + 1, 
                        "undefined" <= "object")]
                    } = {
                        in: "bar" >> 25
                    }))))))) {
                        var bar_1 = a++ + {
                            [(c = 1 + c, ("undefined" >= "number" | 2 >> -3) == ([ , 0 ][1] >= "b") / (NaN && "a"))]: (c = 1 + c, 
                            Math_2 && (Math_2[(c = c + 1) + {
                                "\t": (c = 1 + c, (bar_1 && (bar_1[--b + ((c = 1 + c, bar_1 && (bar_1.in = (38..toString() ^ 23..toString() | 22 << 22) >= (void NaN | "undefined" * 23..toString()))) ? (c = 1 + c, 
                                ((/[a2][^e]+$/ !== -0) > (Math_2 && (Math_2.null += "foo" >>> -0))) % ("function" / "b" & -0 >> undefined)) : (c = 1 + c, 
                                (4 + -2, 25 ^ "object") != NaN >> /[a2][^e]+$/ >= (null < "foo")))] <<= (false != 4) / (5 == ""))) % (5 ^ "function" | (undefined, 
                                NaN))),
                                1.5: (c = 1 + c, (bar_1 && (bar_1[{
                                    "-2": (c = 1 + c, ((NaN !== 5) <= this * /[a2][^e]+$/) + ("c" === 4 | ("bar" || "foo"))),
                                    3: (c = 1 + c, ("function" ^ null) != (-0 ^ "foo") ^ (23..toString() * -2 ^ (undefined ^ {}))),
                                    length: (c = 1 + c, ({} | [ , 0 ][1] || 5 + NaN) - (24..toString() >> 4 >> "bar" + -0)),
                                    ...bar_1,
                                    length: (c = 1 + c, 0 >>> -0 != ([ , 0 ].length === 2 !== "a") & (2 >>> NaN) + delete NaN)
                                }.foo] += this <= Infinity > true - this)) & (this >= {}) >> (true == "b")),
                                [(c = 1 + c, ((c = c + 1, 22) ^ ("object" ^ -4)) % ((2 == -0) / (23..toString() / "function")))]: (c = 1 + c, 
                                ("c" % this ^ (bar_1 && ([ bar_1[c = 1 + c, (5 ^ 5) >> (-1 < undefined) === ("object" !== null != (this == -3))] ] = [ "a" < 2 ]))) / (bar_1 && (bar_1[(c = c + 1) + [ (c = 1 + c, 
                                (this == "undefined" & "c" << undefined) * (25 >>> 3 >> - -2)) ].foo] = delete "a" << (bar_1[c = 1 + c, 
                                delete (([ , 0 ][1] !== 5) << (-5 > "function"))] >>= -2 + null))))
                            }[c = 1 + c, (bar_1 && (bar_1[typeof (c = 1 + c, (!5, -0 << {}) * ("a" <= Infinity < ("bar" >= NaN)))] = ([ , 0 ].length === 2) >> "undefined" < ("function" >= 5))) > ((Math_2 += -5 >>> 22) === (-0 !== "object"))]] = {} > "c" != "bar" + {}), 
                            "b" / undefined | (1 | 24..toString())),
                            Math_2: Math_2
                        }[bar_1 && bar_1[c = 1 + c, 3 >= "bar" !== [ , 0 ][1] % {} !== ((2, "number") === (false !== Infinity))]], foo = 1 === 1 ? a : b, Math = (c = c + 1) + -3;
                    } else {}
                }("undefined", a++ + (typeof a_2.undefined == "function" && --_calls_ >= 0 && a_2.undefined("a")));
            }
        } catch (Math_2) {
            return /[abc4]/.test((a++ + ((b = a) || a || 3).toString() || b || 5).toString());
            return --b + {
                NaN: {
                    NaN: a++ + (Math_2 && typeof Math_2.a == "function" && --_calls_ >= 0 && Math_2.a(-2, 4, undefined)),
                    Math_2: Math_2,
                    null: {}
                }[((a_2 && (a_2[c = 1 + c, ((c = c + 1, 4) != ("undefined" ^ null)) * ((Math_2 && ({
                    Infinity: Math_2.null
                } = {
                    Infinity: "object" % NaN
                })) != (undefined ^ "c"))] += NaN <= "")) << NaN * 24..toString()) - (c = c + 1, 
                25 | "b")],
                [b + 1 - .1 - .1 - .1]: function(bar_2, foo_1) {
                    switch (--b + [ , (c = 1 + c, (-1 >= "a") / (foo_1 = "" + 23..toString()) >= (a_2 && (a_2.Infinity = "c" << /[a2][^e]+$/ ^ Infinity == "object"))), , (c = 1 + c, 
                    (("object" ^ -1) === (c = c + 1, 23..toString())) << ((1 && -3) > ("number" !== ([ , 0 ].length === 2)))) ][c = 1 + c, 
                    (foo_1 && (foo_1[c = 1 + c, ("foo" ^ 25 ^ ([ , 0 ][1] ^ 4)) & (24..toString() < [ , 0 ][1] && "" / "")] %= -3 || this)) >> ("number" >= {}) != (c = c + 1, 
                    "undefined" - [ , 0 ][1])]) {
                      case --b + ~(5 >> 22 ^ (2 ^ -0) || -1 * -5 & "object" % NaN):
                        c = 1 + c, (38..toString() > 23..toString() !== true + 38..toString()) + (3 >>> Infinity) * ("a" == "bar");
                        break;

                      case a_2 && typeof a_2.a == "function" && --_calls_ >= 0 && a_2.a((c = 1 + c, "a" << 22 != (4 == "foo") !== 23..toString() + "number" >= (2 ^ [ , 0 ][1])), undefined, (c = 1 + c, 
                        ((1 == 38..toString()) >= NaN + -1) - (this >> 5 >> (foo_1 && ({
                            "": foo_1[c = 1 + c, Math_2 = -5 === 38..toString() != (Math_2 += 3 & "function") !== (this ^ -4) * ("bar" ^ 4)]
                        } = {
                            "": 2 != 25
                        }))))):
                        break;

                      default:
                        c = 1 + c, (3 ^ "a" | (c = c + 1, "bar")) >= (true - undefined) / (24..toString(), 
                        25);
                        c = 1 + c, (0 <= true != "function" * 1) >>> void (3 < 0);

                      case --b + ({} in [ (c = 1 + c, ((bar_2 && ({
                            NaN: bar_2.b
                        } = {
                            NaN: this << "object"
                        })) & 1 >> -4) >>> (Math_2 |= (0 !== "function", 24..toString() === NaN))) ]):
                        break;
                    }
                    if (--b + (bar_2 && typeof bar_2.undefined == "function" && --_calls_ >= 0 && bar_2.undefined(2))) {
                        if (c = 1 + c, !("foo" + -2 & 2 > -3)) {
                            c = 1 + c, (c = c + 1, foo_1 && ({
                                c: foo_1.Infinity
                            } = {
                                c: "function" << this
                            })) === (this === [] === (-3 == "function"));
                        }
                    }
                }
            }[--b + new function(foo_2, bar) {
                NaN;
                if (typeof a_2 == "function" && --_calls_ >= 0 && a_2()) {
                    var expr19 = (c = 1 + c, (foo_2 += (NaN * "function", foo_2 && (foo_2[c = 1 + c, 
                    ("function" || "c") << (-0 < undefined) ^ (3 == /[a2][^e]+$/, 4 && 2)] = -3 % null))) <= (0 && this) >> Infinity / "foo");
                    for (var key19 in expr19) {
                        c = 1 + c;
                        var bar = expr19[key19];
                        c = 1 + c, (c = c + 1, -3 << "bar") * (foo_2 && (foo_2[--b + {
                            ...Math_2,
                            [(c = 1 + c, (-1 < /[a2][^e]+$/) >> 23..toString() * "foo" || (c = c + 1, 3 & Infinity))]: (c = 1 + c, 
                            (([ , 0 ].length === 2) << 1) - 2 / undefined >> ((a_2 |= /[a2][^e]+$/ % 25) >= (c = c + 1, 
                            -3))),
                            1.5: (c = 1 + c, +38..toString() % ("foo" / "a") / (([ , 0 ].length === 2 && {}) >= 3 * -4)),
                            "": (c = 1 + c, (-3 || -2) << (true != ([ , 0 ].length === 2)) ^ (this & "object") * ("a" <= this))
                        }.foo] %= ("foo" & "foo") * (-5 != -0)));
                    }
                } else {
                    var expr21 = (c = 1 + c, (23..toString() !== -0) << ([ , 0 ][1] || "number") | (c = c + 1, 
                    foo_2 = 23..toString() & -5));
                    for (var key21 in expr21) {
                        c = 1 + c;
                        var b = expr21[key21];
                        c = 1 + c, (4 < []) >>> 23..toString() % /[a2][^e]+$/ | {} > {} !== (0 & Infinity);
                    }
                }
            }(2)];
        } finally {
            {
                var brake23 = 5;
                do {
                    for (var brake24 = 5; (a_2 /= typeof f2 == "function" && --_calls_ >= 0 && f2("undefined", "b", function foo_1() {
                    }())) && brake24 > 0; --brake24) {}
                } while (+a && --brake23 > 0);
            }
            c = c + 1;
        }
    } finally {
        switch ((c = c + 1) + typeof (--b + (a_2 && a_2[a++ + (a++ + {
            a_2: a_2,
            length: typeof a_2 == "function" && --_calls_ >= 0 && a_2((c = 1 + c, a_2 = ((-0 && -5) % ("b" ^ 22), 
            5 >>> null > (2 !== 25))), [])
        }.length ? --b + {
            a_2: a_2,
            "-2": --b + (23..toString() in {
                length: (c = 1 + c, "foo" - "a" >> undefined * "function" || (c = c + 1, NaN >> 0)),
                c: (c = 1 + c, "bar" * "number" / (c = c + 1, "object"), (25 === "a") < (a_2 = 25 == 4)),
                NaN: (c = 1 + c, a_2 && (a_2.undefined ^= (23..toString() % [] === 25 % -3) <= (2 / true != "b" - 5)))
            }),
            in: {
                foo: (c = 1 + c, ("a" !== -2 | 2 & {}) ^ void (c = c + 1, -3)),
                [(c = 1 + c, -5 + null >= (24..toString() > false) || (24..toString() === 22) << (true == false))]: (c = 1 + c, 
                ((a_2 && (a_2[c = 1 + c, a_2 && (a_2[(c = c + 1) + [ (c = 1 + c, (1 ^ 22) % ("bar" | false) || undefined * Infinity / ("a" > "b")), , (c = 1 + c, 
                {} % 38..toString() + (true < false) > (NaN < 5) >> (24..toString() !== "function")), ..."" + a_2, (c = 1 + c, 
                (23..toString() || /[a2][^e]+$/ || false !== 2) !== ("b" | 22) * (false === "number")) ]] += ((25 ^ [ , 0 ][1]) !== (null === [])) * ((-4, 
                23..toString()) === (a_2 && (a_2[c = 1 + c, (c = c + 1, [] & 23..toString()) << ("foo" ^ 23..toString() ^ +2)] -= false + Infinity))))] = 2 == 3)) << (23..toString() >>> "foo")) - (false % 22 || 38..toString() && 3)),
                [(c = 1 + c, delete ("" - "c" ^ 3 != 38..toString()))]: (c = 1 + c, "object" + 38..toString() >> (23..toString() != "number") > ((-0 | 22) ^ "bar" !== "b"))
            },
            var: --b + ((c = 1 + c, (c = c + 1, "c", 23..toString()) == (2 === 38..toString(), 
            -3 >>> {})) ? (c = 1 + c, (0 >> "b" && "foo" % [ , 0 ][1]) ^ (a_2 && (a_2[function() {
            }] = false >= -1 ^ -2 * /[a2][^e]+$/))) : (c = 1 + c, (a_2 |= +NaN !== (false | NaN)) != (a_2 = ~NaN / ("c" >>> /[a2][^e]+$/)))),
            [--b + /[abc4]/g.exec(((c = 1 + c, c = c + 1, (undefined != -0) - (22 < [])) || b || 5).toString())]: a++ + (b = a)
        } : a++ + (a_2 && typeof a_2.length == "function" && --_calls_ >= 0 && a_2.length(--b + (b += a), "number", -2)))]))) {
          case --b + a_2:
            0 === 1 ? a : b;
            {
                var brake29 = 5;
                L35515: do {
                    var a_2_1 = "undefined";
                } while (a++ + a_2 && --brake29 > 0);
            }
            break;

          case a_2_1:
          case --b + ~((a_2 && (a_2[a++ + (a_2 && a_2[c = 1 + c, 23..toString() * -3 < (1 < 22) | ("b" >= "undefined") * (25 || 23..toString())])] = /[a2][^e]+$/ >>> -0 << (a_2 && (a_2[c = 1 + c, 
            2 == "bar" != (NaN === false) | ("c" | "a") == ([ , 0 ][1] ^ /[a2][^e]+$/)] = "b" ^ "object")))) + ([ , 0 ][1] << 22 >= (-5 & -3))):
            L35516: for (var brake31 = 5; a_2 && typeof a_2.NaN == "function" && --_calls_ >= 0 && a_2.NaN() && brake31 > 0; --brake31) {
                [].foo;
            }
            ;
            break;

          case a_2_1:
            for (var brake34 = 5; typeof a_2_1 == "function" && --_calls_ >= 0 && a_2_1((c = c + 1) + (typeof f1 == "function" && --_calls_ >= 0 && f1((c = 1 + c, 
            -5 > this < ({} ^ "bar") ^ "" % [] * (c = c + 1, "number")), (c = 1 + c, a_2 = (a_2 = ("c" <= this) << -4 / "number") === (null ^ -3) < ("b" != NaN)))), ("" in {} || 3).toString()[a--], --b + (a_2_1 && typeof a_2_1.var == "function" && --_calls_ >= 0 && a_2_1.var((c = 1 + c, 
            (1 || "object") ^ delete -0 | -3 > "bar" != (a_2_1 && (a_2_1.a >>= "number" | "number"))), (c = 1 + c, 
            (c = c + 1, NaN + "undefined") >= (4 != this) << ("b" === 25)), (c = 1 + c, 4 << ([ , 0 ].length === 2) != 25 % "" ^ false - true << (null && 24..toString()))))) && brake34 > 0; --brake34) {
                switch ((c = c + 1) + a_2) {
                  default:
                    {
                        var undefined_1 = function f2(NaN_2, parseInt_2) {
                        }((c = 1 + c, -"bar" * ([] >= "object") < +(5 % 4)), -5);
                    }

                  case a--:
                    for (var brake37 = 5; !function b_1() {
                    }() && brake37 > 0; --brake37) {
                        c = 1 + c, -4 + 38..toString() + ("b" & {}) || [ , 0 ][1] >= "undefined" < ("" ^ 25);
                    }
                    break;

                  case --b + (undefined_1 && typeof undefined_1.null == "function" && --_calls_ >= 0 && undefined_1.null((c = c + 1) + [ (c = 1 + c, 
                    ((22 < "function") >>> (-4 >>> 2)) * ((a_2_1 %= "undefined" !== {}) !== NaN >> "c")), (c = 1 + c, 
                    a_2_1 && (a_2_1[c = 1 + c, (Infinity & 25) / ("" << ([ , 0 ].length === 2)) - (("a", 
                    "foo") <= ({} >= undefined))] += -1 - Infinity) || false != ([ , 0 ].length === 2) || (Infinity, 
                    "number") <= [] + null), (c = 1 + c, "c" * NaN >>> "number" / 22, [ , 0 ][1] << true >>> "object" + "c") ][c = 1 + c, 
                    (4 % "" ^ (-0 && "a")) * ("number" >>> 0 << (undefined >= 2))], null, Infinity)):
                    L35517: {
                        c = 1 + c, ~(~{} >> (a_2_1 && (a_2_1.undefined = 38..toString() > 25)));
                        c = 1 + c, a_2_1 && (a_2_1[(c = c + 1) + (a_2 && a_2.var)] >>>= ("function" ^ NaN ^ 5 + 3) >= ([ , 0 ][1] < true === (undefined_1 = [ , 0 ].length === 2 || 1)));
                    }
                    break;

                  case a_2_1:
                    break;
                }
            }
            break;
        }
        {
            return;
            a_2_1 && a_2_1.in;
        }
    }
}

var arguments_1 = f0(NaN, a++ + --a);

console.log(null, a, b, c, Infinity, NaN, undefined);
```
```js
// uglified code
// (beautified)
var u = 10, l = 100, d = 10, v = 0;

!function() {
    try {
        try {
            var n = async function() {
                return l++, void ("function" == typeof n.undefined && 0 <= --u && n.undefined("a")) + d;
            }();
        } catch (n) {
            return d = ++l;
        } finally {
            var e = 5;
            do {
                for (var a = 5; (n /= "function" == typeof f2 && 0 <= --u && f2("undefined", "b", void 0)) && 0 < a; --a) {}
            } while (+l && 0 < --e);
            v += 1;
        }
    } finally {
        switch ((v += 1) + typeof (--d + (n && n[l++ + (l++ + ("function" == typeof n && 0 <= --u && n((v = 1 + v, 
        n = !0), [])) ? --d + {
            a_2: n,
            "-2": --d + ("23" in {
                length: (v = 1 + v, 0),
                c: (v = 1 + (v += 1), !1 < (n = !1)),
                NaN: (v = 1 + (v += 1), n && (n.undefined ^= !0))
            }),
            in: {
                foo: (v = 1 + v, 1 ^ void (v += 1)),
                [0]: (v = 1 + (v = 1 + v), ((n && (n[v = 1 + v, n && (n[(v += 1) + [ NaN, , (v = 1 + (v = 1 + v), 
                !1), ..."" + n, (v = 1 + v, !0) ]] += !0 * ("23" === (n && (n[v = 1 + v, v += 1, 
                0] -= 1 / 0))))] = !1)) << 23) - 3),
                true: !1
            },
            var: --d + (v = 1 + (v = 1 + (v = 1 + v)), (n |= !0) != (n = -1 / 0)),
            [--d + /[abc4]/g.exec((v = 1 + (v = 1 + (v += 1)), v += 1, "1"))]: l++ + (d = l)
        } : l++ + (n && "function" == typeof n.length && 0 <= --u && n.length(--d + (d += l), "number", -2)))]))) {
          case --d + n:
            var t = 5;
            do {
                var f = "undefined";
            } while (l++ + n && 0 < --t);
            break;

          case f:
          case --d + ~((n && (n[l++ + (n && n[v = 1 + v, 1])] = 0 << (n && (n[v = 1 + v, 1] = 0)))) + !0):
            for (var o = 5; n && "function" == typeof n.NaN && 0 <= --u && n.NaN() && 0 < o; --o) {}
            break;

          case f:
            for (var i = 5; "function" == typeof f && 0 <= --u && f((v += 1) + ("function" == typeof f1 && 0 <= --u && f1((v = 1 + v, 
            this < -5 < 0 ^ NaN), (v = 1 + (v += 1), n = !0 === (n = ("c" <= this) << NaN)))), ("" + ("" in {} || 3))[l--], --d + (f && "function" == typeof f.var && 0 <= --u && f.var((v = 1 + v, 
            0 | 0 != (f && (f.a >>= 0))), (v = 1 + v, (4 != this) << !1 <= "NaNundefined"), (v = 1 + (v += 1), 
            4 << (2 === [ , 0 ].length) != NaN ^ -1)))) && 0 < i; --i) {
                switch ((v += 1) + n) {
                  default:
                    var r = void (v = 1 + v);

                  case l--:
                    for (var c = 5; 0 < c; --c) {
                        v = 1 + v;
                    }
                    break;

                  case --d + (r && "function" == typeof r.null && 0 <= --u && r.null((v += 1) + [ (v = 1 + v, 
                    0 * (0 != (f %= !0))), (v = 1 + v, f && (f[v = 1 + v, 0 / ("" << (2 === [ , 0 ].length)) - !1] += -1 / 0) || 0 != (2 === [ , 0 ].length) || !1), (v = 1 + v, 
                    0) ][v = 1 + v, 0], null, 1 / 0)):
                    v = 1 + v, f && (f.undefined = !0), v = 1 + v, f && (f[(v += 1) + (n && n.var)] >>>= (!0 === (r = 2 === [ , 0 ].length || 1)) <= 8);
                    break;

                  case f:
                }
            }
        }
        return;
    }
}((l++, --l)), console.log(null, l, d, v, 1 / 0, NaN, void 0);
```
```
original result:
null 102 99 2 Infinity NaN undefined

uglified result:
null 101 7 2 Infinity NaN undefined
```
```js
// reduced test case (output will differ)

// (beautified)
(async function f1(Math_2) {
    return Math_2;
})(0());
// output: TypeError: 0 is not a function
// minify: 
// options: {
//   "compress": {
//     "passes": 1000000,
//     "unsafe": true
//   },
//   "toplevel": true,
//   "output": {
//     "v8": true
//   },
//   "validate": true
// }
```
```
minify(options):
{
  "compress": {
    "passes": 1000000,
    "unsafe": true
  },
  "toplevel": true,
  "output": {
    "v8": true
  }
}

Suspicious compress options:
  collapse_vars
  dead_code
  keep_fargs
  passes
  unused
```


Discussion:

Patch:
diff --git a/lib/compress.js b/lib/compress.js
index d4b911ee4ee..cb3351ac225 100644
--- a/lib/compress.js
+++ b/lib/compress.js
@@ -1614,6 +1614,14 @@ merge(Compressor.prototype, {
                     var scan_lhs = lhs && !side_effects && !is_lhs_read_only(lhs, compressor);
                     var scan_rhs = foldable(candidate);
                     if (!scan_lhs && !scan_rhs) continue;
+                    var funarg = candidate.name instanceof AST_SymbolFunarg;
+                    var may_throw = return_false;
+                    if (candidate.may_throw(compressor)) {
+                        if (funarg && scope instanceof AST_AsyncFunction) continue;
+                        may_throw = in_try ? function(node) {
+                            return node.has_side_effects(compressor);
+                        } : side_effects_external;
+                    }
                     var read_toplevel = false;
                     var modify_toplevel = false;
                     // Locate symbols which may execute code outside of scanning range
@@ -1622,10 +1630,6 @@ merge(Compressor.prototype, {
                     var rvalue = get_rvalue(candidate);
                     if (!side_effects) side_effects = value_has_side_effects();
                     var replace_all = replace_all_symbols(candidate);
-                    var may_throw = candidate.may_throw(compressor) ? in_try ? function(node) {
-                        return node.has_side_effects(compressor);
-                    } : side_effects_external : return_false;
-                    var funarg = candidate.name instanceof AST_SymbolFunarg;
                     var hit = funarg;
                     var abort = false;
                     var replaced = 0;


Test patch:
diff --git a/test/compress/async.js b/test/compress/async.js
index 3011a6affd1..71df24492f3 100644
--- a/test/compress/async.js
+++ b/test/compress/async.js
@@ -444,3 +444,30 @@ issue_4349_3: {
     expect_stdout: "function"
     node_version: ">=8"
 }
+
+issue_4359: {
+    options = {
+        collapse_vars: true,
+        unused: true,
+    }
+    input: {
+        try {
+            (async function(a) {
+                return a;
+            })(A);
+        } catch (e) {
+            console.log("PASS");
+        }
+    }
+    expect: {
+        try {
+            (async function(a) {
+                return a;
+            })(A);
+        } catch (e) {
+            console.log("PASS");
+        }
+    }
+    expect_stdout: "PASS"
+    node_version: ">=8"
+}