// 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. /** * @fileoverview Tests for differential fuzzing. */ 'use strict'; const assert = require('assert'); const program = require('commander'); const sinon = require('sinon'); const helpers = require('./helpers.js'); const scriptMutator = require('../script_mutator.js'); const sourceHelpers = require('../source_helpers.js'); const random = require('../random.js'); const { DifferentialFuzzMutator, DifferentialFuzzSuppressions } = require( '../mutators/differential_fuzz_mutator.js'); const { DifferentialScriptMutator } = require( '../differential_script_mutator.js'); const sandbox = sinon.createSandbox(); function testMutators(settings, mutatorClass, inputFile, expectedFile) { const source = helpers.loadTestData('differential_fuzz/' + inputFile); const mutator = new mutatorClass(settings); mutator.mutate(source); const mutated = sourceHelpers.generateCode(source); helpers.assertExpectedResult( 'differential_fuzz/' + expectedFile, mutated); } describe('Differential fuzzing', () => { beforeEach(() => { // Zero settings for all mutators. this.settings = scriptMutator.defaultSettings(); for (const key of Object.keys(this.settings)) { this.settings[key] = 0.0; } // By default, deterministically use all mutations of differential // fuzzing. this.settings['DIFF_FUZZ_EXTRA_PRINT'] = 1.0; this.settings['DIFF_FUZZ_TRACK_CAUGHT'] = 1.0; // Fake fuzzer being called with --input_dir flag. this.oldInputDir = program.input_dir; program.input_dir = helpers.BASE_DIR; }); afterEach(() => { sandbox.restore(); program.input_dir = this.oldInputDir; }); it('applies suppressions', () => { // This selects the first random variable when replacing .arguments. sandbox.stub(random, 'single').callsFake(a => a[0]); testMutators( this.settings, DifferentialFuzzSuppressions, 'suppressions.js', 'suppressions_expected.js'); }); it('adds extra printing', () => { testMutators( this.settings, DifferentialFuzzMutator, 'mutations.js', 'mutations_expected.js'); }); it('does no extra printing', () => { this.settings['DIFF_FUZZ_EXTRA_PRINT'] = 0.0; testMutators( this.settings, DifferentialFuzzMutator, 'exceptions.js', 'exceptions_expected.js'); }); it('runs end to end', () => { // Don't choose any zeroed settings or IGNORE_DEFAULT_PROB in try-catch // mutator. Choose using original flags with >= 2%. const chooseOrigFlagsProb = 0.2; sandbox.stub(random, 'choose').callsFake((p) => p >= chooseOrigFlagsProb); // Fake build directory from which two json configurations for flags are // loaded. const env = { APP_DIR: 'test_data/differential_fuzz', GENERATE: process.env.GENERATE, }; sandbox.stub(process, 'env').value(env); // Fake loading resources and instead load one fixed fake file for each. sandbox.stub(sourceHelpers, 'loadResource').callsFake(() => { return helpers.loadTestData('differential_fuzz/fake_resource.js'); }); // Load input files. const files = [ 'differential_fuzz/input1.js', 'differential_fuzz/input2.js', ]; const sources = files.map(helpers.loadTestData); // Apply top-level fuzzing, with all probabilistic configs switched off. this.settings['DIFF_FUZZ_EXTRA_PRINT'] = 0.0; this.settings['DIFF_FUZZ_TRACK_CAUGHT'] = 0.0; const mutator = new DifferentialScriptMutator( this.settings, helpers.DB_DIR); const mutated = mutator.mutateMultiple(sources); helpers.assertExpectedResult( 'differential_fuzz/combined_expected.js', mutated.code); // Flags for v8_foozzie.py are calculated from v8_fuzz_experiments.json and // v8_fuzz_flags.json in test_data/differential_fuzz. const expectedFlags = [ '--first-config=ignition', '--second-config=ignition_turbo', '--second-d8=d8', '--second-config-extra-flags=--foo1', '--second-config-extra-flags=--foo2', '--first-config-extra-flags=--flag1', '--second-config-extra-flags=--flag1', '--first-config-extra-flags=--flag2', '--second-config-extra-flags=--flag2', '--first-config-extra-flags=--flag3', '--second-config-extra-flags=--flag3', '--first-config-extra-flags=--flag4', '--second-config-extra-flags=--flag4' ]; assert.deepEqual(expectedFlags, mutated.flags); }); });