Commit 0ffc1ba5 authored by Michael Achenbach's avatar Michael Achenbach Committed by V8 LUCI CQ

[js-fuzzer] Make db more robust to failing code fragments.

Until now, the cross-over mutator would choke on several expressions
from DB and bail out (just wastes some time). We also have a script,
test_db.js to test on how many expressions it is going to bail out.

With this change, we already omit adding such expressions to the
DB in the first place. As a result, the test_db script now returns
zero failing expressions (while all other expressions remain).

Regression tests that now no longer apply are removed, instead a
test is added that ensures that a failing expression isn't added
to the DB.

No-Try: true
Bug: chromium:1044942
Change-Id: I14a4fe802c99114cf3a8f71188273475a7cb9c13
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3129340Reviewed-by: 's avatarLiviu Rau <liviurau@chromium.org>
Commit-Queue: Michael Achenbach <machenbach@chromium.org>
Cr-Commit-Position: refs/heads/main@{#76598}
parent 797e4afe
......@@ -34,7 +34,6 @@ function main() {
}
const mutateDb = new db.MutateDbWriter(program.output_dir);
const expressions = new Set();
const inputDir = path.resolve(program.input_dir);
for (const corpusName of program.args) {
......@@ -53,7 +52,7 @@ function main() {
}
try{
mutateDb.process(source, expressions);
mutateDb.process(source);
} catch (e) {
console.log(e);
}
......
......@@ -11,11 +11,13 @@ const fs = require('fs');
const fsPath = require('path');
const babelGenerator = require('@babel/generator').default;
const babelTemplate = require('@babel/template').default;
const babelTraverse = require('@babel/traverse').default;
const babelTypes = require('@babel/types');
const globals = require('globals');
const random = require('./random.js');
const sourceHelpers = require('./source_helpers.js');
const globalIdentifiers = new Set(Object.keys(globals.builtin));
const propertyNames = new Set([
......@@ -238,6 +240,29 @@ function _markSkipped(path) {
}
}
/**
* Returns true if an expression can be applied or false otherwise.
*/
function isValid(expression) {
const expressionTemplate = babelTemplate(
expression.source,
sourceHelpers.BABYLON_REPLACE_VAR_OPTIONS);
const dependencies = {};
if (expression.dependencies) {
for (const dependency of expression.dependencies) {
dependencies[dependency] = babelTypes.identifier('__v_0');
}
}
try {
expressionTemplate(dependencies);
} catch (e) {
return false;
}
return true;
}
class MutateDbWriter {
constructor(outputDir) {
this.seen = new Set();
......@@ -393,6 +418,11 @@ class MutateDbWriter {
return;
}
// Test results.
if (!isValid(expression)) {
return;
}
// Write results.
let dirPath = fsPath.join(self.outputDir, expression.type);
if (!fs.existsSync(dirPath)) {
......
......@@ -36,12 +36,9 @@ class CrossOverMutator extends mutator.Mutator {
{canHaveSuper: canHaveSuper});
// Insert the statement.
var templateOptions = Object.assign({}, sourceHelpers.BABYLON_OPTIONS);
templateOptions['placeholderPattern'] = /^VAR_[0-9]+$/;
let toInsert = babelTemplate(
randomExpression.source,
templateOptions);
sourceHelpers.BABYLON_REPLACE_VAR_OPTIONS);
const dependencies = {};
if (randomExpression.dependencies) {
......
......@@ -46,6 +46,9 @@ const BABYLON_OPTIONS = {
],
}
const BABYLON_REPLACE_VAR_OPTIONS = Object.assign({}, BABYLON_OPTIONS);
BABYLON_REPLACE_VAR_OPTIONS['placeholderPattern'] = /^VAR_[0-9]+$/;
function _isV8OrSpiderMonkeyLoad(path) {
// 'load' and 'loadRelativeToScript' used by V8 and SpiderMonkey.
return (babelTypes.isIdentifier(path.node.callee) &&
......@@ -445,6 +448,7 @@ function generateCode(source, dependencies=[]) {
module.exports = {
BABYLON_OPTIONS: BABYLON_OPTIONS,
BABYLON_REPLACE_VAR_OPTIONS: BABYLON_REPLACE_VAR_OPTIONS,
generateCode: generateCode,
loadDependencyAbs: loadDependencyAbs,
loadResource: loadResource,
......
// Copyright 2021 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
/**
* @fileoverview Test the script building the DB.
*/
'use strict';
const assert = require('assert');
const { execSync } = require("child_process");
const fs = require('fs');
const path = require('path');
const tempy = require('tempy');
function buildDb(inputDir, corpusName, outputDir) {
execSync(
`node build_db.js -i ${inputDir} -o ${outputDir} ${corpusName}`,
{stdio: ['pipe']});
}
describe('DB tests', () => {
// Test feeds an expression that does not apply.
it('omits erroneous expressions', () => {
const outPath = tempy.directory();
buildDb('test_data/db', 'this', outPath);
const indexFile = path.join(outPath, 'index.json');
const indexJSON = JSON.parse(fs.readFileSync(indexFile), 'utf-8');
assert.deepEqual(
indexJSON, {"statements": [], "superStatements": [], "all": []});
});
});
......@@ -38,31 +38,6 @@ function execFile(jsFile) {
execSync("node " + jsFile, {stdio: ['pipe']});
}
function buildDb(inputDir, corpusName, outputDir) {
execSync(
`node build_db.js -i ${inputDir} -o ${outputDir} ${corpusName}`,
{stdio: ['pipe']});
}
function assertFuzzWithDbThrows(dbInputDir, corpusName, settings, regexp) {
const outPath = tempy.directory();
buildDb(dbInputDir, corpusName, outPath);
settings['MUTATE_CROSSOVER_INSERT'] = 1.0;
assert.throws(
() => {
createFuzzTest(
outPath, settings,
['regress/build_db/cross_over_mutator_input.js']);
},
err => {
assert(regexp.test(err));
return true;
},
'unexpected error',
);
}
describe('Regression tests', () => {
beforeEach(() => {
helpers.deterministicRandom(sandbox);
......@@ -135,25 +110,4 @@ describe('Regression tests', () => {
['regress/numbers/input_indices.js']);
execFile(file);
});
it('create call expression', () => {
// TODO(machenbach): Build_db extracts a function expression without
// parentheses, re-parsing this later fails in cross-over mutator.
assertFuzzWithDbThrows(
'test_data/regress/build_db',
'destructuring',
this.settings,
SYNTAX_ERROR_RE);
});
it('create assignment expression', () => {
// TODO(machenbach): Build_db extracts some assignment expressions with a
// spurious dependency. This leads to an "unknown substitution" error
// when applying the template.
assertFuzzWithDbThrows(
'test_data/regress/build_db',
'this',
this.settings,
/.*Unknown substitution.*/);
});
});
// Copyright 2020 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
let x = 2;
let y = 2;
Math.pow(x, y);
// Copyright 2020 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
let x, y;
(function([ x = y = 1 ]) {}([]));
......@@ -48,7 +48,7 @@ function main() {
// super.
const source = sourceHelpers.loadSource(
__dirname,
'test_data/regress/build_db/cross_over_mutator_class_input.js');
'test_data/cross_over_mutator_class_input.js');
try {
mutator.mutate(source);
nPass++;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment