Repository: mishoo/UglifyJS (JavaScript)

Issue:
ufuzz failure
```js
// original code
// (beautified)
var _calls_ = 10, a = 100, b = 10, c = 0;

function f0(Math_1, a, Infinity_1) {
    try {
        try {
            L23719: for (var brake4 = 5; --b + 5 && brake4 > 0; --brake4) {
                for (var brake6 = 5; (c = c + 1) + delete ((5 | -0 | {} & 22) << (Infinity_1 |= /[a2][^e]+$/ >> 38..toString()) + (Math_1 = 22 | this)) && brake6 > 0; --brake6) {
                    return;
                }
                c = c + 1;
                Math_1 && Math_1[--b + Math_1];
            }
        } finally {
            {
                var brake10 = 5;
                L23720: do {
                    try {
                        c = c + 1;
                    } finally {
                        {
                            var brake13 = 5;
                            L23721: do {
                                {
                                    return a++ + (+(true + [ , 0 ][1]) != ((Math_1 && (Math_1[c = 1 + c, (c = c + 1, 
                                    25) << (-4 << -4) ^ -3 > 5 < "foo" + 4] *= -4 && "undefined")) | (c = c + 1, [])));
                                }
                            } while (--b + void function Infinity_1() {
                                c = 1 + c, ("function" | 3 || 2 <= 3) ^ ("a" | "") != true >>> "number";
                                c = 1 + c, (Math_1 = 5 ^ "c") - (3 ^ Infinity) || ("b" ^ Infinity) > 24..toString() % ([ , 0 ].length === 2);
                                c = 1 + c, (22 & Infinity ^ {} / 2) & (0 ^ 0) !== (/[a2][^e]+$/ || [ , 0 ].length === 2);
                                c = 1 + c, ("a" != -3) - (undefined << 2) + (22 > -1 !== (-4 !== 1));
                            }() && --brake13 > 0);
                        }
                        c = c + 1;
                    }
                } while ((c = c + 1) + (typeof f0 == "function" && --_calls_ >= 0 && f0("a", 4)) && --brake10 > 0);
            }
            {
                var expr20 = /[abc4]/.test((b-- || b || 5).toString());
                for (var key20 in expr20) {
                    if (--b) {
                        var brake22 = 5;
                        do {
                            {}
                        } while (/[abc4]/.test((typeof f1 == "function" && --_calls_ >= 0 && f1((c = 1 + c, 
                        (true % "function" & [ , 0 ][1] / this) === (Infinity_1 = 38..toString() ^ -5) <= (2 >= NaN)), Infinity) || b || 5).toString()) && --brake22 > 0);
                    }
                }
            }
        }
    } catch (NaN_1) {
        {
            var brake24 = 5;
            while (a++ + ((NaN, "function") == 0 > 24..toString() || (NaN_1 *= 38..toString() !== Infinity == ("function" ^ {}))) && --brake24 > 0) {
                if (+b) {
                    L23722: {
                        {
                            var brake27 = 5;
                            do {
                                {
                                    var brake28 = 5;
                                    do {
                                        if (c = 1 + c, ("" - 0) / ("foo" === -5) << (false, -3) - ("a" === "bar")) {
                                            c = 1 + c, (Infinity_1 |= false > []) >= ({} !== 4) || "b" % {} ^ undefined >> 2;
                                        } else {
                                            c = 1 + c, 1 / null * (0 || [ , 0 ].length === 2) == (Infinity_1 && (Infinity_1[(c = c + 1) + (c = 1 + c, 
                                            Math_1 >>>= (c = c + 1, undefined % "") + ([ , 0 ][1] << 5 && "number" >>> Infinity))] = Infinity + 38..toString() == ![ , 0 ][1]));
                                        }
                                    } while ((c = c + 1) + null && --brake28 > 0);
                                }
                            } while ((c = c + 1) + {}.var && --brake27 > 0);
                        }
                    }
                } else {}
            }
        }
        {
            {
                var brake34 = 5;
                while (--b + (typeof f1 == "function" && --_calls_ >= 0 && f1()) && --brake34 > 0) {}
            }
            {
                var brake36 = 5;
                while (NaN_1 && NaN_1[/[abc4]/g.exec((a++ + /[abc4]/.test(((c = 1 + c, -([] >>> "" && "a" & undefined)) || b || 5).toString()) || b || 5).toString())] && --brake36 > 0) {
                    for (var brake37 = 5; a++ + ((c = c + 1) + /[abc4]/g.exec((NaN_1 || b || 5).toString())) && brake37 > 0; --brake37) {
                        return;
                        --b + Math_1;
                    }
                }
            }
            {
                return {
                    length: (Infinity_1 && (Infinity_1[c = 1 + c, (this ^ this) % (25 >= "number") | ("number" & undefined) << ("function" <= undefined)] = 2 != 23..toString())) * (38..toString(), 
                    -0) % ((1 != "undefined") <= (NaN <= ([ , 0 ].length === 2))),
                    a: a++ + (typeof Math_1 == "function" && --_calls_ >= 0 && Math_1()),
                    b: /[abc4]/g.exec((a++ + NaN_1 || b || 5).toString()),
                    "-2": (c = c + 1) + {
                        Infinity: (c = 1 + c, "c" >> "c" >> ({} >> 4) && (NaN ^ 5) == -1 >= "bar"),
                        a: (c = 1 + c, 2 > /[a2][^e]+$/ < (Math_1 && (Math_1.foo = 5 >> this)) > (-3 <= "undefined" > (2 | 25))),
                        null: (c = 1 + c, ("a" | [ , 0 ].length === 2) / (24..toString() / -2), (-1 != 4) >>> (25 >>> 0))
                    }[Infinity_1 && Infinity_1[c = 1 + c, -0 % "a" - (-0 | true) == (0 < "undefined" == -5 <= -2)]]
                };
            }
            {
                var brake40 = 5;
                L23723: while ((c = c + 1) + ((Math_1 && (Math_1.b = 38..toString() - "a"), -0 ^ "c") + (4 == false) % (3 == "b")) && --brake40 > 0) {
                    var brake41 = 5;
                    while ((b-- ? --b + (typeof c_2 !== "number") : (c = c + 1) + +(((24..toString() | 1) ^ (-2 | 38..toString())) - ((2 != "function") << ("a" >= "function")))) && --brake41 > 0) {
                        var b_1 = (c = c + 1) + ((c = c + 1) + {
                            "-2": (c = 1 + c, Math_1 += [] && "object" && (Infinity_1 && (Infinity_1.var += (undefined, 
                            undefined))) && (NaN_1 && (NaN_1.in += (5, 24..toString()) ^ [] - -1))),
                            undefined: (c = 1 + c, ((NaN >= "a") - "undefined" % 4) % (("number" ^ "b") / ("object" !== ""))),
                            undefined: (c = 1 + c, (-0 && "bar") >= (25 == /[a2][^e]+$/) != (22 >> true == -0 << 24..toString()))
                        }[c = 1 + c, (-5 && {}) >>> (Infinity > -5) < (-5 & -2) >> 23..toString() + 22] || a || 3).toString();
                    }
                }
            }
        }
    }
}

var Infinity = f0(-0, -0, a && a.null);

console.log(null, a, b, c, Infinity, NaN, undefined);
```
```js
// uglified code
// (beautified)
var y = 10, b = 10, N = 0, g = function r(a, t, f) {
    try {
        try {
            for (var i = 5; 5 + --b && 0 < i; --i) {
                if ((N += 1) + (f |= 0, !0)) {
                    return;
                }
                N += 1, (a = 22 | this) && a[--b + a];
            }
        } finally {
            var o = 5;
            do {
                try {
                    N += 1;
                } finally {
                    var e = 5;
                    do {
                        return t++ + (1 != ((a && (a[N = 1 + N, !1 ^ (N += 1, 25)] *= "undefined")) | (N += 1, 
                        [])));
                    } while (--b + (a = 5, void (N = 1 + (N = 1 + (N = 1 + (N = 1 + N))))) && 0 < --e);
                    N += 1;
                }
            } while ((N += 1) + (0 <= --y && r("a", 4)) && 0 < --o);
            var n = /[abc4]/.test("" + (b-- || b || 5));
            for (var l in n) {
                if (--b) {
                    var c = 5;
                    do {} while (/[abc4]/.test("" + ("function" == typeof f1 && 0 <= --y && f1((N = 1 + N, 
                    (NaN & 0 / this) === (f = -35) <= !1), g) || b || 5)) && 0 < --c);
                }
            }
        }
    } catch (r) {
        for (var v = 5; t++ + (r *= "38" !== g == 0) && 0 < --v; ) {
            if (+b) {
                var u = 5;
                do {
                    for (var h = 5; N = 1 + (1 + N), f && (f[(N += 1) + (N = 1 + N, a >>>= (N += 1, 
                    NaN))] = g + "38" == 1), (N += 1) + null && 0 < --h; ) {}
                } while ((N += 1) + {}.var && 0 < --u);
            }
        }
        for (var d = 5; --b + ("function" == typeof f1 && 0 <= --y && f1()) && 0 < --d; ) {}
        for (var s = 5; r && r[/[abc4]/g.exec("" + (t++ + /[abc4]/.test((N = 1 + N, "" + (b || 5))) || b || 5))] && 0 < --s; ) {
            if (t++ + ((N += 1) + /[abc4]/g.exec("" + (r || b || 5)))) {
                return;
            }
        }
        return {
            length: -0 * (f && (f[N = 1 + N, (this ^ this) % !1 | 0] = !0)) % !1,
            a: t++ + ("function" == typeof a && 0 <= --y && a()),
            b: /[abc4]/g.exec("" + (t++ + r || b || 5)),
            "-2": (N += 1) + {
                Infinity: 0,
                a: (N = 1 + (1 + N), !1 < (!1 < (a && (a.foo = 5 >> this)))),
                null: (N = 1 + N, 0)
            }[f && f[N = 1 + N, !1]]
        };
    }
}(-0, -0, void 0);

console.log(null, 100, b, N, g, NaN, void 0);
```
```
original result:
null 100 9 5 1 NaN undefined

uglified result:
null 100 9 3 1 NaN undefined
```
```js
// reduced test case (output will differ)

// (beautified)
var c = 0;

function f0(Math_1) {
    try {
        try {
            for (var brake6 = 5; c + delete (0 << (Math_1 = 1)); 0) {
                return;
            }
            Math_1[0];
        } finally {
            return Math_1;
        }
    } catch (NaN_1) {
        c = 0;
    }
}

var Infinity = f0();

console.log(Infinity);
// output: 1
// 
// minify: undefined
// 
// options: {
//   "compress": {
//     "passes": 1000000,
//     "unsafe": true
//   },
//   "toplevel": true
// }
```
```
minify(options):
{
  "compress": {
    "passes": 1000000,
    "unsafe": true
  },
  "toplevel": true
}

Suspicious compress options:
  collapse_vars
  dead_code
  evaluate
  inline
  loops
  passes
  sequences
  side_effects
  unused
```


Discussion:

Patch:
diff --git a/lib/compress.js b/lib/compress.js
index 644746e40fe..cc2d1ecbd61 100644
--- a/lib/compress.js
+++ b/lib/compress.js
@@ -1172,7 +1172,7 @@ merge(Compressor.prototype, {
                     scope = node;
                     break;
                 } else if (node instanceof AST_Try) {
-                    in_try = node;
+                    if (!in_try) in_try = node;
                 }
             } while (node = compressor.parent(level++));
         }


Test patch:
diff --git a/test/compress/collapse_vars.js b/test/compress/collapse_vars.js
index 446377a1cb6..737697a8202 100644
--- a/test/compress/collapse_vars.js
+++ b/test/compress/collapse_vars.js
@@ -8108,3 +8108,37 @@ issue_3908: {
     }
     expect_stdout: "PASS"
 }
+
+issue_3927: {
+    options = {
+        collapse_vars: true,
+    }
+    input: {
+        var a = 0;
+        console.log(function(b) {
+            try {
+                try {
+                    if (a + (b = "PASS", true)) return;
+                    b.p;
+                } finally {
+                    return b;
+                }
+            } catch (e) {
+            }
+        }());
+    }
+    expect: {
+        var a = 0;
+        console.log(function(b) {
+            try {
+                try {
+                    if (a + (b = "PASS", true)) return;
+                    b.p;
+                } finally {
+                    return b;
+                }
+            } catch (e) {}
+        }());
+    }
+    expect_stdout: "PASS"
+}