Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(es/minifier): Abort IIFE invoker on eval #6478

Merged
merged 64 commits into from Dec 13, 2022
Merged
Show file tree
Hide file tree
Changes from 61 commits
Commits
Show all changes
64 commits
Select commit Hold shift + click to select a range
31a0dcd
Add tests
kdy1 Nov 18, 2022
49c810c
config.json: Correct
kdy1 Nov 18, 2022
bfe8bc4
Store correct output
kdy1 Nov 18, 2022
98e2454
config.json: Enable inline
kdy1 Nov 18, 2022
9160518
Remove needless
kdy1 Nov 18, 2022
9bf3be4
Remove needless
kdy1 Nov 18, 2022
07b7690
Remove trivial
kdy1 Nov 18, 2022
b651771
fmt
kdy1 Dec 5, 2022
5d075cc
fmt
kdy1 Dec 5, 2022
1a4b7cd
Update test refs (without buggy code)
kdy1 Dec 5, 2022
11e403b
Update test refs (correct)
kdy1 Dec 8, 2022
8054283
Remove
kdy1 Dec 8, 2022
207d90a
Remove
kdy1 Dec 8, 2022
a381c64
Remove
kdy1 Dec 8, 2022
fc5f698
Remove
kdy1 Dec 8, 2022
509c12b
Update test refs (working)
kdy1 Dec 8, 2022
236c824
fmt input
kdy1 Dec 8, 2022
224a301
Reduce
kdy1 Dec 8, 2022
019ae63
Reduce
kdy1 Dec 8, 2022
45142df
Reduce
kdy1 Dec 8, 2022
de086a9
Reduce
kdy1 Dec 8, 2022
9f3556d
Reduce
kdy1 Dec 8, 2022
7f216f5
Reduce
kdy1 Dec 8, 2022
d742e75
Reduce
kdy1 Dec 8, 2022
3cf92c1
Reduce
kdy1 Dec 8, 2022
6695c1f
Reduce
kdy1 Dec 8, 2022
fd6ec3c
Reduce
kdy1 Dec 8, 2022
48e8435
Reduce
kdy1 Dec 8, 2022
f2fc815
Reduce
kdy1 Dec 8, 2022
e513cb7
Reduce
kdy1 Dec 8, 2022
626aa73
Reduce
kdy1 Dec 8, 2022
812dcb4
Reduce
kdy1 Dec 8, 2022
8024a78
Reduce
kdy1 Dec 8, 2022
00f485b
Reduce
kdy1 Dec 8, 2022
c60e914
Reduce
kdy1 Dec 8, 2022
3fdb71e
Reduce
kdy1 Dec 8, 2022
b6c9652
Reduce
kdy1 Dec 8, 2022
4a728f7
Reduce
kdy1 Dec 8, 2022
068829c
Reduce
kdy1 Dec 8, 2022
d1f7667
Reduce
kdy1 Dec 8, 2022
ed708c2
Reduce
kdy1 Dec 8, 2022
e919122
Reduce
kdy1 Dec 8, 2022
b9579a0
fmt
kdy1 Dec 8, 2022
d2d4bab
Reduce input
kdy1 Dec 8, 2022
a925e49
Reduce input
kdy1 Dec 8, 2022
04f2417
Remove
kdy1 Dec 8, 2022
edfe4a5
Reduce input
kdy1 Dec 8, 2022
d6b2d7a
Reduce input
kdy1 Dec 8, 2022
0a6d5a4
Move
kdy1 Dec 8, 2022
b6366e6
Fix
kdy1 Dec 8, 2022
0ce8377
Update test refs
kdy1 Dec 8, 2022
27c6925
Update test refs
kdy1 Dec 8, 2022
9e1d73a
Reduce
kdy1 Dec 9, 2022
fb4f43e
Reduce
kdy1 Dec 9, 2022
bd907d7
Reduce
kdy1 Dec 9, 2022
84ce4a5
Reduce
kdy1 Dec 9, 2022
9e85f0d
Reduce
kdy1 Dec 9, 2022
5f5ab01
Update test refs
kdy1 Dec 9, 2022
150e2f7
Add mangle.json
kdy1 Dec 9, 2022
bb28f34
Ensure mangler
kdy1 Dec 9, 2022
ce6e0c7
Update test refs
kdy1 Dec 9, 2022
ac7dcb6
abort on eval
kdy1 Dec 12, 2022
7b695ba
Update test refs
kdy1 Dec 12, 2022
3e2cdf1
Merge branch 'main' into bug1
swc-bot Dec 13, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
13 changes: 12 additions & 1 deletion crates/swc_ecma_minifier/src/compress/optimize/iife.rs
Expand Up @@ -15,7 +15,7 @@ use crate::debug::dump;
use crate::{
compress::optimize::{util::Remapper, Ctx},
mode::Mode,
util::{idents_captured_by, idents_used_by, make_number},
util::{contains_eval, idents_captured_by, idents_used_by, make_number},
};

/// Methods related to the option `negate_iife`.
Expand Down Expand Up @@ -728,6 +728,13 @@ where
}
}

// If we has an eval, we cannot remap variables correctly.
let has_eval = contains_eval(body, false);
if !param_ids.is_empty() && has_eval {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm kinda surprised we allow any further modifications in the presence of eval.

Copy link
Member Author

@kdy1 kdy1 Dec 9, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

eval is used by some libraries, so I thought we should only give up if it's going to be problematic. (e.g. name mangler aborts)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But I'm not sure about this. Do you think it's better to abort completely on eval?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Personally, yah, I would. Looking at terser, eval deopts:

  • name mangling
  • unused var removal
  • joining of expressions
  • inlining functions
  • conversion from functions/methods to arrows

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Did it and checked other passes, too. Thank you!

log_abort!("iife: [x] Aborting because of eval");
return false;
}

if self.ctx.executed_multiple_time {
if !param_ids.is_empty() {
let captured = idents_captured_by(body);
Expand All @@ -754,6 +761,10 @@ where
}
) =>
{
if has_eval {
return false;
}

if var.decls.iter().any(|decl| match &decl.name {
Pat::Ident(BindingIdent {
id:
Expand Down
@@ -0,0 +1,6 @@
{
"defaults": false,
"toplevel": true,
"passes": 2,
"inline": true
}
37 changes: 37 additions & 0 deletions crates/swc_ecma_minifier/tests/fixture/next/43052/input.js
@@ -0,0 +1,37 @@
use((function (__unused_webpack_module, exports, __webpack_require__) {
! function (e, t) {
true ? t(exports, __webpack_require__(7294), __webpack_require__(1321)) : 0
}(this, (function (exports, React) {
"use strict";

var index_production = {
exports: {}
};
(function (module, exports) {
var t;
t = function (exports) {
function inquire(moduleName) {
try {
var mod = eval("quire".replace(/^/, "re"))(moduleName);
if (mod && (mod.length || Object.keys(mod).length)) return mod
} catch (e) { }
return null
}

Object.defineProperty(exports, "__esModule", {
value: !0
})
}, t(exports)
})(index_production, index_production.exports);

exports.chunkBlocks = index_production.exports.chunkBlocks, exports.encodeDirectory = index_production.exports.encodeDirectory, exports.encodeFile = index_production.exports.encodeFile, Object.defineProperty(exports, "__esModule", {
value: !0
})
}));
}));


(function checkMangler() {
const longName = 1;
use(longName)
})
@@ -0,0 +1 @@
{}
31 changes: 31 additions & 0 deletions crates/swc_ecma_minifier/tests/fixture/next/43052/output.js
@@ -0,0 +1,31 @@
use(function(__unused_webpack_module, exports, __webpack_require__) {
var e, t;
e = this, t = function(exports, React) {
"use strict";
var index_production = {
exports: {}
};
(function(module, exports) {
var t;
t = function(exports) {
function inquire(moduleName) {
try {
var mod = eval("quire".replace(/^/, "re"))(moduleName);
if (mod && (mod.length || Object.keys(mod).length)) return mod;
} catch (e) {}
return null;
}
Object.defineProperty(exports, "__esModule", {
value: !0
});
}, t(exports);
})(index_production, index_production.exports);
exports.chunkBlocks = index_production.exports.chunkBlocks, exports.encodeDirectory = index_production.exports.encodeDirectory, exports.encodeFile = index_production.exports.encodeFile, Object.defineProperty(exports, "__esModule", {
value: !0
});
}, t(exports, __webpack_require__(7294), __webpack_require__(1321)), true;
});
(function e() {
const e = 1;
use(e);
});
219 changes: 112 additions & 107 deletions crates/swc_ecma_minifier/tests/fixture/next/wrap-contracts/output.js
Expand Up @@ -17556,115 +17556,120 @@
}();
},
1951: function(module) {
var __webpack_modules__, __webpack_exports__, __dirname = "/";
__webpack_modules__ = {
965: function(__unused_webpack_module, exports) {
var indexOf = function(e, t) {
if (e.indexOf) return e.indexOf(t);
for(var r = 0; r < e.length; r++)if (e[r] === t) return r;
return -1;
}, Object_keys = function(e) {
if (Object.keys) return Object.keys(e);
var t = [];
for(var r in e)t.push(r);
return t;
}, forEach = function(e, t) {
if (e.forEach) return e.forEach(t);
for(var r = 0; r < e.length; r++)t(e[r], r, e);
}, defineProp = function() {
try {
return Object.defineProperty({}, "_", {}), function(e, t, r) {
Object.defineProperty(e, t, {
writable: !0,
enumerable: !1,
configurable: !0,
value: r
});
};
} catch (e) {
return function(e, t, r) {
e[t] = r;
var __dirname = "/";
!function() {
var __webpack_modules__ = {
965: function(__unused_webpack_module, exports) {
var indexOf = function(e, t) {
if (e.indexOf) return e.indexOf(t);
for(var r = 0; r < e.length; r++)if (e[r] === t) return r;
return -1;
}, Object_keys = function(e) {
if (Object.keys) return Object.keys(e);
var t = [];
for(var r in e)t.push(r);
return t;
}, forEach = function(e, t) {
if (e.forEach) return e.forEach(t);
for(var r = 0; r < e.length; r++)t(e[r], r, e);
}, defineProp = function() {
try {
return Object.defineProperty({}, "_", {}), function(e, t, r) {
Object.defineProperty(e, t, {
writable: !0,
enumerable: !1,
configurable: !0,
value: r
});
};
} catch (e) {
return function(e, t, r) {
e[t] = r;
};
}
}(), globals = [
"Array",
"Boolean",
"Date",
"Error",
"EvalError",
"Function",
"Infinity",
"JSON",
"Math",
"NaN",
"Number",
"Object",
"RangeError",
"ReferenceError",
"RegExp",
"String",
"SyntaxError",
"TypeError",
"URIError",
"decodeURI",
"decodeURIComponent",
"encodeURI",
"encodeURIComponent",
"escape",
"eval",
"isFinite",
"isNaN",
"parseFloat",
"parseInt",
"undefined",
"unescape"
];
function Context() {}
Context.prototype = {};
var Script = exports.Script = function(e) {
if (!(this instanceof Script)) return new Script(e);
this.code = e;
};
Script.prototype.runInContext = function(e) {
if (!(e instanceof Context)) throw TypeError("needs a 'context' argument.");
var t = document.createElement("iframe");
t.style || (t.style = {}), t.style.display = "none", document.body.appendChild(t);
var r = t.contentWindow, n = r.eval, o = r.execScript;
!n && o && (o.call(r, "null"), n = r.eval), forEach(Object_keys(e), function(t) {
r[t] = e[t];
}), forEach(globals, function(t) {
e[t] && (r[t] = e[t]);
});
var c = Object_keys(r), i = n.call(r, this.code);
return forEach(Object_keys(r), function(t) {
(t in e || -1 === indexOf(c, t)) && (e[t] = r[t]);
}), forEach(globals, function(t) {
t in e || defineProp(e, t, r[t]);
}), document.body.removeChild(t), i;
}, Script.prototype.runInThisContext = function() {
return eval(this.code);
}, Script.prototype.runInNewContext = function(e) {
var t = Script.createContext(e), r = this.runInContext(t);
return e && forEach(Object_keys(t), function(r) {
e[r] = t[r];
}), r;
}, forEach(Object_keys(Script.prototype), function(e) {
exports[e] = Script[e] = function(t) {
var r = Script(t);
return r[e].apply(r, [].slice.call(arguments, 1));
};
}
}(), globals = [
"Array",
"Boolean",
"Date",
"Error",
"EvalError",
"Function",
"Infinity",
"JSON",
"Math",
"NaN",
"Number",
"Object",
"RangeError",
"ReferenceError",
"RegExp",
"String",
"SyntaxError",
"TypeError",
"URIError",
"decodeURI",
"decodeURIComponent",
"encodeURI",
"encodeURIComponent",
"escape",
"eval",
"isFinite",
"isNaN",
"parseFloat",
"parseInt",
"undefined",
"unescape"
];
function Context() {}
Context.prototype = {};
var Script = exports.Script = function(e) {
if (!(this instanceof Script)) return new Script(e);
this.code = e;
};
Script.prototype.runInContext = function(e) {
if (!(e instanceof Context)) throw TypeError("needs a 'context' argument.");
var t = document.createElement("iframe");
t.style || (t.style = {}), t.style.display = "none", document.body.appendChild(t);
var r = t.contentWindow, n = r.eval, o = r.execScript;
!n && o && (o.call(r, "null"), n = r.eval), forEach(Object_keys(e), function(t) {
r[t] = e[t];
}), forEach(globals, function(t) {
e[t] && (r[t] = e[t]);
});
var c = Object_keys(r), i = n.call(r, this.code);
return forEach(Object_keys(r), function(t) {
(t in e || -1 === indexOf(c, t)) && (e[t] = r[t]);
}), forEach(globals, function(t) {
t in e || defineProp(e, t, r[t]);
}), document.body.removeChild(t), i;
}, Script.prototype.runInThisContext = function() {
return eval(this.code);
}, Script.prototype.runInNewContext = function(e) {
var t = Script.createContext(e), r = this.runInContext(t);
return e && forEach(Object_keys(t), function(r) {
e[r] = t[r];
}), r;
}, forEach(Object_keys(Script.prototype), function(e) {
exports[e] = Script[e] = function(t) {
var r = Script(t);
return r[e].apply(r, [].slice.call(arguments, 1));
}), exports.isContext = function(e) {
return e instanceof Context;
}, exports.createScript = function(e) {
return exports.Script(e);
}, exports.createContext = Script.createContext = function(e) {
var t = new Context;
return "object" == typeof e && forEach(Object_keys(e), function(r) {
t[r] = e[r];
}), t;
};
}), exports.isContext = function(e) {
return e instanceof Context;
}, exports.createScript = function(e) {
return exports.Script(e);
}, exports.createContext = Script.createContext = function(e) {
var t = new Context;
return "object" == typeof e && forEach(Object_keys(e), function(r) {
t[r] = e[r];
}), t;
};
}
}, "undefined" != typeof __nccwpck_require__ && (__nccwpck_require__.ab = __dirname + "/"), __webpack_exports__ = {}, __webpack_modules__[965](0, __webpack_exports__), module.exports = __webpack_exports__;
}
};
"undefined" != typeof __nccwpck_require__ && (__nccwpck_require__.ab = __dirname + "/");
var __webpack_exports__ = {};
__webpack_modules__[965](0, __webpack_exports__), module.exports = __webpack_exports__;
}();
},
4375: function(module, __unused_webpack_exports, __webpack_require__) {
let promise;
Expand Down