From 9d740909595546ebd34a845e6328cb60afa388b8 Mon Sep 17 00:00:00 2001 From: Richard Levitte Date: Wed, 28 Mar 2018 15:46:28 +0200 Subject: [PATCH] Faster fuzz test: teach the fuzz test programs to handle directories Instead of invoking the fuzz test programs once for every corpora file, we invoke them once for each directory of corpora files. This dramatically reduces the number of program invikations, as well as the time 99-test_fuzz.t takes to complete. fuzz/test-corpus.c was enhanced to handle directories as well as regular files. Reviewed-by: Bernd Edlinger Reviewed-by: Rich Salz (Merged from https://github.com/openssl/openssl/pull/5776) --- fuzz/test-corpus.c | 85 ++++++++++++++++++++++++++++++------- test/recipes/99-test_fuzz.t | 10 ++--- 2 files changed, 75 insertions(+), 20 deletions(-) diff --git a/fuzz/test-corpus.c b/fuzz/test-corpus.c index 9cef01f86d..95ffcf2d42 100644 --- a/fuzz/test-corpus.c +++ b/fuzz/test-corpus.c @@ -16,31 +16,86 @@ #include #include +#include #include #include #include "fuzzer.h" +#include "internal/o_dir.h" -int main(int argc, char **argv) { - int n; +#if defined(_WIN32) && defined(_MAX_PATH) +# define PATH_MAX _MAX_PATH +#endif - FuzzerInitialize(&argc, &argv); +#ifndef PATH_MAX +# define PATH_MAX 4096 +#endif - for (n = 1; n < argc; ++n) { - struct stat st; - FILE *f; - unsigned char *buf; - size_t s; - - stat(argv[n], &st); - f = fopen(argv[n], "rb"); - if (f == NULL) - continue; - buf = malloc(st.st_size); +# if !defined(S_ISREG) +# define S_ISREG(m) ((m) & S_IFREG) +# endif + +static void testfile(const char *pathname) +{ + struct stat st; + FILE *f; + unsigned char *buf; + size_t s; + + if (stat(pathname, &st) < 0 || !S_ISREG(st.st_mode)) + return; + printf("# %s\n", pathname); + fflush(stdout); + f = fopen(pathname, "rb"); + if (f == NULL) + return; + buf = malloc(st.st_size); + if (buf != NULL) { s = fread(buf, 1, st.st_size, f); OPENSSL_assert(s == (size_t)st.st_size); FuzzerTestOneInput(buf, s); free(buf); - fclose(f); + } + fclose(f); +} + +int main(int argc, char **argv) { + int n; + + FuzzerInitialize(&argc, &argv); + + for (n = 1; n < argc; ++n) { + size_t dirname_len = strlen(argv[n]); + const char *filename = NULL; + char *pathname = NULL; + OPENSSL_DIR_CTX *ctx = NULL; + int wasdir = 0; + + /* + * We start with trying to read the given path as a directory. + */ + while ((filename = OPENSSL_DIR_read(&ctx, argv[n])) != NULL) { + wasdir = 1; + if (pathname == NULL) { + pathname = malloc(PATH_MAX); + if (pathname == NULL) + break; + strcpy(pathname, argv[n]); +#ifdef __VMS + if (strchr(":<]", pathname[dirname_len - 1]) == NULL) +#endif + pathname[dirname_len++] = '/'; + pathname[dirname_len] = '\0'; + } + strcpy(pathname + dirname_len, filename); + testfile(pathname); + } + OPENSSL_DIR_end(&ctx); + + /* If it wasn't a directory, treat it as a file instead */ + if (!wasdir) + testfile(argv[n]); + + free(pathname); } FuzzerCleanup(); diff --git a/test/recipes/99-test_fuzz.t b/test/recipes/99-test_fuzz.t index 9322ff7790..2c45fecc94 100644 --- a/test/recipes/99-test_fuzz.t +++ b/test/recipes/99-test_fuzz.t @@ -26,14 +26,14 @@ plan tests => scalar @fuzzers; foreach my $f (@fuzzers) { subtest "Fuzzing $f" => sub { - my @files = glob(srctop_file('fuzz', 'corpora', $f, '*')); - push @files, glob(srctop_file('fuzz', 'corpora', "$f-*", '*')); + my @dirs = glob(srctop_file('fuzz', 'corpora', $f)); + push @dirs, glob(srctop_file('fuzz', 'corpora', "$f-*")); - plan skip_all => "No corpora for $f-test" unless @files; + plan skip_all => "No corpora for $f-test" unless @dirs; - plan tests => scalar @files; + plan tests => scalar @dirs; - foreach (@files) { + foreach (@dirs) { ok(run(fuzz(["$f-test", $_]))); } } -- 2.34.1