aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.pylintrc2
-rw-r--r--infra/base-images/base-builder/bisect_clang.py29
-rw-r--r--infra/base-images/base-builder/bisect_clang_test.py15
-rwxr-xr-xinfra/base-images/base-builder/write_labels.py7
-rwxr-xr-xinfra/base-images/base-runner/dataflow_tracer.py59
-rw-r--r--infra/bisector_test.py12
-rwxr-xr-xinfra/presubmit.py17
7 files changed, 75 insertions, 66 deletions
diff --git a/.pylintrc b/.pylintrc
index 02abe5f6c..141ea83f5 100644
--- a/.pylintrc
+++ b/.pylintrc
@@ -7,7 +7,7 @@ extension-pkg-whitelist=
# Add files or directories to the blacklist. They should be base names, not
# paths.
-ignore=CVS
+ignore=CVS,base-clang,base-sanitizer-libs-builder
# Add files or directories matching the regex patterns to the blacklist. The
# regex matches against base names, not paths.
diff --git a/infra/base-images/base-builder/bisect_clang.py b/infra/base-images/base-builder/bisect_clang.py
index 2e7db61ca..8c530b627 100644
--- a/infra/base-images/base-builder/bisect_clang.py
+++ b/infra/base-images/base-builder/bisect_clang.py
@@ -112,7 +112,7 @@ class GitRepo:
class BisectError(Exception):
- pass
+ """Error that was encountered during bisection."""
def get_clang_build_env():
@@ -140,8 +140,8 @@ def clone_with_retries(repo, local_path, num_retries=10):
for _ in range(num_retries):
if os.path.isdir(local_path):
shutil.rmtree(local_path)
- retcode, _, _ = execute(
- ['git', 'clone', repo, local_path], expect_zero=False)
+ retcode, _, _ = execute(['git', 'clone', repo, local_path],
+ expect_zero=False)
if retcode == 0:
return
raise Exception('Could not checkout %s.' % repo)
@@ -162,17 +162,16 @@ def prepare_build(llvm_project_path):
llvm_build_dir = os.path.join(os.getenv('WORK'), 'llvm-build')
if not os.path.exists(llvm_build_dir):
os.mkdir(llvm_build_dir)
- execute(
- [
- 'cmake', '-G', 'Ninja', '-DLIBCXX_ENABLE_SHARED=OFF',
- '-DLIBCXX_ENABLE_STATIC_ABI_LIBRARY=ON',
- '-DLIBCXXABI_ENABLE_SHARED=OFF', '-DCMAKE_BUILD_TYPE=Release',
- '-DLLVM_ENABLE_PROJECTS=libcxx;libcxxabi;compiler-rt;clang',
- '-DLLVM_TARGETS_TO_BUILD=' + get_clang_target_arch(),
- os.path.join(llvm_project_path, 'llvm')
- ],
- env=get_clang_build_env(),
- cwd=llvm_build_dir)
+ execute([
+ 'cmake', '-G', 'Ninja', '-DLIBCXX_ENABLE_SHARED=OFF',
+ '-DLIBCXX_ENABLE_STATIC_ABI_LIBRARY=ON', '-DLIBCXXABI_ENABLE_SHARED=OFF',
+ '-DCMAKE_BUILD_TYPE=Release',
+ '-DLLVM_ENABLE_PROJECTS=libcxx;libcxxabi;compiler-rt;clang',
+ '-DLLVM_TARGETS_TO_BUILD=' + get_clang_target_arch(),
+ os.path.join(llvm_project_path, 'llvm')
+ ],
+ env=get_clang_build_env(),
+ cwd=llvm_build_dir)
return llvm_build_dir
@@ -201,12 +200,14 @@ def find_culprit_commit(test_command, good_commit, bad_commit):
def main():
+ # pylint: disable=line-too-long
"""Finds the culprit LLVM commit that introduced a clang regression.
Can be tested using this command in a libsodium shell:
python3 bisect_clang.py "cd /src/libsodium; make clean; cd -; compile && /out/secret_key_auth_fuzzer -runs=100" \
f7e52fbdb5a7af8ea0808e98458b497125a5eca1 \
8288453f6aac05080b751b680455349e09d49825
"""
+ # pylint: enable=line-too-long
# TODO(metzman): Sanity check CFLAGS for things like
# -fsanitize=fuzzer-no-link.
# TODO(metzman): Allow test_command to be optional and for just build.sh to be
diff --git a/infra/base-images/base-builder/bisect_clang_test.py b/infra/base-images/base-builder/bisect_clang_test.py
index 7a11021d1..edf13e759 100644
--- a/infra/base-images/base-builder/bisect_clang_test.py
+++ b/infra/base-images/base-builder/bisect_clang_test.py
@@ -37,10 +37,11 @@ def patch_environ(testcase_obj):
patcher.start()
-class BisectClangTestMixin:
+class BisectClangTestMixin: # pylint: disable=too-few-public-methods
"""Useful mixin for bisect_clang unittests."""
- def setUp(self):
+ def setUp(self): # pylint: disable=invalid-name
+ """Initialization method for unittests."""
patch_environ(self)
os.environ['SRC'] = '/src'
os.environ['WORK'] = '/work'
@@ -68,8 +69,9 @@ class GetClangBuildEnvTest(BisectClangTestMixin, unittest.TestCase):
def read_test_data(filename):
- with open(os.path.join(FILE_DIRECTORY, 'test_data', filename)) as f:
- return f.read()
+ """Returns data from |filename| in the test_data directory."""
+ with open(os.path.join(FILE_DIRECTORY, 'test_data', filename)) as file_handle:
+ return file_handle.read()
class SearchBisectOutputTest(BisectClangTestMixin, unittest.TestCase):
@@ -126,6 +128,7 @@ def create_mock_popen(
def mock_prepare_build(llvm_project_path): # pylint: disable=unused-argument
+ """Mocked prepare_build function."""
return '/work/llvm-build'
@@ -224,8 +227,8 @@ class GitRepoTest(BisectClangTestMixin, unittest.TestCase):
with mock.patch('subprocess.Popen', create_mock_popen()) as mock_popen:
self.git.bisect_start(self.good_commit, self.bad_commit,
self.test_command)
- self.assertEqual(
- get_git_command('bisect', 'start'), mock_popen.commands[0])
+ self.assertEqual(get_git_command('bisect', 'start'),
+ mock_popen.commands[0])
mock_test_start_commit.assert_has_calls([
mock.call('bad_commit', 'bad', 'testcommand'),
mock.call('good_commit', 'good', 'testcommand')
diff --git a/infra/base-images/base-builder/write_labels.py b/infra/base-images/base-builder/write_labels.py
index 338ac716f..b1a748427 100755
--- a/infra/base-images/base-builder/write_labels.py
+++ b/infra/base-images/base-builder/write_labels.py
@@ -1,10 +1,13 @@
#!/usr/bin/python3
+"""Script for writing from project.yaml to .labels file."""
import os
import json
import sys
+
def main():
+ """Writes labels."""
if len(sys.argv) != 3:
print('Usage: write_labels.py labels_json out_dir', file=sys.stderr)
sys.exit(1)
@@ -13,8 +16,8 @@ def main():
out = sys.argv[2]
for target_name, labels in labels_by_target.items():
- with open(os.path.join(out, target_name + '.labels'), 'w') as f:
- f.write('\n'.join(labels))
+ with open(os.path.join(out, target_name + '.labels'), 'w') as file_handle:
+ file_handle.write('\n'.join(labels))
if __name__ == '__main__':
diff --git a/infra/base-images/base-runner/dataflow_tracer.py b/infra/base-images/base-runner/dataflow_tracer.py
index 7166bf43e..66855a0f7 100755
--- a/infra/base-images/base-runner/dataflow_tracer.py
+++ b/infra/base-images/base-runner/dataflow_tracer.py
@@ -26,9 +26,9 @@ import sys
# These can be controlled by the runner in order to change the values without
# rebuilding OSS-Fuzz base images.
-FILE_SIZE_LIMIT = int(os.getenv('DFT_FILE_SIZE_LIMIT', 32 * 1024))
-MIN_TIMEOUT = float(os.getenv('DFT_MIN_TIMEOUT', 1.0))
-TIMEOUT_RANGE = float(os.getenv('DFT_TIMEOUT_RANGE', 3.0))
+FILE_SIZE_LIMIT = int(os.environ.get('DFT_FILE_SIZE_LIMIT', 32 * 1024))
+MIN_TIMEOUT = float(os.environ.get('DFT_MIN_TIMEOUT', 1.0))
+TIMEOUT_RANGE = float(os.enviro.get('DFT_TIMEOUT_RANGE', 3.0))
DFSAN_OPTIONS = 'fast16labels=1:warn_unimplemented=0'
@@ -39,15 +39,15 @@ def _error(msg):
def _list_dir(dirpath):
for root, _, files in os.walk(dirpath):
- for f in files:
- yield os.path.join(root, f)
+ for filename in files:
+ yield os.path.join(root, filename)
def _sha1(filepath):
- h = hashlib.sha1()
- with open(filepath, 'rb') as f:
- h.update(f.read())
- return h.hexdigest()
+ digest = hashlib.sha1()
+ with open(filepath, 'rb') as file_handle:
+ digest.update(file_handle.read())
+ return digest.hexdigest()
def _run(cmd, timeout=None):
@@ -56,15 +56,16 @@ def _run(cmd, timeout=None):
result = subprocess.run(cmd,
timeout=timeout,
stdout=subprocess.PIPE,
- stderr=subprocess.PIPE)
+ stderr=subprocess.PIPE,
+ check=False)
if result.returncode:
_error('{command} finished with non-zero code: {code}'.format(
command=str(cmd), code=result.returncode))
except subprocess.TimeoutExpired:
raise
- except Exception as e:
- _error('Exception: ' + str(e))
+ except Exception as error: # pylint: disable=broad-except
+ _error('Exception: ' + str(error))
return result
@@ -77,6 +78,7 @@ def _timeout(size):
def collect_traces(binary, corpus_dir, dft_dir):
+ """Collects traces and returns stats summarizing them."""
stats = {
'total': 0,
'traced': 0,
@@ -86,43 +88,46 @@ def collect_traces(binary, corpus_dir, dft_dir):
}
files_and_sizes = {}
- for f in _list_dir(corpus_dir):
+ for filename in _list_dir(corpus_dir):
stats['total'] += 1
- size = os.path.getsize(f)
+ size = os.path.getsize(filename)
if size > FILE_SIZE_LIMIT:
stats['long'] += 1
- print('Skipping large file ({size}b): {path}'.format(size=size, path=f))
+ print('Skipping large file ({size}b): {path}'.format(size=size,
+ path=filename))
continue
- files_and_sizes[f] = size
+ files_and_sizes[filename] = size
- for f in sorted(files_and_sizes, key=files_and_sizes.get):
- output_path = os.path.join(dft_dir, _sha1(f))
+ for filename in sorted(files_and_sizes, key=files_and_sizes.get):
+ output_path = os.path.join(dft_dir, _sha1(filename))
try:
- result = _run([binary, f, output_path], timeout=_timeout(size))
+ result = _run([binary, filename, output_path], timeout=_timeout(size))
if result.returncode:
stats['failed'] += 1
else:
stats['traced'] += 1
- except subprocess.TimeoutExpired as e:
- _error('Slow input: ' + str(e))
+ except subprocess.TimeoutExpired as error:
+ _error('Slow input: ' + str(error))
stats['slow'] += 1
return stats
def dump_functions(binary, dft_dir):
+ """Dumps functions to functions.txt. Returns True on success."""
result = _run([binary])
if not result or result.returncode:
return False
- with open(os.path.join(dft_dir, 'functions.txt'), 'wb') as f:
- f.write(result.stdout)
+ with open(os.path.join(dft_dir, 'functions.txt'), 'wb') as file_handle:
+ file_handle.write(result.stdout)
return True
def main():
+ """Collect dataflow traces."""
if len(sys.argv) < 4:
_error('Usage: {0} <binary> <corpus_dir> <dft_dir>'.format(sys.argv[0]))
sys.exit(1)
@@ -138,13 +143,13 @@ def main():
sys.exit(1)
stats = collect_traces(binary, corpus_dir, dft_dir)
- for k, v in stats.items():
- print('{0}: {1}'.format(k, v))
+ for key, value in stats.items():
+ print('{0}: {1}'.format(key, value))
# Checksum that we didn't lose track of any of the inputs.
- assert stats['total'] * 2 == sum(v for v in stats.values())
+ assert stats['total'] * 2 == sum(value for value in stats.values())
sys.exit(0)
-if __name__ == "__main__":
+if __name__ == '__main__':
main()
diff --git a/infra/bisector_test.py b/infra/bisector_test.py
index 883e0f1fc..5e3dc5232 100644
--- a/infra/bisector_test.py
+++ b/infra/bisector_test.py
@@ -33,6 +33,8 @@ TEST_DIR_PATH = os.path.dirname(os.path.realpath(__file__))
class BisectIntegrationTests(unittest.TestCase):
"""Class to test the functionality of bisection method."""
+ BISECT_TYPE = 'regressed'
+
def test_bisect_invalid_repo(self):
"""Test the bisection method on a project that does not exist."""
test_repo = test_repos.INVALID_REPO
@@ -42,9 +44,9 @@ class BisectIntegrationTests(unittest.TestCase):
sanitizer='address',
architecture='x86_64')
with self.assertRaises(ValueError):
- bisector.bisect(test_repo.old_commit, test_repo.new_commit,
- test_repo.test_case_path, test_repo.fuzz_target,
- build_data)
+ bisector.bisect(self.BISECT_TYPE, test_repo.old_commit,
+ test_repo.new_commit, test_repo.test_case_path,
+ test_repo.fuzz_target, build_data)
def test_bisect(self):
"""Test the bisect method on example projects."""
@@ -55,8 +57,8 @@ class BisectIntegrationTests(unittest.TestCase):
engine='libfuzzer',
sanitizer='address',
architecture='x86_64')
- result = bisector.bisect(test_repo.old_commit, test_repo.new_commit,
- test_repo.test_case_path,
+ result = bisector.bisect(self.BISECT_TYPE, test_repo.old_commit,
+ test_repo.new_commit, test_repo.test_case_path,
test_repo.fuzz_target, build_data)
self.assertEqual(result.commit, test_repo.intro_commit)
diff --git a/infra/presubmit.py b/infra/presubmit.py
index 3a616aca0..7699ab9ff 100755
--- a/infra/presubmit.py
+++ b/infra/presubmit.py
@@ -292,16 +292,11 @@ def is_nonfuzzer_python(path):
return os.path.splitext(path)[1] == '.py' and '/projects/' not in path
-def lint(paths):
+def lint():
"""Run python's linter on |paths| if it is a python file. Return False if it
fails linting."""
- paths = [path for path in paths if is_nonfuzzer_python(path)]
- if not paths:
- return True
-
- command = ['python3', '-m', 'pylint', '-j', '0']
- command.extend(paths)
+ command = ['python3', '-m', 'pylint', '-j', '0', 'infra']
returncode = subprocess.run(command, check=False).returncode
return returncode == 0
@@ -333,10 +328,10 @@ def get_changed_files():
]
-def run_tests():
+def run_tests(relevant_files):
"""Run all unit tests in directories that are different from HEAD."""
changed_dirs = set()
- for file in get_changed_files():
+ for file in relevant_files:
changed_dirs.add(os.path.dirname(file))
# TODO(metzman): This approach for running tests is flawed since tests can
@@ -384,7 +379,7 @@ def main():
return bool_to_returncode(success)
if args.command == 'lint':
- success = lint(relevant_files)
+ success = lint()
return bool_to_returncode(success)
if args.command == 'license':
@@ -392,7 +387,7 @@ def main():
return bool_to_returncode(success)
if args.command == 'infra-tests':
- success = run_tests()
+ success = run_tests(relevant_files)
return bool_to_returncode(success)
# Do all the checks (but no tests).