Repository: mishoo/UglifyJS (JavaScript)

Issue:
ufuzz failure
```js
// original code
// (beautified)
var _calls_ = 10, a = 100, b = 10, c = 0;

{
    var brake1 = 5;
    L11821: do {
        {
            var undefined_2 = function f0(c_2) {
                function f1() {
                    c = c + 1;
                    c = c + 1;
                }
                var bar = f1("c");
                function f2(a, NaN) {
                    c = c + 1;
                    for (var brake6 = 5; "a" in {
                        in: (c = 1 + c, ((c = c + 1, 23..toString()) ^ [ , 0 ][1] >= 1) >= (null <= -5) % (24..toString() >= "")),
                        "": (c = 1 + c, (-0 >>> 25 && 25 | 3) != (c = c + 1, 0) % ("" > 5))
                    } && brake6 > 0; --brake6) {
                        try {
                            {
                                var brake8 = 5;
                                while ((c = 1 + c, (c_2 && (c_2[{
                                    length: (c = 1 + c, (a = -0 % "b" === 2 + 1) | (-0 > "") / ("b" ^ "")),
                                    then: (c = 1 + c, c = c + 1, (/[a2][^e]+$/, 4) % (-3 == "b")),
                                    static: (c = 1 + c, !((a && (a[c = 1 + c, (NaN %= ("number" + -0) % (-5 || 2)) + (NaN && (NaN[0 === 1 ? a : b] += (a && (a.in += 1 / 5)) >> (-2 || "bar")))] = "bar" >= 25)) !== (38..toString() !== 3))),
                                    b: (c = 1 + c, ((c_2 && (c_2[c = 1 + c, NaN <= "object" == 4 >= "number" && (false ^ "a") % (/[a2][^e]+$/ === [])] >>= "b" - 22)) ^ -3 % 2) == (24..toString() - 23..toString()) % ({} ^ "undefined"))
                                }] <<= null != 4 != -5 >> 25)) != ("" == "" & 2 * false)) && --brake8 > 0) {
                                    c = 1 + c, null == null == ([ , 0 ].length === 2) + false !== (null && "undefined") >= "foo" >>> [ , 0 ][1];
                                }
                            }
                        } catch (await) {
                            c = 1 + c, NaN += 24..toString() >= 4 !== "a" * "bar" && (0 ^ -4) >> (-4 >> -4);
                            c = 1 + c, ([ , 0 ].length === 2) / "object" >> ("b" ^ /[a2][^e]+$/) >>> (-3 > -3) * ~"a";
                        }
                    }
                }
                var b_2 = f2();
                function f3(b_1, bar_1) {
                    {
                        var brake12 = 5;
                        do {
                            switch (b--) {
                              case (c = c + 1) + {
                                    length: (c = 1 + c, bar_1 && (bar_1[a++ + (("number" - NaN) / ([ , 0 ].length === 2, 
                                    0) >> (-"a" === false < 5))] = (("function", "undefined") >= 1 - "c") >>> (b_2 += 3 >> "b" == (0 ^ {})))),
                                    a: (c = 1 + c, b_2 && (b_2.foo <<= (null / Infinity >> ("function" !== "function")) % (("c" | 38..toString()) + (false == 1)))),
                                    a: (c = 1 + c, ("b" >> -0 != -4 >> "object") * ((b_1 && (b_1[c = 1 + c, (c = c + 1, 
                                    "undefined", 2 || 0) <= ("foo" >>> 25 != -3 % /[a2][^e]+$/)] <<= "" + "c")) == -3 >= 25)),
                                    async: (c = 1 + c, ("foo", []) >> (22 <= "b") > "" << -2 >> (5 << this)),
                                    foo: (c = 1 + c, 38..toString() / 3 % ([] | undefined) !== (c = c + 1, bar_1 && (bar_1.b = -2 % -0)))
                                }:
                                c = 1 + c, (undefined + 1) / ([ , 0 ].length === 2 != -5) ^ ("undefined" * -0 ^ (bar_1 = "undefined" % 22));
                                c = 1 + c, (c = c + 1, "function" > "c") << (false * "bar" >= (bar_1 = [ , 0 ][1] % "function"));
                                break;

                              case (c = c + 1) + "function":
                                c = 1 + c, (b_2 && (b_2.then = 38..toString() >= "c" ^ -1 / [ , 0 ][1])) << ((b_1 = [ , 0 ].length === 2 ^ /[a2][^e]+$/) >> (([ , 0 ].length === 2) < 25));
                                c = 1 + c, (bar && (bar[--b + (b = a)] = this & -3 | 3 ^ "b")) <= +(-4 % [ , 0 ][1]);
                                break;

                              case a++ + [ (c = 1 + c, ((-2 ^ "a") >= 1 >>> -1) / (23..toString() * Infinity - ("number", 
                                25))) ][c = 1 + c, ((Infinity ^ 1) === (24..toString() | {})) <= (38..toString() > 1 === ("bar" == []))]:
                                c = 1 + c, (null ^ -2 ^ 23..toString() + Infinity) >= (b_2 *= 25 != -2) % (([ , 0 ].length === 2) >= []);
                                break;

                              case (c = c + 1) + (false in [ (c = 1 + c, (-0 + ([ , 0 ].length === 2) | "a" < "undefined") + (false ^ [ , 0 ][1]) % (b_2 && (b_2.static = 3 >>> 24..toString()))), (c = 1 + c, 
                                ([ , 0 ].length === 2 === 24..toString()) / (this ^ NaN) << (b_2 = (null || -3) === 23..toString() % this)), (c = 1 + c, 
                                ("function" + "c" >= ("" ^ 4)) << ((c = c + 1, "a") ^ ("object" ^ "undefined"))) ]):
                            }
                        } while (true in [ (c = 1 + c, delete 38..toString() === 0 <= "c", -0 > Infinity, 
                        c_2 += "object" ^ undefined), (c = 1 + c, 22 - true >> ("undefined" > NaN) & (bar && (bar.undefined = false << 22 >> (b_2 && (b_2.var ^= "number" === /[a2][^e]+$/))))), (c = 1 + c, 
                        bar_1 && (bar_1.static = (b_1 && (b_1.null -= 22 / 1 & 22 != [ , 0 ][1])) == -4 << undefined > ("a" !== -2))), (c = 1 + c, 
                        ("undefined" ^ 23..toString()) * (0 == [ , 0 ][1]) != ((-4 ^ -2) === (c = c + 1, 
                        ""))) ] && --brake12 > 0);
                    }
                    c = c + 1;
                }
                var Infinity_2 = f3(a++ + (null in [ a++ + bar, 1 === 1 ? a : b, b = a, (c = c + 1) + (b_2 && b_2.b) ]), undefined, b += a);
                function f4(Infinity_2) {
                    return (c = c + 1) + (typeof f2 == "function" && --_calls_ >= 0 && f2`${c = 1 + c, 
                    delete ((38..toString() ^ 2) >>> ("number", 5))}${c = 1 + c, ((Infinity_2 && (Infinity_2.b = [] >> 4)) >>> (-3 || -5)) + (Infinity_2 && (Infinity_2.null = (bar && (bar.in |= /[a2][^e]+$/ >>> NaN)) === "number" < "foo"))}${c = 1 + c, 
                    b_2 && (b_2.set = (-4 ^ 4) - (bar = "object" ^ 22) & (Infinity_2 && (Infinity_2.var /= ([ , 0 ][1] | "foo") >> (false << "object"))))}${c = 1 + c, 
                    ([ , 0 ][1] !== 0) / (-4 + null) - (this + ([ , 0 ].length === 2) >>> (undefined || "c"))}`);
                }
                var async_2 = f4(null, ...[]);
            }();
        }
    } while ((c = c + 1) + (([] == null) < (undefined_2 = -0 % "") ^ (c = c + 1, false) / (-2 % 3)) && --brake1 > 0);
}

{
    {
        var expr23 = (c = c + 1) + ((undefined_2 <<= "" ^ 5) % (-0 < -0) >>> (undefined_2 = (true === -2) - (-3 || -4)));
        for (var key23 in expr23) {
            var yield_2;
        }
    }
    undefined_2 && undefined_2[a++ + (typeof a !== "unknown")] ? undefined_2 = a++ + [] : b++;
    {
        var a_2 = function f5(a_2) {
            var yield = a++ + (yield && typeof yield.done == "function" && --_calls_ >= 0 && (--b + (yield && yield.in), 
            yield.done)()), await_1 = (c = c + 1) + (0 === 1 ? a : b);
            {
                var brake28 = 5;
                do {
                    {
                        var Infinity = function bar(b, b, a_2) {
                            function f6() {
                                c = 1 + c, ([ , 0 ].length === 2) <= false >= ({} >= true) !== (await_1 && (await_1[(c = c + 1) + ((38..toString() ^ "number") >= (a_2 && (a_2[c = 1 + c, 
                                (1 - -5) * (c = c + 1, null) || [ , 0 ][1] >= "bar" <= ({} <= true)] >>= 4 * "foo")) && 23..toString() - -2 - (25 || 24..toString()))] -= false >> 4 === [] - -0));
                                c = 1 + c, (await_1 && (await_1.NaN += (undefined_2 && (undefined_2.value = 3 & [ , 0 ].length === 2)) % (38..toString() / "a"))) + (0 <= "number", 
                                5 || 22);
                            }
                            var bar = f6("c", ...[ (c = 1 + c, ((bar && ([ bar[c = 1 + c, "a" > 5 && "foo" % 2 && false / 1 === [ , 0 ][1] + "foo"] ] = [ 22 || "object" ])) | "foo" !== -4) % ("undefined" << false & "b" == 0)) ]);
                            function f7() {
                                c = 1 + c, 22 < ([ , 0 ].length === 2) < void /[a2][^e]+$/ && (a_2 && (a_2[b = a] = (2 >>> NaN) / (([ , 0 ].length === 2) + 5)));
                                c = 1 + c, (b && (b.static = 2 === 24..toString()), ([ , 0 ].length === 2) <= {}) ^ -5 >>> null > ([] != [ , 0 ][1]);
                            }
                            var bar_2 = f7(undefined, true, -3);
                            function f8(a_2_1, {}) {
                            }
                            var bar_2 = f8("object", {});
                            function f9(NaN_2) {
                            }
                            var b = f9((c = c + 1) + (typeof f6 == "function" && --_calls_ >= 0 && f6((c = 1 + c, 
                            ("object" / "a" === ("b" && 22)) >> ((yield && (yield.then = {} >>> 22)) & "number" / "c")), ...[ (c = 1 + c, 
                            (b && (b.get = "object" && Infinity)) * (bar_2 && (bar_2[c = 1 + c, undefined_2 && (undefined_2[c = 1 + c, 
                            ((null != "") <= -5 % []) % ((22 ^ 38..toString()) <= (-1, Infinity))] = 4 >> -4) && 3 & NaN && (false && "undefined") < (null && -3)] = "object" << NaN)) < (c = c + 1, 
                            false & /[a2][^e]+$/)), (c = 1 + c, void (/[a2][^e]+$/ - null) ^ (await_1 = -1 < "c") >> (-5 > "bar")) ])), --b + {
                                next: (c = 1 + c, void (NaN >= Infinity) || 24..toString() >>> -3 === true + "function"),
                                var: (c = 1 + c, (38..toString() / -3, 22 * 24..toString()) << ("foo" * "foo" & ("a" || []))),
                                c: (c = 1 + c, true - -2 + "c" % -0 !== ("c" <= ([ , 0 ].length === 2)) - null % "bar"),
                                bar: bar
                            }.in);
                        }();
                    }
                } while (--b + void function undefined() {
                    if (0 === 1 ? a : b) {
                        var brake35 = 5;
                        L11822: do {
                        } while (a++ + (a_2 && a_2.done) && --brake35 > 0);
                    }
                }() && --brake28 > 0);
            }
        }(-0);
    }
    for (var brake37 = 5; a++ + (a_2 && typeof a_2.c == "function" && --_calls_ >= 0 && a_2.c([ , 0 ][1], --b + {
        3: a++ + typeof void a,
        static: [ a++ + {}[+function a_2() {
        }()], a_2 && typeof a_2.set == "function" && --_calls_ >= 0 && a_2.set({}), ..."" + undefined_2, a_2 && typeof a_2.foo == "function" && --_calls_ >= 0 && a_2.foo`${c = 1 + c, 
        (true >= null) * ("a", "b") && (a_2 && (a_2[c = 1 + c, NaN % /[a2][^e]+$/ >>> ("c" && "bar") & (23..toString() - -5) / (0 == -5)] += Infinity == -0)) - (a_2 %= -5 < 4)}${c = 1 + c, 
        delete ("bar" - Infinity) !== (a_2 && (a_2[a++ + "function"] += ([] && -4) >= (a_2 = "function" * "number")))}${c = 1 + c, 
        (Infinity < 0) / (22 ^ this) < delete ("function" * "number")}${c = 1 + c, c = c + 1, 
        (undefined_2 = 2 < -0) >>> ("a" >= "undefined")}` ][typeof f10 == "function" && --_calls_ >= 0 && f10(-4, 22, undefined_2 && typeof undefined_2.get == "function" && --_calls_ >= 0 && undefined_2.get(25, -5, "b"))]
    }.b, "b")) && brake37 > 0; --brake37) {
        var expr38 = (c = c + 1) + (--b + (typeof a_2 == "function" && --_calls_ >= 0 && a_2()) ? --b + typeof (a_2 && a_2[typeof a_2 === "string"]) : {
            a_2: a_2,
            undefined_2: undefined_2,
            async: (c = c + 1) + (typeof f2 == "function" && --_calls_ >= 0 && f2()),
            then: --b + (0 === 1 ? a : b)
        }.foo);
        for (var key38 in expr38) {
            c = 1 + c;
            var foo = expr38[key38];
            c = c + 1;
        }
    }
}

console.log(null, a, b, c, Infinity, NaN, undefined);
```
```js
// uglified code
// (beautified)
var _calls_ = 10, a = 100, b = 10, c = 0, brake1 = 5;

do {
    var undefined_2 = function(t) {
        var o = (c += 1, void (c += 1));
        function n(a, n) {
            c += 1;
            for (var e = 5; "a" in {
                in: !0,
                "": (c = 1 + (1 + c + 1), 0 != (c += 1, NaN))
            } && 0 < e; --e) {
                try {
                    for (var i = 5; c = 1 + c, 0 != (t && (t[{
                        length: 0,
                        then: NaN,
                        static: !1,
                        b: (c = 1 + (1 + (1 + (1 + c) + 1)), NaN == (-1 ^ (t && (t[c = 1 + c, n <= "object" == 0 && NaN] >>= NaN))))
                    }] <<= !0)) && 0 < --i; ) {
                        c = 1 + c;
                    }
                } catch (a) {
                    n += -1, c = 1 + (1 + c);
                }
            }
        }
        var f = n();
        !function(n, e) {
            var i = 5;
            do {
                switch (b--) {
                  case (c += 1) + {
                        length: (c = 1 + c, e && (e[0 + a++] = !1 >>> (f += !1))),
                        a: (c = 1 + c, f && (f.foo <<= 0)),
                        a: (c = 1 + c, !0 * (0 == (n && (n[c = 1 + c, c += 1, !1] <<= "c")))),
                        async: 0 >> (5 << this) < 0,
                        foo: (c = 1 + (1 + c), NaN !== (c += 1, e && (e.b = NaN)))
                    }:
                    c = 1 + (1 + c), c += 1, e = NaN;
                    break;

                  case (c += 1) + "function":
                    c = 1 + c, f && (f.then = 0), n = 2 === [ , 0 ].length ^ /[a2][^e]+$/, c = 1 + c, 
                    o && (o[--b + (b = a)] = -3 & this | 3);
                    break;

                  case a++ + [ 0 ][c = 1 + (1 + c), !0]:
                    c = 1 + c, f *= !0;
                    break;

                  case (c += 1) + (!1 in [ (c = 1 + c, (-0 + (2 === [ , 0 ].length) | !0) + 0 % (f && (f.static = 0))), (c = 1 + c, 
                    (2 === [ , 0 ].length === "24") / (NaN ^ this) << (f = -3 == "23" % this)), (c = 1 + c, 
                    !1 << (0 ^ (c += 1, "a"))) ]):
                }
            } while (!0 in [ t += 0, (c = 1 + (1 + c), 21 & (o && (o.undefined = 0 >> (f && (f.var ^= !1))))), (c = 1 + c, 
            e && (e.static = 0 == (n && (n.null -= 0)))), (c = 1 + c, 23 != (2 === (c += 1, 
            ""))) ] && 0 < --i);
            c += 1;
        }(a++ + (null in [ a++ + o, a, b = a, (c += 1) + (f && f.b) ]), void 0, b += a), 
        function() {
            c += 1, 0 <= --_calls_ && n`${c = 1 + c, !0}${c = 1 + c, 0}${c = 1 + c, f && (f.set = -8 - (o = 22) & null)}${c = 1 + c, 
            -0 - (this + (2 === [ , 0 ].length) >>> "c")}`;
        }();
    }();
} while ((c += 1) + (!1 < (undefined_2 = NaN) ^ (c += 1, -0)) && 0 < --brake1);

var key23, yield_2, expr23 = (c += 1) + ((undefined_2 <<= 5) % !1 >>> (undefined_2 = 3));

for (key23 in expr23) {}

undefined_2 && undefined_2[a++ + ("unknown" != typeof a)] ? undefined_2 = a++ + [] : b++;

for (var a_2 = function() {
    var n, e, i = a++ + (i && "function" == typeof i.done && 0 <= --_calls_ && (--b, 
    i && i.in, i.done)()), t = (c += 1, 5);
    do {
        var o = ((e = function() {
            c = 1 + (1 + c);
        })((c = 1 + c, n = void 0)), c = 1 + (1 + c), n && (n.static = !1), c += 1, 0 <= --_calls_ && e((c = 1 + c, 
        i && (i.then = 0)), (c = 1 + c, n && (n.get = o), c += 1), c = 1 + c), --n, void (c = 1 + (1 + (1 + c))));
    } while (--b + void function() {
        if (b) {
            for (var c = 5; a++ && 0 < --c; ) {}
        }
    }() && 0 < --t);
}(), brake37 = 5; a++ + (a_2 && "function" == typeof a_2.c && 0 <= --_calls_ && a_2.c(0, --b + {
    3: a++ + "undefined",
    static: [ a++ + {}.NaN, a_2 && "function" == typeof a_2.set && 0 <= --_calls_ && a_2.set({}), ..."" + undefined_2, a_2 && "function" == typeof a_2.foo && 0 <= --_calls_ && a_2.foo`${c = 1 + c, 
    NaN}${c = 1 + c, !0 !== (a_2 && (a_2[a++ + "function"] += (a_2 = NaN) <= -4))}${c = 1 + c, 
    !1 / (22 ^ this) < !0}${c = 1 + c, c += 1, (undefined_2 = !1) >>> !1}` ]["function" == typeof f10 && 0 <= --_calls_ && f10(-4, 22, undefined_2 && "function" == typeof undefined_2.get && 0 <= --_calls_ && undefined_2.get(25, -5, "b"))]
}.b, "b")) && 0 < brake37; --brake37) {
    var key38, expr38 = (c += 1) + (--b + ("function" == typeof a_2 && 0 <= --_calls_ && a_2()) ? --b + typeof (a_2 && a_2["string" == typeof a_2]) : {
        a_2: a_2,
        undefined_2: undefined_2,
        async: (c += 1) + ("function" == typeof f2 && 0 <= --_calls_ && f2()),
        then: --b + b
    }.foo);
    for (key38 in expr38) {
        var c = 1 + c, foo = expr38[key38];
        c += 1;
    }
}

console.log(null, a, b, c, 1 / 0, NaN, void 0);
```
```
original result:
null 123 227 233 Infinity NaN undefined

uglified result:
null 123 227 232 Infinity NaN undefined
```
```js
// reduced test case (output will differ)

// (beautified)
(function f5() {
    var await_1 = 1;
    do {
        (function bar() {
            function f6() {
                console.log(await_1);
            }
            f6();
            f6(...[ await_1 = 0 ]);
        })();
    } while (0);
})();
// output: 1
// 0
// 
// minify: 0
// 0
// 
// options: {
//   "compress": {
//     "passes": 1000000,
//     "sequences": 1000000,
//     "unsafe": true,
//     "unsafe_Function": true,
//     "unsafe_math": true,
//     "unsafe_proto": true,
//     "unsafe_regexp": true
//   },
//   "mangle": {
//     "v8": true
//   },
//   "output": {
//     "v8": true
//   },
//   "validate": true
// }
```
```
minify(options):
{
  "compress": {
    "passes": 1000000,
    "sequences": 1000000,
    "unsafe": true,
    "unsafe_Function": true,
    "unsafe_math": true,
    "unsafe_proto": true,
    "unsafe_regexp": true
  },
  "mangle": {
    "v8": true
  },
  "output": {
    "v8": true
  }
}

Suspicious compress options:
  collapse_vars
  evaluate
  inline
  passes
  reduce_vars
  sequences
  unused

Suspicious options:
  rename
```


Discussion:

Patch:
diff --git a/lib/compress.js b/lib/compress.js
index 90261d0ab85..dbfc2e7599f 100644
--- a/lib/compress.js
+++ b/lib/compress.js
@@ -889,6 +889,7 @@ merge(Compressor.prototype, {
                     } else {
                         right.parent_scope.resolve().fn_defs.push(right);
                         right.safe_ids = null;
+                        if (!node.write_only) mark_fn_def(tw, ld, right);
                     }
                     return true;
                 } else if (scan) {


Test patch:
diff --git a/test/compress/functions.js b/test/compress/functions.js
index 6d41a265c18..7c6ebe03b0e 100644
--- a/test/compress/functions.js
+++ b/test/compress/functions.js
@@ -6346,3 +6346,55 @@ issue_5046: {
     }
     expect_stdout: "PASS"
 }
+
+issue_5061_1: {
+    options = {
+        evaluate: true,
+        reduce_vars: true,
+        toplevel: true,
+    }
+    input: {
+        var f, a = 1;
+        (f = function() {
+            console.log(a ? "foo" : "bar");
+        })();
+        f(a = 0);
+    }
+    expect: {
+        var f, a = 1;
+        (f = function() {
+            console.log(a ? "foo" : "bar");
+        })();
+        f(a = 0);
+    }
+    expect_stdout: [
+        "foo",
+        "bar",
+    ]
+}
+
+issue_5061_2: {
+    options = {
+        reduce_vars: true,
+        toplevel: true,
+        unused: true,
+    }
+    input: {
+        var f, a = 1;
+        (f = function() {
+            console.log(a ? "foo" : "bar");
+        })();
+        f(a = 0);
+    }
+    expect: {
+        var f, a = 1;
+        (f = function() {
+            console.log(a ? "foo" : "bar");
+        })();
+        f(a = 0);
+    }
+    expect_stdout: [
+        "foo",
+        "bar",
+    ]
+}