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 <bernd.edlinger@hotmail.de>
Reviewed-by: Rich Salz <rsalz@openssl.org>
(Merged from https://github.com/openssl/openssl/pull/5776)
This commit is contained in:
Richard Levitte 2018-03-28 15:46:28 +02:00
parent 00701e5ea8
commit 9d74090959
2 changed files with 74 additions and 19 deletions

View File

@ -16,9 +16,47 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <openssl/crypto.h>
#include "fuzzer.h"
#include "internal/o_dir.h"
#if defined(_WIN32) && defined(_MAX_PATH)
# define PATH_MAX _MAX_PATH
#endif
#ifndef PATH_MAX
# define PATH_MAX 4096
#endif
# 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);
}
int main(int argc, char **argv) {
int n;
@ -26,21 +64,38 @@ int main(int argc, char **argv) {
FuzzerInitialize(&argc, &argv);
for (n = 1; n < argc; ++n) {
struct stat st;
FILE *f;
unsigned char *buf;
size_t s;
size_t dirname_len = strlen(argv[n]);
const char *filename = NULL;
char *pathname = NULL;
OPENSSL_DIR_CTX *ctx = NULL;
int wasdir = 0;
stat(argv[n], &st);
f = fopen(argv[n], "rb");
if (f == NULL)
continue;
buf = malloc(st.st_size);
s = fread(buf, 1, st.st_size, f);
OPENSSL_assert(s == (size_t)st.st_size);
FuzzerTestOneInput(buf, s);
free(buf);
fclose(f);
/*
* 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();

View File

@ -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", $_])));
}
}