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 completely on eval #6659

Merged
merged 12 commits into from Dec 15, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
8 changes: 6 additions & 2 deletions 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::{contains_eval, idents_captured_by, idents_used_by, make_number},
util::{idents_captured_by, idents_used_by, make_number},
};

/// Methods related to the option `negate_iife`.
Expand Down Expand Up @@ -730,7 +730,11 @@ where

// Abort on eval.
// See https://github.com/swc-project/swc/pull/6478
if contains_eval(body, false) {
//
// We completetly abort on eval, because we cannot know whether a variable in
// upper scope will be afftected by eval.
// https://github.com/swc-project/swc/issues/6628
if self.data.top.has_eval_call {
log_abort!("iife: [x] Aborting because of eval");
return false;
}
Expand Down
18 changes: 18 additions & 0 deletions crates/swc_ecma_minifier/tests/fixture/issues/6628/input.js
@@ -0,0 +1,18 @@
(function () {
var Collector = function () {
var e = function e(e) { };
return e.usePlugin = function (t, i, n) {

}, e.plugins = [], e;
}();
var CallbackType;
!function (e) {
e[e.Var = 0] = "Var", e[e.All = 1] = "All";
}(CallbackType || (CallbackType = {}));
var CepRule = function () {
eval();
}();
Collector.usePlugin(CepRule, "cep");

exports.Collector = Collector;
})()
@@ -0,0 +1 @@
{}
13 changes: 13 additions & 0 deletions crates/swc_ecma_minifier/tests/fixture/issues/6628/output.js
@@ -0,0 +1,13 @@
!function() {
Copy link
Member Author

Choose a reason for hiding this comment

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

Previous: SWC playground

var CallbackType, Collector = function() {
var n = function(n) {};
return n.usePlugin = function(n, u, l) {}, n.plugins = [], n;
}();
!function(n) {
n[n.Var = 0] = "Var", n[n.All = 1] = "All";
}(CallbackType || (CallbackType = {}));
var CepRule = function() {
eval();
}();
Collector.usePlugin(CepRule, "cep"), exports.Collector = Collector;
}();
7 changes: 4 additions & 3 deletions crates/swc_ecma_minifier/tests/fixture/next/43052/output.js
@@ -1,6 +1,7 @@
use(function(__unused_webpack_module, exports, __webpack_require__) {
var e, t;
e = this, t = function(exports, React) {
!function(e, t) {
t(exports, __webpack_require__(7294), __webpack_require__(1321));
}(this, function(exports, React) {
"use strict";
var index_production = {
exports: {}
Expand All @@ -23,7 +24,7 @@ use(function(__unused_webpack_module, exports, __webpack_require__) {
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;
Expand Down

Large diffs are not rendered by default.

554 changes: 293 additions & 261 deletions crates/swc_ecma_minifier/tests/fixture/next/wrap-contracts/output.js

Large diffs are not rendered by default.

177 changes: 95 additions & 82 deletions crates/swc_ecma_minifier/tests/projects/output/mootools-1.4.5.js
Expand Up @@ -449,7 +449,7 @@
return array ? hex : "#" + hex.join("");
}
}), Array.alias("extend", "append");
var fireEvent, $pick = function() {
var $pick = function() {
return Array.from(arguments).pick();
};
String.implement({
Expand Down Expand Up @@ -743,7 +743,7 @@ var $try = Function.attempt;
indexOf: "keyOf",
contains: "hasValue"
}), function() {
var XMLHTTP, MSXML2, MSXML, document1 = this.document, window1 = document1.window = this, ua = navigator.userAgent.toLowerCase(), platform = navigator.platform.toLowerCase(), UA = ua.match(/(opera|ie|firefox|chrome|version)[\s\/:]([\w\d\.]+)?.*?(safari|version[\s\/:]([\w\d\.]+)|$)/) || [
var document1 = this.document, window1 = document1.window = this, ua = navigator.userAgent.toLowerCase(), platform = navigator.platform.toLowerCase(), UA = ua.match(/(opera|ie|firefox|chrome|version)[\s\/:]([\w\d\.]+)?.*?(safari|version[\s\/:]([\w\d\.]+)|$)/) || [
null,
"unknown",
0
Expand All @@ -764,19 +764,22 @@ var $try = Function.attempt;
},
Plugins: {}
};
Browser1[Browser1.name] = !0, Browser1[Browser1.name + parseInt(Browser1.version, 10)] = !0, Browser1.Platform[Browser1.Platform.name] = !0, Browser1.Request = (XMLHTTP = function() {
return new XMLHttpRequest();
}, MSXML2 = function() {
return new ActiveXObject("MSXML2.XMLHTTP");
}, MSXML = function() {
return new ActiveXObject("Microsoft.XMLHTTP");
}, Function.attempt(function() {
return XMLHTTP(), XMLHTTP;
}, function() {
return MSXML2(), MSXML2;
}, function() {
return MSXML(), MSXML;
})), Browser1.Features.xhr = !!Browser1.Request;
Browser1[Browser1.name] = !0, Browser1[Browser1.name + parseInt(Browser1.version, 10)] = !0, Browser1.Platform[Browser1.Platform.name] = !0, Browser1.Request = function() {
var XMLHTTP = function() {
return new XMLHttpRequest();
}, MSXML2 = function() {
return new ActiveXObject("MSXML2.XMLHTTP");
}, MSXML = function() {
return new ActiveXObject("Microsoft.XMLHTTP");
};
return Function.attempt(function() {
return XMLHTTP(), XMLHTTP;
}, function() {
return MSXML2(), MSXML2;
}, function() {
return MSXML(), MSXML;
});
}(), Browser1.Features.xhr = !!Browser1.Request;
var version = (Function.attempt(function() {
return navigator.plugins["Shockwave Flash"].description;
}, function() {
Expand Down Expand Up @@ -1683,9 +1686,11 @@ var Element = function(tag, props) {
}
return document.newElement(tag, props);
};
Browser.Element && (Element.prototype = Browser.Element.prototype, Element.prototype._fireEvent = (fireEvent = Element.prototype.fireEvent, function(type, event) {
return fireEvent.call(this, type, event);
})), new Type("Element", Element).mirror(function(name) {
Browser.Element && (Element.prototype = Browser.Element.prototype, Element.prototype._fireEvent = function(fireEvent) {
return function(type, event) {
return fireEvent.call(this, type, event);
};
}(Element.prototype.fireEvent)), new Type("Element", Element).mirror(function(name) {
if (!Array.prototype[name]) {
var obj = {};
obj[name] = function() {
Expand Down Expand Up @@ -1797,29 +1802,32 @@ Elements.prototype = {
getWindow: function() {
return this.window;
},
id: ((types = {
string: function(id, nocash, doc) {
return (id = Slick.find(doc, "#" + id.replace(/(\W)/g, "\\$1"))) ? types.element(id, nocash) : null;
},
element: function(el, nocash) {
if (Slick.uidOf(el), !nocash && !el.$family && !/^(?:object|embed)$/i.test(el.tagName)) {
var fireEvent = el.fireEvent;
el._fireEvent = function(type, event) {
return fireEvent(type, event);
}, Object.append(el, Element.Prototype);
id: function() {
var types = {
string: function(id, nocash, doc) {
return (id = Slick.find(doc, "#" + id.replace(/(\W)/g, "\\$1"))) ? types.element(id, nocash) : null;
},
element: function(el, nocash) {
if (Slick.uidOf(el), !nocash && !el.$family && !/^(?:object|embed)$/i.test(el.tagName)) {
var fireEvent = el.fireEvent;
el._fireEvent = function(type, event) {
return fireEvent(type, event);
}, Object.append(el, Element.Prototype);
}
return el;
},
object: function(obj, nocash, doc) {
return obj.toElement ? types.element(obj.toElement(doc), nocash) : null;
}
return el;
},
object: function(obj, nocash, doc) {
return obj.toElement ? types.element(obj.toElement(doc), nocash) : null;
}
}).textnode = types.whitespace = types.window = types.document = function(zero) {
return zero;
}, function(el, nocash, doc) {
if (el && el.$family && el.uniqueNumber) return el;
var type = typeOf(el);
return types[type] ? types[type](el, nocash, doc || document) : null;
})
};
return types.textnode = types.whitespace = types.window = types.document = function(zero) {
return zero;
}, function(el, nocash, doc) {
if (el && el.$family && el.uniqueNumber) return el;
var type = typeOf(el);
return types[type] ? types[type](el, nocash, doc || document) : null;
};
}()
}), null == window.$ && Window.implement("$", function(el, nc) {
return document.id(el, nc, this.document);
}), Window.implement({
Expand All @@ -1840,7 +1848,7 @@ Elements.prototype = {
return document.id(Slick.find(this, expression));
}
});
var types, div, set, translations, contains = {
var contains = {
contains: function(element) {
return Slick.contains(this, element);
}
Expand Down Expand Up @@ -2024,7 +2032,9 @@ Elements.prototype = {
var value = node.value;
node.type = type, node.value = value;
}), input = null;
var pollutesGetAttribute = ((div = document.createElement("div")).random = "attribute", "attribute" == div.getAttribute("random"));
var pollutesGetAttribute = function(div) {
return div.random = "attribute", "attribute" == div.getAttribute("random");
}(document.createElement("div"));
Element.implement({
setProperty: function(name, value) {
var setter = propertySetters[name.toLowerCase()];
Expand Down Expand Up @@ -2222,52 +2232,55 @@ Elements.prototype = {
this.innerHTML = "";
}
};
var div1 = document.createElement("div");
div1.innerHTML = "<nav></nav>";
var supportsHTML5Elements = 1 == div1.childNodes.length;
var div = document.createElement("div");
div.innerHTML = "<nav></nav>";
var supportsHTML5Elements = 1 == div.childNodes.length;
if (!supportsHTML5Elements) for(var tags = "abbr article aside audio canvas datalist details figcaption figure footer header hgroup mark meter nav output progress section summary time video".split(" "), fragment = document.createDocumentFragment(), l = tags.length; l--;)fragment.createElement(tags[l]);
div1 = null;
div = null;
var supportsTableInnerHTML = Function.attempt(function() {
return document.createElement("table").innerHTML = "<tr><td></td></tr>", !0;
}), tr = document.createElement("tr"), html = "<td></td>";
tr.innerHTML = html;
var supportsTRInnerHTML = tr.innerHTML == html;
tr = null, (!supportsTableInnerHTML || !supportsTRInnerHTML || !supportsHTML5Elements) && (Element.Properties.html.set = (set = Element.Properties.html.set, (translations = {
table: [
1,
"<table>",
"</table>"
],
select: [
1,
"<select>",
"</select>"
],
tbody: [
2,
"<table><tbody>",
"</tbody></table>"
],
tr: [
3,
"<table><tbody><tr>",
"</tr></tbody></table>"
]
}).thead = translations.tfoot = translations.tbody, function(html) {
var wrap = translations[this.get("tag")];
if (wrap || supportsHTML5Elements || (wrap = [
0,
"",
""
]), !wrap) return set.call(this, html);
var level = wrap[0], wrapper = document.createElement("div"), target = wrapper;
for(supportsHTML5Elements || fragment.appendChild(wrapper), wrapper.innerHTML = [
wrap[1],
html,
wrap[2]
].flatten().join(""); level--;)target = target.firstChild;
this.empty().adopt(target.childNodes), supportsHTML5Elements || fragment.removeChild(wrapper), wrapper = null;
}));
tr = null, supportsTableInnerHTML && supportsTRInnerHTML && supportsHTML5Elements || (Element.Properties.html.set = function(set) {
var translations = {
table: [
1,
"<table>",
"</table>"
],
select: [
1,
"<select>",
"</select>"
],
tbody: [
2,
"<table><tbody>",
"</tbody></table>"
],
tr: [
3,
"<table><tbody><tr>",
"</tr></tbody></table>"
]
};
return translations.thead = translations.tfoot = translations.tbody, function(html) {
var wrap = translations[this.get("tag")];
if (wrap || supportsHTML5Elements || (wrap = [
0,
"",
""
]), !wrap) return set.call(this, html);
var level = wrap[0], wrapper = document.createElement("div"), target = wrapper;
for(supportsHTML5Elements || fragment.appendChild(wrapper), wrapper.innerHTML = [
wrap[1],
html,
wrap[2]
].flatten().join(""); level--;)target = target.firstChild;
this.empty().adopt(target.childNodes), supportsHTML5Elements || fragment.removeChild(wrapper), wrapper = null;
};
}(Element.Properties.html.set));
var testForm = document.createElement("form");
testForm.innerHTML = "<select><option>s</option></select>", "s" != testForm.firstChild.value && (Element.Properties.value = {
set: function(value) {
Expand Down