aboutsummaryrefslogtreecommitdiffstats
path: root/src/scripts
diff options
context:
space:
mode:
authorJack Lloyd <[email protected]>2017-07-31 15:13:15 -0400
committerJack Lloyd <[email protected]>2017-08-25 17:36:51 -0400
commit3baa546d70bcd078b23be07069d755a5f130fb0f (patch)
treed626d73fdf845987e2d1783e8493593501378a07 /src/scripts
parent41e1e7cbc1e4e864ad5d15dd0c09227b04940a91 (diff)
Create new fuzzer build mode
Diffstat (limited to 'src/scripts')
-rwxr-xr-xsrc/scripts/ci/travis/build.sh13
-rwxr-xr-xsrc/scripts/create_corpus_zip.py48
-rwxr-xr-xsrc/scripts/test_fuzzers.py78
3 files changed, 138 insertions, 1 deletions
diff --git a/src/scripts/ci/travis/build.sh b/src/scripts/ci/travis/build.sh
index 36517738b..d2e35112e 100755
--- a/src/scripts/ci/travis/build.sh
+++ b/src/scripts/ci/travis/build.sh
@@ -23,6 +23,8 @@ elif [ "$BUILD_MODE" = "nist" ]; then
elif [ "$BUILD_MODE" = "sonarqube" ]; then
# No special flags required
CFG_FLAGS+=()
+elif [ "$BUILD_MODE" = "fuzzers" ]; then
+ CFG_FLAGS+=(--build-fuzzers=test --with-sanitizers --with-debug-info --disable-shared)
elif [ "$BUILD_MODE" = "parallel" ]; then
if [ "$CC" = "gcc" ]; then
@@ -137,6 +139,11 @@ else
time "${MAKE_CMD[@]}"
fi
+if [ "$BUILD_MODE" = "fuzzers" ]; then
+ make fuzzers
+ make fuzzer_corpus_zip
+fi
+
# post-build ccache stats
ccache --show-stats
@@ -171,9 +178,13 @@ if [ "$BUILD_MODE" = "sonarqube" ]; then
# When neither on master branch nor on a non-external pull request => nothing to do
fi
-if [ "$BUILD_MODE" = "sonarqube" ] || [ "$BUILD_MODE" = "docs" ] || \
+if [ "$BUILD_MODE" = "sonarqube" ] || [ "$BUILD_MODE" = "docs" ] ||
( [ "${BUILD_MODE:0:5}" = "cross" ] && [ "$TRAVIS_OS_NAME" = "osx" ] ); then
echo "Running tests disabled on this build type"
+
+elif [ "$BUILD_MODE" = "fuzzers" ]; then
+ # Test each fuzzer against its corpus
+ ./src/scripts/test_fuzzers.py fuzzer_corpus build/fuzzer
else
TEST_CMD=("${TEST_PREFIX[@]}" $TEST_EXE "${TEST_FLAGS[@]}")
echo "Running" "${TEST_CMD[@]}"
diff --git a/src/scripts/create_corpus_zip.py b/src/scripts/create_corpus_zip.py
new file mode 100755
index 000000000..5faee3b52
--- /dev/null
+++ b/src/scripts/create_corpus_zip.py
@@ -0,0 +1,48 @@
+#!/usr/bin/python
+
+# These is used to create fuzzer corpus zip files
+
+# This is primarily used by OSS-Fuzz but might be useful if you were
+# deploying the binaries in a custom fuzzer deployment system.
+
+import sys
+import os
+import zipfile
+import stat
+
+def main(args=None):
+ if args is None:
+ args = sys.argv
+
+ if len(args) != 2 and len(args) != 3:
+ print("Usage: %s corpus_dir <output_dir>" % (args[0]))
+ return 1
+
+ root_dir = args[1]
+
+ if len(args) == 3:
+ output_dir = args[2]
+ else:
+ output_dir = ''
+
+ if not os.access(root_dir, os.R_OK):
+ print("Error could not access directory '%s'" % (root_dir))
+ return 1
+
+ for corpus_dir in os.listdir(root_dir):
+ if corpus_dir == '.git':
+ continue
+ subdir = os.path.join(root_dir, corpus_dir)
+ if not stat.S_ISDIR(os.stat(subdir).st_mode):
+ continue
+
+ zipfile_path = os.path.join(output_dir, '%s.zip' % (corpus_dir))
+ zf = zipfile.ZipFile(zipfile_path, 'w', zipfile.ZIP_DEFLATED)
+ for f in os.listdir(subdir):
+ zf.write(os.path.join(subdir, f), f)
+ zf.close()
+
+ return 0
+
+if __name__ == '__main__':
+ sys.exit(main())
diff --git a/src/scripts/test_fuzzers.py b/src/scripts/test_fuzzers.py
new file mode 100755
index 000000000..0d473e00c
--- /dev/null
+++ b/src/scripts/test_fuzzers.py
@@ -0,0 +1,78 @@
+#!/usr/bin/python
+
+import sys
+import os
+import subprocess
+
+def main(args=None):
+ if args is None:
+ args = sys.argv
+
+ if len(args) != 3:
+ print("Usage: %s <corpus_dir> <fuzzers_dir>" % (args[0]))
+ return 1
+
+ corpus_dir = args[1]
+ fuzzer_dir = args[2]
+
+ if not os.access(corpus_dir, os.R_OK):
+ print("Error could not access corpus directory '%s'" % (corpus_dir))
+ return 1
+
+ if not os.access(fuzzer_dir, os.R_OK):
+ print("Error could not access fuzzers directory '%s'" % (fuzzer_dir))
+ return 1
+
+ fuzzers = set([])
+ for fuzzer in os.listdir(fuzzer_dir):
+ if fuzzer.endswith('.zip'):
+ continue
+ fuzzers.add(fuzzer)
+
+ corpii = set([])
+ for corpus in os.listdir(corpus_dir):
+ if corpus in ['.git', 'readme.txt']:
+ continue
+ corpii.add(corpus)
+
+ fuzzers_without_corpus = fuzzers - corpii
+ corpus_without_fuzzers = corpii - fuzzers
+
+ for f in sorted(list(fuzzers_without_corpus)):
+ print("Warning: Fuzzer %s has no corpus" % (f))
+ for c in sorted(list(corpus_without_fuzzers)):
+ print("Warning: Corpus %s has no fuzzer" % (c))
+
+ fuzzers_with_corpus = fuzzers & corpii
+
+ any_crashes = False
+
+ for f in sorted(list(fuzzers_with_corpus)):
+ fuzzer_bin = os.path.join(fuzzer_dir, f)
+ corpus_files = os.path.join(corpus_dir, f)
+ for corpus_file in sorted(list(os.listdir(corpus_files))):
+ corpus_fd = open(os.path.join(corpus_files, corpus_file), 'r')
+ fuzzer_proc = subprocess.Popen([fuzzer_bin], stdin=corpus_fd,
+ stdout=subprocess.PIPE, stderr=subprocess.PIPE, close_fds=True)
+ (stdout, stderr) = fuzzer_proc.communicate()
+ corpus_fd.close()
+
+ if fuzzer_proc.returncode != 0:
+ print("Fuzzer %s crashed with input %s returncode %d" % (f, corpus_file, fuzzer_proc.returncode))
+ any_crashes = True
+
+ if len(stdout) != 0:
+ stdout = stdout.decode('ascii')
+ print("Fuzzer %s produced stdout on input %s:\n%s" % (f, corpus_file, stdout))
+
+ if len(stderr) != 0:
+ stderr = stderr.decode('ascii')
+ print("Fuzzer %s produced stderr on input %s:\n%s" % (f, corpus_file, stderr))
+
+ if any_crashes:
+ return 2
+ return 0
+
+
+if __name__ == '__main__':
+ sys.exit(main())