[fuzz] Improve fuzzer build script and docs
* Remove the `make libFuzzer` target since it is broken and obsoleted by `CC=clang CXX=clang++ ./fuzz.py build all --enable-fuzzer`. The new `-fsanitize=fuzzer` is much better because it works with MSAN by default. * Improve the `./fuzz.py gen` command by making the input type explicit when creating a new target. * Update the `README` for `--enable-fuzzer`. Fixes #1727.
This commit is contained in:
parent
c9072ee674
commit
3982935aef
@ -113,15 +113,6 @@ zstd_frame_info: $(FUZZ_HEADERS) $(FUZZ_OBJ) zstd_frame_info.o
|
|||||||
libregression.a: $(FUZZ_HEADERS) $(PRGDIR)/util.h $(PRGDIR)/util.c regression_driver.o
|
libregression.a: $(FUZZ_HEADERS) $(PRGDIR)/util.h $(PRGDIR)/util.c regression_driver.o
|
||||||
$(AR) $(FUZZ_ARFLAGS) $@ regression_driver.o
|
$(AR) $(FUZZ_ARFLAGS) $@ regression_driver.o
|
||||||
|
|
||||||
# Install libfuzzer (not usable for MSAN testing)
|
|
||||||
# Provided for convenience. To use this library run make libFuzzer and
|
|
||||||
# set LDFLAGS=-L.
|
|
||||||
.PHONY: libFuzzer
|
|
||||||
libFuzzer:
|
|
||||||
@$(RM) -rf Fuzzer
|
|
||||||
@git clone https://chromium.googlesource.com/chromium/llvm-project/compiler-rt/lib/fuzzer Fuzzer
|
|
||||||
@cd Fuzzer && ./build.sh
|
|
||||||
|
|
||||||
corpora/%_seed_corpus.zip:
|
corpora/%_seed_corpus.zip:
|
||||||
@mkdir -p corpora
|
@mkdir -p corpora
|
||||||
$(DOWNLOAD) $@ $(CORPORA_URL_PREFIX)$*_seed_corpus.zip
|
$(DOWNLOAD) $@ $(CORPORA_URL_PREFIX)$*_seed_corpus.zip
|
||||||
|
@ -35,6 +35,8 @@ The environment variables can be overridden with the corresponding flags
|
|||||||
`--cc`, `--cflags`, etc.
|
`--cc`, `--cflags`, etc.
|
||||||
The specific fuzzing engine is selected with `LIB_FUZZING_ENGINE` or
|
The specific fuzzing engine is selected with `LIB_FUZZING_ENGINE` or
|
||||||
`--lib-fuzzing-engine`, the default is `libregression.a`.
|
`--lib-fuzzing-engine`, the default is `libregression.a`.
|
||||||
|
Alternatively, you can use Clang's built in fuzzing engine with
|
||||||
|
`--enable-fuzzer`.
|
||||||
It has flags that can easily set up sanitizers `--enable-{a,ub,m}san`, and
|
It has flags that can easily set up sanitizers `--enable-{a,ub,m}san`, and
|
||||||
coverage instrumentation `--enable-coverage`.
|
coverage instrumentation `--enable-coverage`.
|
||||||
It sets sane defaults which can be overridden with flags `--debug`,
|
It sets sane defaults which can be overridden with flags `--debug`,
|
||||||
@ -51,22 +53,25 @@ The command used to run the fuzzer is printed for debugging.
|
|||||||
## LibFuzzer
|
## LibFuzzer
|
||||||
|
|
||||||
```
|
```
|
||||||
# Build libfuzzer if necessary
|
|
||||||
make libFuzzer
|
|
||||||
# Build the fuzz targets
|
# Build the fuzz targets
|
||||||
./fuzz.py build all --enable-coverage --enable-asan --enable-ubsan --lib-fuzzing-engine Fuzzer/libFuzzer.a --cc clang --cxx clang++
|
./fuzz.py build all --enable-fuzzer --enable-asan --enable-ubsan --cc clang --cxx clang++
|
||||||
# OR equivalently
|
# OR equivalently
|
||||||
CC=clang CXX=clang++ LIB_FUZZING_ENGINE=Fuzzer/libFuzzer.a ./fuzz.py build all --enable-coverage --enable-asan --enable-ubsan
|
CC=clang CXX=clang++ ./fuzz.py build all --enable-fuzzer --enable-asan --enable-ubsan
|
||||||
# Run the fuzzer
|
# Run the fuzzer
|
||||||
./fuzz.py libfuzzer TARGET -max_len=8192 -jobs=4
|
./fuzz.py libfuzzer TARGET <libfuzzer args like -jobs=4>
|
||||||
```
|
```
|
||||||
|
|
||||||
where `TARGET` could be `simple_decompress`, `stream_round_trip`, etc.
|
where `TARGET` could be `simple_decompress`, `stream_round_trip`, etc.
|
||||||
|
|
||||||
### MSAN
|
### MSAN
|
||||||
|
|
||||||
Fuzzing with `libFuzzer` and `MSAN` will require building a C++ standard library
|
Fuzzing with `libFuzzer` and `MSAN` is as easy as:
|
||||||
and libFuzzer with MSAN.
|
|
||||||
|
```
|
||||||
|
CC=clang CXX=clang++ ./fuzz.py build all --enable-fuzzer --enable-msan
|
||||||
|
./fuzz.py libfuzzer TARGET <libfuzzer args>
|
||||||
|
```
|
||||||
|
|
||||||
`fuzz.py` respects the environment variables / flags `MSAN_EXTRA_CPPFLAGS`,
|
`fuzz.py` respects the environment variables / flags `MSAN_EXTRA_CPPFLAGS`,
|
||||||
`MSAN_EXTRA_CFLAGS`, `MSAN_EXTRA_CXXFLAGS`, `MSAN_EXTRA_LDFLAGS` to easily pass
|
`MSAN_EXTRA_CFLAGS`, `MSAN_EXTRA_CXXFLAGS`, `MSAN_EXTRA_LDFLAGS` to easily pass
|
||||||
the extra parameters only for MSAN.
|
the extra parameters only for MSAN.
|
||||||
|
@ -24,21 +24,38 @@ def abs_join(a, *p):
|
|||||||
return os.path.abspath(os.path.join(a, *p))
|
return os.path.abspath(os.path.join(a, *p))
|
||||||
|
|
||||||
|
|
||||||
|
class InputType(object):
|
||||||
|
RAW_DATA = 1
|
||||||
|
COMPRESSED_DATA = 2
|
||||||
|
|
||||||
|
|
||||||
|
class FrameType(object):
|
||||||
|
ZSTD = 1
|
||||||
|
BLOCK = 2
|
||||||
|
|
||||||
|
|
||||||
|
class TargetInfo(object):
|
||||||
|
def __init__(self, input_type, frame_type=FrameType.ZSTD):
|
||||||
|
self.input_type = input_type
|
||||||
|
self.frame_type = frame_type
|
||||||
|
|
||||||
|
|
||||||
# Constants
|
# Constants
|
||||||
FUZZ_DIR = os.path.abspath(os.path.dirname(__file__))
|
FUZZ_DIR = os.path.abspath(os.path.dirname(__file__))
|
||||||
CORPORA_DIR = abs_join(FUZZ_DIR, 'corpora')
|
CORPORA_DIR = abs_join(FUZZ_DIR, 'corpora')
|
||||||
TARGETS = [
|
TARGET_INFO = {
|
||||||
'simple_round_trip',
|
'simple_round_trip': TargetInfo(InputType.RAW_DATA),
|
||||||
'stream_round_trip',
|
'stream_round_trip': TargetInfo(InputType.RAW_DATA),
|
||||||
'block_round_trip',
|
'block_round_trip': TargetInfo(InputType.RAW_DATA, FrameType.BLOCK),
|
||||||
'simple_decompress',
|
'simple_decompress': TargetInfo(InputType.COMPRESSED_DATA),
|
||||||
'stream_decompress',
|
'stream_decompress': TargetInfo(InputType.COMPRESSED_DATA),
|
||||||
'block_decompress',
|
'block_decompress': TargetInfo(InputType.COMPRESSED_DATA, FrameType.BLOCK),
|
||||||
'dictionary_round_trip',
|
'dictionary_round_trip': TargetInfo(InputType.RAW_DATA),
|
||||||
'dictionary_decompress',
|
'dictionary_decompress': TargetInfo(InputType.COMPRESSED_DATA),
|
||||||
'zstd_frame_info',
|
'zstd_frame_info': TargetInfo(InputType.COMPRESSED_DATA),
|
||||||
'simple_compress',
|
'simple_compress': TargetInfo(InputType.RAW_DATA),
|
||||||
]
|
}
|
||||||
|
TARGETS = list(TARGET_INFO.keys())
|
||||||
ALL_TARGETS = TARGETS + ['all']
|
ALL_TARGETS = TARGETS + ['all']
|
||||||
FUZZ_RNG_SEED_SIZE = 4
|
FUZZ_RNG_SEED_SIZE = 4
|
||||||
|
|
||||||
@ -67,7 +84,7 @@ MSAN_EXTRA_LDFLAGS = os.environ.get('MSAN_EXTRA_LDFLAGS', '')
|
|||||||
def create(r):
|
def create(r):
|
||||||
d = os.path.abspath(r)
|
d = os.path.abspath(r)
|
||||||
if not os.path.isdir(d):
|
if not os.path.isdir(d):
|
||||||
os.mkdir(d)
|
os.makedirs(d)
|
||||||
return d
|
return d
|
||||||
|
|
||||||
|
|
||||||
@ -158,7 +175,7 @@ def compiler_version(cc, cxx):
|
|||||||
assert(b'clang' in cxx_version_bytes)
|
assert(b'clang' in cxx_version_bytes)
|
||||||
compiler = 'clang'
|
compiler = 'clang'
|
||||||
elif b'gcc' in cc_version_bytes:
|
elif b'gcc' in cc_version_bytes:
|
||||||
assert(b'gcc' in cxx_version_bytes)
|
assert(b'gcc' in cxx_version_bytes or b'g++' in cxx_version_bytes)
|
||||||
compiler = 'gcc'
|
compiler = 'gcc'
|
||||||
if compiler is not None:
|
if compiler is not None:
|
||||||
version_regex = b'([0-9])+\.([0-9])+\.([0-9])+'
|
version_regex = b'([0-9])+\.([0-9])+\.([0-9])+'
|
||||||
@ -699,7 +716,8 @@ def gen(args):
|
|||||||
'-o{}'.format(decompressed),
|
'-o{}'.format(decompressed),
|
||||||
]
|
]
|
||||||
|
|
||||||
if 'block_' in args.TARGET:
|
info = TARGET_INFO[args.TARGET]
|
||||||
|
if info.frame_type == FrameType.BLOCK:
|
||||||
cmd += [
|
cmd += [
|
||||||
'--gen-blocks',
|
'--gen-blocks',
|
||||||
'--max-block-size-log={}'.format(args.max_size_log)
|
'--max-block-size-log={}'.format(args.max_size_log)
|
||||||
@ -710,10 +728,11 @@ def gen(args):
|
|||||||
print(' '.join(cmd))
|
print(' '.join(cmd))
|
||||||
subprocess.check_call(cmd)
|
subprocess.check_call(cmd)
|
||||||
|
|
||||||
if '_round_trip' in args.TARGET:
|
if info.input_type == InputType.RAW_DATA:
|
||||||
print('using decompressed data in {}'.format(decompressed))
|
print('using decompressed data in {}'.format(decompressed))
|
||||||
samples = decompressed
|
samples = decompressed
|
||||||
elif '_decompress' in args.TARGET:
|
else:
|
||||||
|
assert info.input_type == InputType.COMPRESSED_DATA
|
||||||
print('using compressed data in {}'.format(compressed))
|
print('using compressed data in {}'.format(compressed))
|
||||||
samples = compressed
|
samples = compressed
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user