suppress `ufuzz` false positives (#3893)
authorAlex Lam S.L <alexlamsl@gmail.com>
Tue, 12 May 2020 23:07:49 +0000 (00:07 +0100)
committerGitHub <noreply@github.com>
Tue, 12 May 2020 23:07:49 +0000 (07:07 +0800)
test/ufuzz/index.js

index f8c6555..1ade4fc 100644 (file)
@@ -1136,6 +1136,37 @@ function fuzzy_match(original, uglified) {
     return true;
 }
 
+function skip_infinite_recursion(orig, toplevel) {
+    var code = orig;
+    var tries = [];
+    var offset = 0;
+    var re = /(?:(?:^|[\s{};])try|}\s*catch\s*\(([^)]+)\)|}\s*finally)\s*(?={)/g;
+    var match;
+    while (match = re.exec(code)) {
+        if (/}\s*finally\s*$/.test(match[0])) {
+            tries.shift();
+            continue;
+        }
+        if (tries.length && tries[0].catch) tries.shift();
+        var index = match.index + match[0].length + 1;
+        if (/(?:^|[\s{};])try\s*$/.test(match[0])) {
+            tries.unshift({ try: index - offset });
+            continue;
+        }
+        tries[0].catch = index;
+        var insert = "throw " + match[1] + ".ufuzz_skip || (" + match[1] + ".ufuzz_skip = " + tries[0].try + "), " + match[1] + ";";
+        var new_code = code.slice(0, index) + insert + code.slice(index);
+        var result = sandbox.run_code(new_code, toplevel);
+        if (typeof result != "object" || typeof result.name != "string" || typeof result.message != "string") {
+            offset += insert.length;
+            code = new_code;
+        } else if (result.name == "RangeError" && result.message == "Maximum call stack size exceeded") {
+            index = result.ufuzz_skip;
+            return orig.slice(0, index) + 'throw new Error("skipping infinite recursion");' + orig.slice(index);
+        }
+    }
+}
+
 var fallback_options = [ JSON.stringify({
     compress: false,
     mangle: false
@@ -1180,6 +1211,14 @@ for (var round = 1; round <= num_iterations; round++) {
                     ok = sandbox.same_stdout(fuzzy_result, uglify_result);
                 }
             }
+            // ignore difference in depth of termination caused by infinite recursion
+            if (!ok) {
+                var orig_skipped = skip_infinite_recursion(original_code, toplevel);
+                var uglify_skipped = skip_infinite_recursion(uglify_code, toplevel);
+                if (orig_skipped && uglify_skipped) {
+                    ok = sandbox.same_stdout(sandbox.run_code(orig_skipped, toplevel), sandbox.run_code(uglify_skipped, toplevel));
+                }
+            }
         } else {
             uglify_code = uglify_code.error;
             ok = errored && uglify_code.name == original_result.name;