Repository: mishoo/UglifyJS (JavaScript)

Issue:
ufuzz failure
```js
// original code
// (beautified)
var _calls_ = 10, a = 100, b = 10, c = 0;

function f0(a_2, a_2_1) {
    function f1() {
        {
            var brake1 = 5;
            L50903: do {
                var b;
            } while ((c = c + 1) + b && --brake1 > 0);
        }
        L50904: {
            switch (--b + (typeof a_2 !== "function")) {
              case a++ + void ((-2 ^ "foo" ?? "c" >>> 5) > ((-1 && "function") != undefined << this)):
                break;

              case 3:
                c = 1 + c, (a_2 && (a_2.next += (/[a2][^e]+$/ | "c") !== (2 & "a"))) >>> ("foo" >> [] ^ ([ , 0 ].length === 2) * 3);
                c = 1 + c, (a_2_1 && (a_2_1.then **= (b && (b[c = 1 + c, delete 5 >> -"bar" ?? (a_2_1 *= [] >> 23..toString()) ^ "number" - "b"] %= 2 * "foo")) < undefined / -1)) !== ("object" ^ this) <= (-2 ?? this);
                break;

              case (c = c + 1) + (typeof async_1 !== "undefined"):
                break;

              default:
                c = 1 + c, (b && (b[c = 1 + c, ("a" != 38..toString()) * (4 - 38..toString()) >> ((a_2_1 && (a_2_1.get += "b" <= 3)) > (a_2 && (a_2.set = -2 >> {})))] ^= (a_2 && (a_2[c = 1 + c, 
                (38..toString() !== ([ , 0 ].length === 2) === (5 ^ "bar")) + (-4, "b", undefined)] -= (-0) ** false)) ** ("undefined" < "bar"))) > ([] & 25) + (-4 || [ 3n ][0] > 2);
            }
        }
    }
    var bar_1 = f1();
    function f2(await_2, b_1) {
        var bar_1_2 = --b + +function bar_1() {
            c = c + 1;
            c = c + 1;
        }(), bar_1 = a_2;
        bar_1;
    }
    var bar_1_1 = f2(a++ + --b, -3, b += a);
    function f3(yield_2) {
        switch (yield_2 = 0 === 1 ? a : b) {
          case a++ + ++a:
            try {
                {
                    var brake14 = 5;
                    do {
                        c = 1 + c, ("function" >>> -5 || (-1, /[a2][^e]+$/)) !== (a_2 && (a_2.Infinity += "object" < "undefined" >= null / -2));
                    } while ((c = 1 + c, (25 != -1 && delete 5) * void ("c" >= null)) && --brake14 > 0);
                }
            } catch (yield_2) {
                c = 1 + c, (("b" ^ 25) >= (bar_1_1 += 38..toString() > 23..toString())) >>> (yield_2 && (yield_2.then %= ("function" >= /[a2][^e]+$/) >> (2 & 2)));
                c = 1 + c, ("undefined" > "number" & "b" !== true) << (-5 - -1 >> -1 - false);
            } finally {
                c = 1 + c, (!/[a2][^e]+$/ | ("undefined" ?? 2)) === ("function" < [] && -NaN);
                c = 1 + c, "function" ** "number" >> ("" ^ "object") && /[a2][^e]+$/ >>> true ^ ([] ^ [ , 0 ][1]);
            }
            if (bar_1_1 = (c = 1 + c, undefined / 5 < (c = c + 1, -0) === Number(0xdeadn << 16n | 0xbeefn) * this / (24..toString() << ""))) {
                try {
                    c = 1 + c, (c = c + 1, -3) * ((bar_1 && (bar_1.value >>>= null / this)) < (/[a2][^e]+$/ | "object"));
                } finally {
                }
            } else {
            }
            break;

          case (c = c + 1) + (yield_2 && typeof yield_2.var == "function" && --_calls_ >= 0 && yield_2.var([ 3n ][0] > 2, typeof a == "function")):
            var bar_1_1_2;
            break;

          case (c = c + 1) + {} ? a++ : 1 === 1 ? a : b:
            {}
            break;

          case bar_1_1_2 && (bar_1_1_2[typeof f5 == "function" && --_calls_ >= 0 && f5((c = 1 + c, 
            (25 >> 1) * (-0 << "function") > (a_2 = (25 & Infinity) / (5 >= (-42n).toString()))), "object")] += ((NaN || undefined) == (a_2_1 = Infinity & -2)) >>> (bar_1_1_2 && (bar_1_1_2[a++ + (b = a)] ^= (c = c + 1, 
            []) ?? 38..toString() >= "undefined"))):
            {
                var a_2_2 = function f4(bar_1_1_2_2, bar_1_2) {
                    const b_2 = (c = 1 + c, 24..toString() % -1 << (4 > 24..toString()) ^ (-2 === "c") / (23..toString() - -1));
                }("foo");
            }
            break;
        }
        {
            return (c = c + 1) + b++;
        }
    }
    var b_1 = f3(void a, "undefined");
}

var yield_1 = f0(true);

console.log(null, a, b, c, Infinity, NaN, undefined);
```
```js
// uglified code
// (beautified)
var _calls_ = 10, a = 100, b = 10, c = 0;

function f0(a_2, a_2_1) {
    var bar_1 = function() {
        var b, brake1 = 5;
        do {} while ((c += 1) + b && 0 < --brake1);
        switch (--b + ("function" != typeof a_2)) {
          case a++ + void 0:
            break;

          case 3:
            c = 1 + c, a_2 && (a_2.next += !1), c = 1 + c, a_2_1 && (a_2_1.then **= (b && (b[c = 1 + c, 
            1] %= NaN)) < NaN);
            break;

          case (c += 1) + ("undefined" != typeof async_1):
            break;

          default:
            c = 1 + c, b && (b[c = 1 + c, ("a" != 38..toString()) * (4 - 38..toString()) >> ((a_2_1 && (a_2_1.get += !1)) > (a_2 && (a_2.set = -2 >> {})))] ^= (a_2 && --a_2[c = 1 + c, 
            (38..toString() !== (2 === [ , 0 ].length) === 5) + void 0]) ** !1);
        }
    }();
    --b, b += ++a, --b, c += 1, c += 1;
    !function(yield_2) {
        switch (b) {
          case a++ + ++a:
            try {
                c = 1 + c, a_2 && (a_2.Infinity += !0), c = 1 + c;
            } catch (yield_2) {
                c = 1 + c, 38..toString(), 23..toString(), b && (b.then %= 0), c = 1 + c;
            } finally {
                c = 1 + (c = 1 + c);
            }
            c = 1 + c, NaN < (c += 1, -0) === Number(0xdeadn << 16n | 0xbeefn) * this / (24..toString() << "") && (c = 1 + c, 
            c += 1, bar_1 && (bar_1.value >>>= null / this));
            break;

          case (c += 1) + (b && "function" == typeof yield_2.var && 0 <= --_calls_ && yield_2.var(2 < 3n, "function" == typeof a)):
            break;

          case (c += 1) + {} ? a++ : a:
            break;

          case void 0:
            c = 1 + c, 24..toString(), 24..toString(), 23..toString();
        }
        c += 1, b++;
    }(void 0);
}

var yield_1 = f0(!0);

console.log(null, a, b, c, 1 / 0, NaN, void 0);
```
```
original result:
null 105 111 8 Infinity NaN undefined

uglified result:
evalmachine.<anonymous>:1
var _calls_=10,a=100,b=10,c=0;function f0(a_2,a_2_1){var bar_1=function(){var b,brake1=5;do{}while((c+=1)+b&&0<--brake1);switch(--b+("function"!=typeof a_2)){case a+++void 0:break;case 3:c=1+c,a_2&&(a_2.next+=!1),c=1+c,a_2_1&&(a_2_1.then**=(b&&(b[c=1+c,1]%=NaN))<NaN);break;case(c+=1)+("undefined"!=typeof async_1):break;default:c=1+c,b&&(b[c=1+c,("a"!=38..toString())*(4-38..toString())>>((a_2_1&&(a_2_1.get+=!1))>(a_2&&(a_2.set=-2>>{})))]^=(a_2&&--a_2[c=1+c,(38..toString()!==(2===[,0].length)===5)+void 0])**!1)}}();--b,b+=++a,--b,c+=1,c+=1;!function(yield_2){switch(b){case a+++ ++a:try{c=1+c,a_2&&(a_2.Infinity+=!0),c=1+c}catch(yield_2){c=1+c,38..toString(),23..toString(),b&&(b.then%=0),c=1+c}finally{c=1+(c=1+c)}c=1+c,NaN<(c+=1,-0)===Number(0xdeadn<<16n|0xbeefn)*this/(24..toString()<<"")&&(c=1+c,c+=1,bar_1&&(bar_1.value>>>=null/this));break;case(c+=1)+(b&&"function"==typeof yield_2.var&&0<=--_calls_&&yield_2.var(2<3n,"function"==typeof a)):break;case(c+=1)+{}?a++:a:break;case void 0:c=1+c,24..toString(),24..toString(),23..toString()}c+=1,b++}(void 0)}var yield_1=f0(!0);console.log(null,a,b,c,1/0,NaN,void 0);
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                            ^

TypeError: Cannot read property 'var' of undefined
    at evalmachine.<anonymous>:1:893
    at f0 (evalmachine.<anonymous>:1:1056)
    at evalmachine.<anonymous>:1:1077
    at Script.runInContext (node:vm:141:12)
    at Object.runInContext (node:vm:292:6)
    at run_code_vm (/Users/runner/work/UglifyJS/UglifyJS/test/sandbox.js:257:12)
    at Object.exports.run_code (/Users/runner/work/UglifyJS/UglifyJS/test/sandbox.js:37:16)
    at run_code (/Users/runner/work/UglifyJS/UglifyJS/test/ufuzz/index.js:2043:20)
    at /Users/runner/work/UglifyJS/UglifyJS/test/ufuzz/index.js:2427:29
    at Array.forEach (<anonymous>)
```
```js
// reduced test case (output will differ)

// (beautified)
var a = 0, b = 0;

function f3(yield_2) {
    switch (yield_2 = b) {
      case ++a:
        try {
            brake14;
        } catch (yield_2) {
            yield_2.then;
        }

      case console.log(yield_2):
    }
}

f3(void 0);
// output: 0
// 
// minify: undefined
// 
// options: {
//   "mangle": false,
//   "output": {
//     "v8": true
//   },
//   "validate": true
// }
```
```
minify(options):
{
  "mangle": false,
  "output": {
    "v8": true
  }
}

Suspicious compress options:
  collapse_vars
  conditionals
  evaluate
```


Discussion:

Patch:
diff --git a/lib/compress.js b/lib/compress.js
index 21eec7c311d..911cf554398 100644
--- a/lib/compress.js
+++ b/lib/compress.js
@@ -1866,7 +1866,7 @@ merge(Compressor.prototype, {
                             return null;
                         }
                       default:
-                        return;
+                        return handle_custom_scan_order(node, multi_replacer);
                     }
                 }
                 // Replace variable when found


Test patch:
diff --git a/test/compress/collapse_vars.js b/test/compress/collapse_vars.js
index eaff0127cbc..fcc47391b2e 100644
--- a/test/compress/collapse_vars.js
+++ b/test/compress/collapse_vars.js
@@ -8897,3 +8897,38 @@ issue_4806: {
     }
     expect_stdout: "PASS"
 }
+
+issue_4852: {
+    options = {
+        collapse_vars: true,
+    }
+    input: {
+        var a = "PASS";
+        (function(b) {
+            switch (b = a) {
+              case 42:
+                try {
+                    console;
+                } catch (b) {
+                    b.p;
+                }
+              case console.log(b):
+            }
+        })("FAIL");
+    }
+    expect: {
+        var a = "PASS";
+        (function(b) {
+            switch (a) {
+              case 42:
+                try {
+                    console;
+                } catch (b) {
+                    b.p;
+                }
+              case console.log(a):
+            }
+        })("FAIL");
+    }
+    expect_stdout: "PASS"
+}