From: Alex Lam S.L Date: Thu, 6 Aug 2020 08:39:50 +0000 (+0100) Subject: fix corner cases in aliasing of global variables (#4039) X-Git-Url: https://git.ndcode.org/public/gitweb.cgi?a=commitdiff_plain;h=9b05494ebcbcc40a6682cf570aa183f045244650;p=UglifyJS.git fix corner cases in aliasing of global variables (#4039) fixes #4038 --- diff --git a/lib/compress.js b/lib/compress.js index 650a7634..7131e104 100644 --- a/lib/compress.js +++ b/lib/compress.js @@ -167,7 +167,7 @@ merge(Compressor.prototype, { if (def.global) for (var i = 0; i < def.orig.length; i++) if (!this.toplevel[def.orig[i] instanceof AST_SymbolDefun ? "funcs" : "vars"]) return true; - return false; + return def.undeclared; }, compress: function(node) { node = node.resolve_defines(this); @@ -1386,6 +1386,7 @@ 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 read_toplevel = false; var modify_toplevel = false; // Locate symbols which may execute code outside of scanning range var lvalues = get_lvalues(candidate); @@ -1548,8 +1549,10 @@ merge(Compressor.prototype, { return lvalues.has(node.name.name) || side_effects && may_modify(node.name); } var sym = is_lhs(node.left, node); - if (sym && lvalues.has(sym.name)) return true; - if (sym instanceof AST_PropAccess) return true; + if (!sym) return false; + return lvalues.has(sym.name) + || sym instanceof AST_PropAccess + || read_toplevel && compressor.exposed(sym.definition()); } function extract_args() { @@ -1936,26 +1939,43 @@ merge(Compressor.prototype, { }; } + function may_be_global(node) { + if (node instanceof AST_SymbolRef) { + node = node.fixed_value(); + if (!node) return true; + } + if (node instanceof AST_Assign) return node.operator == "=" && may_be_global(node.right); + return node instanceof AST_PropAccess || node instanceof AST_This; + } + function get_lvalues(expr) { var lvalues = new Dictionary(); - if (candidate instanceof AST_VarDef) lvalues.add(candidate.name.name, lhs); - var scan_iife = scope instanceof AST_Toplevel; + if (expr instanceof AST_VarDef) lvalues.add(expr.name.name, lhs); + var scan_toplevel = scope instanceof AST_Toplevel; var tw = new TreeWalker(function(node) { - if (scan_iife && node.TYPE == "Call") { - var exp = node.expression; - if (exp instanceof AST_PropAccess) return; - if (exp instanceof AST_Function && !exp.contains_this()) return; - modify_toplevel = true; - scan_iife = false; - return; - } var value; if (node instanceof AST_SymbolRef) { value = node.fixed_value() || node; } else if (node instanceof AST_This) { value = node; } - if (value) lvalues.add(node.name, is_modified(compressor, tw, node, value, 0)); + if (value) { + lvalues.add(node.name, is_modified(compressor, tw, node, value, 0)); + } else if (scan_toplevel) { + if (node.TYPE == "Call") { + if (modify_toplevel) return; + var exp = node.expression; + if (exp instanceof AST_PropAccess) return; + if (exp instanceof AST_Function && !exp.contains_this()) return; + modify_toplevel = true; + } else if (node instanceof AST_PropAccess && may_be_global(node.expression)) { + if (node === lhs && !(expr instanceof AST_Unary)) { + modify_toplevel = true; + } else { + read_toplevel = true; + } + } + } }); expr.walk(tw); return lvalues; diff --git a/test/compress/collapse_vars.js b/test/compress/collapse_vars.js index 109bbde0..d68c10e2 100644 --- a/test/compress/collapse_vars.js +++ b/test/compress/collapse_vars.js @@ -8317,3 +8317,61 @@ issue_4012: { } expect_stdout: "PASS" } + +global_assign: { + options = { + collapse_vars: true, + } + input: { + this.A = "FAIL"; + A = "PASS"; + B = "FAIL"; + console.log(A); + } + expect: { + this.A = "FAIL"; + A = "PASS"; + B = "FAIL"; + console.log(A); + } + expect_stdout: "PASS" +} + +global_read: { + options = { + collapse_vars: true, + } + input: { + var a = 0; + a = this.A; + A = 1; + a ? console.log("FAIL") : console.log("PASS"); + } + expect: { + var a = 0; + a = this.A; + A = 1; + a ? console.log("FAIL") : console.log("PASS"); + } + expect_stdout: "PASS" +} + +issue_4038: { + options = { + collapse_vars: true, + } + input: { + var a = 0; + a = this; + a = a.A; + A = 1; + a ? console.log("FAIL") : console.log("PASS"); + } + expect: { + var a = 0; + a = (a = this).A; + A = 1; + a ? console.log("FAIL") : console.log("PASS"); + } + expect_stdout: "PASS" +} diff --git a/test/compress/reduce_vars.js b/test/compress/reduce_vars.js index 85969f90..77782cfd 100644 --- a/test/compress/reduce_vars.js +++ b/test/compress/reduce_vars.js @@ -7402,7 +7402,27 @@ issue_4030: { } expect: { A = "PASS"; - console.log("PASS"); + console.log(A); + } + expect_stdout: "PASS" +} + +global_assign: { + options = { + evaluate: true, + reduce_vars: true, + toplevel: true, + unused: true, + } + input: { + A = "FAIL"; + this.A = "PASS"; + console.log(A); + } + expect: { + A = "FAIL"; + this.A = "PASS"; + console.log(A); } expect_stdout: "PASS" } diff --git a/test/ufuzz/index.js b/test/ufuzz/index.js index 1123d57e..9e8ca8dc 100644 --- a/test/ufuzz/index.js +++ b/test/ufuzz/index.js @@ -1175,7 +1175,8 @@ function log(options) { } function sort_globals(code) { - return "var " + sandbox.run_code("throw Object.keys(this).sort();" + code).join(",") + ";" + code; + var globals = sandbox.run_code("throw Object.keys(this).sort();" + code); + return globals.length ? "var " + globals.join(",") + ";" + code : code; } function fuzzy_match(original, uglified) {