mirror of https://github.com/google/oss-fuzz.git
parent
aa8740a98a
commit
525e9eccd0
|
@ -17,13 +17,8 @@ import logging
|
|||
import os
|
||||
import shutil
|
||||
import stat
|
||||
import sys
|
||||
|
||||
import base_runner_utils
|
||||
import config_utils
|
||||
# pylint: disable=wrong-import-position,import-error
|
||||
sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
|
||||
import utils
|
||||
|
||||
import clusterfuzz.environment
|
||||
import clusterfuzz.fuzz
|
||||
|
@ -39,6 +34,8 @@ LIBFUZZER_OPTIONS = ['-seed=1337', '-len_control=0']
|
|||
# The number of reproduce attempts for a crash.
|
||||
REPRODUCE_ATTEMPTS = 10
|
||||
|
||||
REPRODUCE_TIME_SECONDS = 30
|
||||
|
||||
# Seconds on top of duration until a timeout error is raised.
|
||||
BUFFER_TIME = 10
|
||||
|
||||
|
@ -213,21 +210,25 @@ class FuzzTarget: # pylint: disable=too-many-instance-attributes
|
|||
|
||||
os.chmod(target_path, stat.S_IRWXO)
|
||||
|
||||
env = base_runner_utils.get_env(self.config, self.workspace)
|
||||
env['TESTCASE'] = testcase
|
||||
command = ['reproduce', self.target_name, '-runs=100']
|
||||
logging.info('Trying to reproduce crash using: %s.', testcase)
|
||||
with clusterfuzz.environment.Environment(config_utils.DEFAULT_ENGINE,
|
||||
self.config.sanitizer,
|
||||
target_path,
|
||||
interactive=True):
|
||||
for _ in range(REPRODUCE_ATTEMPTS):
|
||||
engine_impl = clusterfuzz.fuzz.get_engine(config_utils.DEFAULT_ENGINE)
|
||||
result = engine_impl.reproduce(target_path,
|
||||
testcase,
|
||||
arguments=[],
|
||||
max_time=REPRODUCE_TIME_SECONDS)
|
||||
|
||||
logging.info('Running reproduce command: %s.', ' '.join(command))
|
||||
for _ in range(REPRODUCE_ATTEMPTS):
|
||||
_, _, returncode = utils.execute(command, env=env)
|
||||
if result.return_code != 0:
|
||||
logging.info('Reproduce command returned: %s. Reproducible on %s.',
|
||||
result.return_code, target_path)
|
||||
|
||||
if returncode != 0:
|
||||
logging.info('Reproduce command returned: %s. Reproducible on %s.',
|
||||
returncode, target_path)
|
||||
return True
|
||||
|
||||
return True
|
||||
|
||||
logging.info('Reproduce command returned 0. Not reproducible on %s.',
|
||||
logging.info('Reproduce command returned: 0. Not reproducible on %s.',
|
||||
target_path)
|
||||
return False
|
||||
|
||||
|
|
|
@ -19,8 +19,12 @@ import unittest
|
|||
from unittest import mock
|
||||
|
||||
import certifi
|
||||
# Importing this later causes import failures with pytest for some reason.
|
||||
# TODO(ochang): Figure out why.
|
||||
import parameterized
|
||||
import google.cloud.ndb # pylint: disable=unused-import
|
||||
from pyfakefs import fake_filesystem_unittest
|
||||
from clusterfuzz.fuzz import engine
|
||||
|
||||
import clusterfuzz_deployment
|
||||
import fuzz_target
|
||||
|
@ -34,11 +38,9 @@ EXAMPLE_PROJECT = 'example'
|
|||
# An example fuzzer that triggers an error.
|
||||
EXAMPLE_FUZZER = 'example_crash_fuzzer'
|
||||
|
||||
# The return value of a successful call to utils.execute.
|
||||
EXECUTE_SUCCESS_RETVAL = ('', '', 0)
|
||||
|
||||
# The return value of a failed call to utils.execute.
|
||||
EXECUTE_FAILURE_RETVAL = ('', '', 1)
|
||||
# Mock return values for engine_impl.reproduce.
|
||||
EXECUTE_SUCCESS_RESULT = engine.ReproduceResult([], 0, 0, '')
|
||||
EXECUTE_FAILURE_RESULT = engine.ReproduceResult([], 1, 0, '')
|
||||
|
||||
|
||||
def _create_config(**kwargs):
|
||||
|
@ -85,40 +87,39 @@ class IsReproducibleTest(fake_filesystem_unittest.TestCase):
|
|||
self.workspace, deployment,
|
||||
deployment.config)
|
||||
|
||||
# ClusterFuzz requires ROOT_DIR.
|
||||
root_dir = os.environ['ROOT_DIR']
|
||||
test_helpers.patch_environ(self, empty=True)
|
||||
os.environ['ROOT_DIR'] = root_dir
|
||||
|
||||
def test_reproducible(self, _):
|
||||
"""Tests that is_reproducible returns True if crash is detected and that
|
||||
is_reproducible uses the correct command to reproduce a crash."""
|
||||
all_repro = [EXECUTE_FAILURE_RETVAL] * fuzz_target.REPRODUCE_ATTEMPTS
|
||||
with mock.patch('utils.execute', side_effect=all_repro) as mock_execute:
|
||||
all_repro = [EXECUTE_FAILURE_RESULT] * fuzz_target.REPRODUCE_ATTEMPTS
|
||||
with mock.patch('clusterfuzz.fuzz.get_engine') as mock_get_engine:
|
||||
mock_get_engine().reproduce.side_effect = all_repro
|
||||
|
||||
result = self.target.is_reproducible(self.testcase_path,
|
||||
self.fuzz_target_path)
|
||||
expected_command = ['reproduce', 'fuzz-target', '-runs=100']
|
||||
expected_env = {
|
||||
'SANITIZER': self.config.sanitizer,
|
||||
'FUZZING_LANGUAGE': 'c++',
|
||||
'OUT': self.workspace.out,
|
||||
'CIFUZZ': 'True',
|
||||
'FUZZING_ENGINE': 'libfuzzer',
|
||||
'ARCHITECTURE': 'x86_64',
|
||||
'TESTCASE': self.testcase_path,
|
||||
'FUZZER_ARGS': '-rss_limit_mb=2560 -timeout=25'
|
||||
}
|
||||
mock_execute.assert_called_once_with(expected_command, env=expected_env)
|
||||
mock_get_engine().reproduce.assert_called_once_with(
|
||||
'/workspace/build-out/fuzz-target',
|
||||
'/testcase',
|
||||
arguments=[],
|
||||
max_time=30)
|
||||
self.assertTrue(result)
|
||||
self.assertEqual(1, mock_execute.call_count)
|
||||
self.assertEqual(1, mock_get_engine().reproduce.call_count)
|
||||
|
||||
def test_flaky(self, _):
|
||||
"""Tests that is_reproducible returns True if crash is detected on the last
|
||||
attempt."""
|
||||
last_time_repro = [EXECUTE_SUCCESS_RETVAL] * 9 + [EXECUTE_FAILURE_RETVAL]
|
||||
with mock.patch('utils.execute',
|
||||
side_effect=last_time_repro) as mock_execute:
|
||||
last_time_repro = [EXECUTE_SUCCESS_RESULT] * 9 + [EXECUTE_FAILURE_RESULT]
|
||||
with mock.patch('clusterfuzz.fuzz.get_engine') as mock_get_engine:
|
||||
mock_get_engine().reproduce.side_effect = last_time_repro
|
||||
self.assertTrue(
|
||||
self.target.is_reproducible(self.testcase_path,
|
||||
self.fuzz_target_path))
|
||||
self.assertEqual(fuzz_target.REPRODUCE_ATTEMPTS, mock_execute.call_count)
|
||||
self.assertEqual(fuzz_target.REPRODUCE_ATTEMPTS,
|
||||
mock_get_engine().reproduce.call_count)
|
||||
|
||||
def test_nonexistent_fuzzer(self, _):
|
||||
"""Tests that is_reproducible raises an error if it could not attempt
|
||||
|
@ -129,8 +130,9 @@ class IsReproducibleTest(fake_filesystem_unittest.TestCase):
|
|||
def test_unreproducible(self, _):
|
||||
"""Tests that is_reproducible returns False for a crash that did not
|
||||
reproduce."""
|
||||
all_unrepro = [EXECUTE_SUCCESS_RETVAL] * fuzz_target.REPRODUCE_ATTEMPTS
|
||||
with mock.patch('utils.execute', side_effect=all_unrepro):
|
||||
all_unrepro = [EXECUTE_SUCCESS_RESULT] * fuzz_target.REPRODUCE_ATTEMPTS
|
||||
with mock.patch('clusterfuzz.fuzz.get_engine') as mock_get_engine:
|
||||
mock_get_engine().reproduce.side_effect = all_unrepro
|
||||
result = self.target.is_reproducible(self.testcase_path,
|
||||
self.fuzz_target_path)
|
||||
self.assertFalse(result)
|
||||
|
|
Loading…
Reference in New Issue