whitelist `unsafe` `evaluate` candidates (#2039)
authorAlex Lam S.L <alexlamsl@gmail.com>
Wed, 31 May 2017 20:33:05 +0000 (04:33 +0800)
committerGitHub <noreply@github.com>
Wed, 31 May 2017 20:33:05 +0000 (04:33 +0800)
- all arguments may accept constant values
- return constant value
- free of side effects
- available & identical across locales and runtime environments

lib/compress.js
test/compress/evaluate.js

index a928d7b..71cffce 100644 (file)
@@ -1665,6 +1665,44 @@ merge(Compressor.prototype, {
             }
             throw def;
         });
+        var object_fns = [
+            'constructor',
+            'toString',
+            'valueOf',
+        ];
+        var native_fns = {
+            Array: makePredicate([
+                'indexOf',
+                'join',
+                'lastIndexOf',
+                'slice',
+            ].concat(object_fns)),
+            Boolean: makePredicate(object_fns),
+            Number: makePredicate([
+                'toExponential',
+                'toFixed',
+                'toPrecision',
+            ].concat(object_fns)),
+            RegExp: makePredicate([
+                'test',
+            ].concat(object_fns)),
+            String: makePredicate([
+                'charAt',
+                'charCodeAt',
+                'concat',
+                'indexOf',
+                'italics',
+                'lastIndexOf',
+                'match',
+                'replace',
+                'search',
+                'slice',
+                'split',
+                'substr',
+                'substring',
+                'trim',
+            ].concat(object_fns)),
+        };
         def(AST_Call, function(compressor){
             var exp = this.expression;
             if (compressor.option("unsafe") && exp instanceof AST_PropAccess) {
@@ -1673,9 +1711,8 @@ merge(Compressor.prototype, {
                     key = ev(key, compressor);
                 }
                 var val = ev(exp.expression, compressor);
-                var fn = val[key];
-                if (typeof fn == "function") {
-                    return fn.apply(val, this.args.map(function(arg) {
+                if ((val && native_fns[val.constructor.name] || return_false)(key)) {
+                    return val[key].apply(val, this.args.map(function(arg) {
                         return ev(arg, compressor);
                     }));
                 }
index 020d7cf..99245d0 100644 (file)
@@ -780,13 +780,15 @@ unsafe_charAt_noop: {
     input: {
         console.log(
             s.charAt(0),
-            "string".charAt(x)
+            "string".charAt(x),
+            (typeof x).charAt()
         );
     }
     expect: {
         console.log(
             s.charAt(0),
-            "string".charAt(x)
+            "string".charAt(x),
+            (typeof x)[0]
         );
     }
 }