Merge branch 'dev' into extract_sequences_api
This commit is contained in:
+2
-11
@@ -40,8 +40,8 @@ FUZZ_LDFLAGS := -pthread $(LDFLAGS)
|
||||
FUZZ_ARFLAGS := $(ARFLAGS)
|
||||
FUZZ_TARGET_FLAGS = $(FUZZ_CPPFLAGS) $(FUZZ_CXXFLAGS) $(FUZZ_LDFLAGS)
|
||||
|
||||
FUZZ_HEADERS := fuzz_helpers.h fuzz.h zstd_helpers.h
|
||||
FUZZ_SRC := $(PRGDIR)/util.c zstd_helpers.c
|
||||
FUZZ_HEADERS := fuzz_helpers.h fuzz.h zstd_helpers.h fuzz_data_producer.h
|
||||
FUZZ_SRC := $(PRGDIR)/util.c zstd_helpers.c fuzz_data_producer.c
|
||||
|
||||
ZSTDCOMMON_SRC := $(ZSTDDIR)/common/*.c
|
||||
ZSTDCOMP_SRC := $(ZSTDDIR)/compress/*.c
|
||||
@@ -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
|
||||
$(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:
|
||||
@mkdir -p corpora
|
||||
$(DOWNLOAD) $@ $(CORPORA_URL_PREFIX)$*_seed_corpus.zip
|
||||
|
||||
+13
-8
@@ -35,6 +35,8 @@ The environment variables can be overridden with the corresponding flags
|
||||
`--cc`, `--cflags`, etc.
|
||||
The specific fuzzing engine is selected with `LIB_FUZZING_ENGINE` or
|
||||
`--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
|
||||
coverage instrumentation `--enable-coverage`.
|
||||
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
|
||||
|
||||
```
|
||||
# Build libfuzzer if necessary
|
||||
make libFuzzer
|
||||
# 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
|
||||
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
|
||||
./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.
|
||||
|
||||
### MSAN
|
||||
|
||||
Fuzzing with `libFuzzer` and `MSAN` will require building a C++ standard library
|
||||
and libFuzzer with MSAN.
|
||||
Fuzzing with `libFuzzer` and `MSAN` is as easy as:
|
||||
|
||||
```
|
||||
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`,
|
||||
`MSAN_EXTRA_CFLAGS`, `MSAN_EXTRA_CXXFLAGS`, `MSAN_EXTRA_LDFLAGS` to easily pass
|
||||
the extra parameters only for MSAN.
|
||||
@@ -85,7 +90,7 @@ CC=afl-clang CXX=afl-clang++ ./fuzz.py build all --enable-asan --enable-ubsan
|
||||
|
||||
## Regression Testing
|
||||
|
||||
The regression rest supports the `all` target to run all the fuzzers in one
|
||||
The regression test supports the `all` target to run all the fuzzers in one
|
||||
command.
|
||||
|
||||
```
|
||||
|
||||
@@ -28,8 +28,6 @@ int LLVMFuzzerTestOneInput(const uint8_t *src, size_t size)
|
||||
{
|
||||
size_t const neededBufSize = ZSTD_BLOCKSIZE_MAX;
|
||||
|
||||
FUZZ_seed(&src, &size);
|
||||
|
||||
/* Allocate all buffers and contexts if not already allocated */
|
||||
if (neededBufSize > bufSize) {
|
||||
free(rBuf);
|
||||
|
||||
@@ -20,21 +20,20 @@
|
||||
#include <string.h>
|
||||
#include "fuzz_helpers.h"
|
||||
#include "zstd.h"
|
||||
|
||||
static const int kMaxClevel = 19;
|
||||
#include "zstd_helpers.h"
|
||||
#include "fuzz_data_producer.h"
|
||||
|
||||
static ZSTD_CCtx *cctx = NULL;
|
||||
static ZSTD_DCtx *dctx = NULL;
|
||||
static void* cBuf = NULL;
|
||||
static void* rBuf = NULL;
|
||||
static size_t bufSize = 0;
|
||||
static uint32_t seed;
|
||||
|
||||
static size_t roundTripTest(void *result, size_t resultCapacity,
|
||||
void *compressed, size_t compressedCapacity,
|
||||
const void *src, size_t srcSize)
|
||||
const void *src, size_t srcSize,
|
||||
int cLevel)
|
||||
{
|
||||
int const cLevel = FUZZ_rand(&seed) % kMaxClevel;
|
||||
ZSTD_parameters const params = ZSTD_getParams(cLevel, srcSize, 0);
|
||||
size_t ret = ZSTD_compressBegin_advanced(cctx, NULL, 0, params, srcSize);
|
||||
FUZZ_ZASSERT(ret);
|
||||
@@ -52,12 +51,16 @@ static size_t roundTripTest(void *result, size_t resultCapacity,
|
||||
|
||||
int LLVMFuzzerTestOneInput(const uint8_t *src, size_t size)
|
||||
{
|
||||
size_t neededBufSize;
|
||||
/* Give a random portion of src data to the producer, to use for
|
||||
parameter generation. The rest will be used for (de)compression */
|
||||
FUZZ_dataProducer_t *producer = FUZZ_dataProducer_create(src, size);
|
||||
size = FUZZ_dataProducer_reserveDataPrefix(producer);
|
||||
|
||||
seed = FUZZ_seed(&src, &size);
|
||||
neededBufSize = size;
|
||||
int const cLevel = FUZZ_dataProducer_int32Range(producer, kMinClevel, kMaxClevel);
|
||||
|
||||
size_t neededBufSize = size;
|
||||
if (size > ZSTD_BLOCKSIZE_MAX)
|
||||
return 0;
|
||||
size = ZSTD_BLOCKSIZE_MAX;
|
||||
|
||||
/* Allocate all buffers and contexts if not already allocated */
|
||||
if (neededBufSize > bufSize || !cBuf || !rBuf) {
|
||||
@@ -79,11 +82,13 @@ int LLVMFuzzerTestOneInput(const uint8_t *src, size_t size)
|
||||
|
||||
{
|
||||
size_t const result =
|
||||
roundTripTest(rBuf, neededBufSize, cBuf, neededBufSize, src, size);
|
||||
roundTripTest(rBuf, neededBufSize, cBuf, neededBufSize, src, size,
|
||||
cLevel);
|
||||
FUZZ_ZASSERT(result);
|
||||
FUZZ_ASSERT_MSG(result == size, "Incorrect regenerated size");
|
||||
FUZZ_ASSERT_MSG(!memcmp(src, rBuf, size), "Corruption!");
|
||||
}
|
||||
FUZZ_dataProducer_free(producer);
|
||||
#ifndef STATEFUL_FUZZING
|
||||
ZSTD_freeCCtx(cctx); cctx = NULL;
|
||||
ZSTD_freeDCtx(dctx); dctx = NULL;
|
||||
|
||||
@@ -18,33 +18,37 @@
|
||||
#include <stdio.h>
|
||||
#include "fuzz_helpers.h"
|
||||
#include "zstd_helpers.h"
|
||||
#include "fuzz_data_producer.h"
|
||||
|
||||
static ZSTD_DCtx *dctx = NULL;
|
||||
|
||||
int LLVMFuzzerTestOneInput(const uint8_t *src, size_t size)
|
||||
{
|
||||
uint32_t seed = FUZZ_seed(&src, &size);
|
||||
/* Give a random portion of src data to the producer, to use for
|
||||
parameter generation. The rest will be used for (de)compression */
|
||||
FUZZ_dataProducer_t *producer = FUZZ_dataProducer_create(src, size);
|
||||
size = FUZZ_dataProducer_reserveDataPrefix(producer);
|
||||
|
||||
FUZZ_dict_t dict;
|
||||
ZSTD_DDict* ddict = NULL;
|
||||
int i;
|
||||
|
||||
if (!dctx) {
|
||||
dctx = ZSTD_createDCtx();
|
||||
FUZZ_ASSERT(dctx);
|
||||
}
|
||||
dict = FUZZ_train(src, size, &seed);
|
||||
if (FUZZ_rand32(&seed, 0, 1) == 0) {
|
||||
dict = FUZZ_train(src, size, producer);
|
||||
if (FUZZ_dataProducer_uint32Range(producer, 0, 1) == 0) {
|
||||
ddict = ZSTD_createDDict(dict.buff, dict.size);
|
||||
FUZZ_ASSERT(ddict);
|
||||
} else {
|
||||
FUZZ_ZASSERT(ZSTD_DCtx_loadDictionary_advanced(
|
||||
dctx, dict.buff, dict.size,
|
||||
(ZSTD_dictLoadMethod_e)FUZZ_rand32(&seed, 0, 1),
|
||||
(ZSTD_dictContentType_e)FUZZ_rand32(&seed, 0, 2)));
|
||||
(ZSTD_dictLoadMethod_e)FUZZ_dataProducer_uint32Range(producer, 0, 1),
|
||||
(ZSTD_dictContentType_e)FUZZ_dataProducer_uint32Range(producer, 0, 2)));
|
||||
}
|
||||
/* Run it 10 times over 10 output sizes. Reuse the context and dict. */
|
||||
for (i = 0; i < 10; ++i) {
|
||||
size_t const bufSize = FUZZ_rand32(&seed, 0, 2 * size);
|
||||
|
||||
{
|
||||
size_t const bufSize = FUZZ_dataProducer_uint32Range(producer, 0, 10 * size);
|
||||
void* rBuf = malloc(bufSize);
|
||||
FUZZ_ASSERT(rBuf);
|
||||
if (ddict) {
|
||||
@@ -55,6 +59,7 @@ int LLVMFuzzerTestOneInput(const uint8_t *src, size_t size)
|
||||
free(rBuf);
|
||||
}
|
||||
free(dict.buff);
|
||||
FUZZ_dataProducer_free(producer);
|
||||
ZSTD_freeDDict(ddict);
|
||||
#ifndef STATEFUL_FUZZING
|
||||
ZSTD_freeDCtx(dctx); dctx = NULL;
|
||||
|
||||
@@ -19,22 +19,21 @@
|
||||
#include <string.h>
|
||||
#include "fuzz_helpers.h"
|
||||
#include "zstd_helpers.h"
|
||||
|
||||
static const int kMaxClevel = 19;
|
||||
#include "fuzz_data_producer.h"
|
||||
|
||||
static ZSTD_CCtx *cctx = NULL;
|
||||
static ZSTD_DCtx *dctx = NULL;
|
||||
static uint32_t seed;
|
||||
|
||||
static size_t roundTripTest(void *result, size_t resultCapacity,
|
||||
void *compressed, size_t compressedCapacity,
|
||||
const void *src, size_t srcSize)
|
||||
const void *src, size_t srcSize,
|
||||
FUZZ_dataProducer_t *producer)
|
||||
{
|
||||
ZSTD_dictContentType_e dictContentType = ZSTD_dct_auto;
|
||||
FUZZ_dict_t dict = FUZZ_train(src, srcSize, &seed);
|
||||
FUZZ_dict_t dict = FUZZ_train(src, srcSize, producer);
|
||||
size_t cSize;
|
||||
if ((FUZZ_rand(&seed) & 15) == 0) {
|
||||
int const cLevel = FUZZ_rand(&seed) % kMaxClevel;
|
||||
if (FUZZ_dataProducer_uint32Range(producer, 0, 15) == 0) {
|
||||
int const cLevel = FUZZ_dataProducer_int32Range(producer, kMinClevel, kMaxClevel);
|
||||
|
||||
cSize = ZSTD_compress_usingDict(cctx,
|
||||
compressed, compressedCapacity,
|
||||
@@ -42,20 +41,20 @@ static size_t roundTripTest(void *result, size_t resultCapacity,
|
||||
dict.buff, dict.size,
|
||||
cLevel);
|
||||
} else {
|
||||
dictContentType = FUZZ_rand32(&seed, 0, 2);
|
||||
FUZZ_setRandomParameters(cctx, srcSize, &seed);
|
||||
dictContentType = FUZZ_dataProducer_uint32Range(producer, 0, 2);
|
||||
FUZZ_setRandomParameters(cctx, srcSize, producer);
|
||||
/* Disable checksum so we can use sizes smaller than compress bound. */
|
||||
FUZZ_ZASSERT(ZSTD_CCtx_setParameter(cctx, ZSTD_c_checksumFlag, 0));
|
||||
FUZZ_ZASSERT(ZSTD_CCtx_loadDictionary_advanced(
|
||||
cctx, dict.buff, dict.size,
|
||||
(ZSTD_dictLoadMethod_e)FUZZ_rand32(&seed, 0, 1),
|
||||
(ZSTD_dictLoadMethod_e)FUZZ_dataProducer_uint32Range(producer, 0, 1),
|
||||
dictContentType));
|
||||
cSize = ZSTD_compress2(cctx, compressed, compressedCapacity, src, srcSize);
|
||||
}
|
||||
FUZZ_ZASSERT(cSize);
|
||||
FUZZ_ZASSERT(ZSTD_DCtx_loadDictionary_advanced(
|
||||
dctx, dict.buff, dict.size,
|
||||
(ZSTD_dictLoadMethod_e)FUZZ_rand32(&seed, 0, 1),
|
||||
(ZSTD_dictLoadMethod_e)FUZZ_dataProducer_uint32Range(producer, 0, 1),
|
||||
dictContentType));
|
||||
{
|
||||
size_t const ret = ZSTD_decompressDCtx(
|
||||
@@ -67,17 +66,20 @@ static size_t roundTripTest(void *result, size_t resultCapacity,
|
||||
|
||||
int LLVMFuzzerTestOneInput(const uint8_t *src, size_t size)
|
||||
{
|
||||
/* Give a random portion of src data to the producer, to use for
|
||||
parameter generation. The rest will be used for (de)compression */
|
||||
FUZZ_dataProducer_t *producer = FUZZ_dataProducer_create(src, size);
|
||||
size = FUZZ_dataProducer_reserveDataPrefix(producer);
|
||||
|
||||
size_t const rBufSize = size;
|
||||
void* rBuf = malloc(rBufSize);
|
||||
size_t cBufSize = ZSTD_compressBound(size);
|
||||
void* cBuf;
|
||||
|
||||
seed = FUZZ_seed(&src, &size);
|
||||
void *cBuf;
|
||||
/* Half of the time fuzz with a 1 byte smaller output size.
|
||||
* This will still succeed because we force the checksum to be disabled,
|
||||
* giving us 4 bytes of overhead.
|
||||
*/
|
||||
cBufSize -= FUZZ_rand32(&seed, 0, 1);
|
||||
cBufSize -= FUZZ_dataProducer_uint32Range(producer, 0, 1);
|
||||
cBuf = malloc(cBufSize);
|
||||
|
||||
if (!cctx) {
|
||||
@@ -91,13 +93,14 @@ int LLVMFuzzerTestOneInput(const uint8_t *src, size_t size)
|
||||
|
||||
{
|
||||
size_t const result =
|
||||
roundTripTest(rBuf, rBufSize, cBuf, cBufSize, src, size);
|
||||
roundTripTest(rBuf, rBufSize, cBuf, cBufSize, src, size, producer);
|
||||
FUZZ_ZASSERT(result);
|
||||
FUZZ_ASSERT_MSG(result == size, "Incorrect regenerated size");
|
||||
FUZZ_ASSERT_MSG(!memcmp(src, rBuf, size), "Corruption!");
|
||||
}
|
||||
free(rBuf);
|
||||
free(cBuf);
|
||||
FUZZ_dataProducer_free(producer);
|
||||
#ifndef STATEFUL_FUZZING
|
||||
ZSTD_freeCCtx(cctx); cctx = NULL;
|
||||
ZSTD_freeDCtx(dctx); dctx = NULL;
|
||||
|
||||
@@ -17,12 +17,6 @@
|
||||
* test code paths which are only executed when contexts are reused.
|
||||
* WARNING: Makes reproducing crashes much harder.
|
||||
* Default: Not defined.
|
||||
* @param FUZZ_RNG_SEED_SIZE:
|
||||
* The number of bytes of the source to look at when constructing a seed
|
||||
* for the deterministic RNG. These bytes are discarded before passing
|
||||
* the data to zstd functions. Every fuzzer initializes the RNG exactly
|
||||
* once before doing anything else, even if it is unused.
|
||||
* Default: 4.
|
||||
* @param DEBUGLEVEL:
|
||||
* This is a parameter for the zstd library. Defining `DEBUGLEVEL=1`
|
||||
* enables assert() statements in the zstd library. Higher levels enable
|
||||
@@ -42,10 +36,6 @@
|
||||
#ifndef FUZZ_H
|
||||
#define FUZZ_H
|
||||
|
||||
#ifndef FUZZ_RNG_SEED_SIZE
|
||||
# define FUZZ_RNG_SEED_SIZE 4
|
||||
#endif
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
|
||||
+38
-21
@@ -24,21 +24,38 @@ def abs_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
|
||||
FUZZ_DIR = os.path.abspath(os.path.dirname(__file__))
|
||||
CORPORA_DIR = abs_join(FUZZ_DIR, 'corpora')
|
||||
TARGETS = [
|
||||
'simple_round_trip',
|
||||
'stream_round_trip',
|
||||
'block_round_trip',
|
||||
'simple_decompress',
|
||||
'stream_decompress',
|
||||
'block_decompress',
|
||||
'dictionary_round_trip',
|
||||
'dictionary_decompress',
|
||||
'zstd_frame_info',
|
||||
'simple_compress',
|
||||
]
|
||||
TARGET_INFO = {
|
||||
'simple_round_trip': TargetInfo(InputType.RAW_DATA),
|
||||
'stream_round_trip': TargetInfo(InputType.RAW_DATA),
|
||||
'block_round_trip': TargetInfo(InputType.RAW_DATA, FrameType.BLOCK),
|
||||
'simple_decompress': TargetInfo(InputType.COMPRESSED_DATA),
|
||||
'stream_decompress': TargetInfo(InputType.COMPRESSED_DATA),
|
||||
'block_decompress': TargetInfo(InputType.COMPRESSED_DATA, FrameType.BLOCK),
|
||||
'dictionary_round_trip': TargetInfo(InputType.RAW_DATA),
|
||||
'dictionary_decompress': TargetInfo(InputType.COMPRESSED_DATA),
|
||||
'zstd_frame_info': TargetInfo(InputType.COMPRESSED_DATA),
|
||||
'simple_compress': TargetInfo(InputType.RAW_DATA),
|
||||
}
|
||||
TARGETS = list(TARGET_INFO.keys())
|
||||
ALL_TARGETS = TARGETS + ['all']
|
||||
FUZZ_RNG_SEED_SIZE = 4
|
||||
|
||||
@@ -67,7 +84,7 @@ MSAN_EXTRA_LDFLAGS = os.environ.get('MSAN_EXTRA_LDFLAGS', '')
|
||||
def create(r):
|
||||
d = os.path.abspath(r)
|
||||
if not os.path.isdir(d):
|
||||
os.mkdir(d)
|
||||
os.makedirs(d)
|
||||
return d
|
||||
|
||||
|
||||
@@ -158,7 +175,7 @@ def compiler_version(cc, cxx):
|
||||
assert(b'clang' in cxx_version_bytes)
|
||||
compiler = 'clang'
|
||||
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'
|
||||
if compiler is not None:
|
||||
version_regex = b'([0-9])+\.([0-9])+\.([0-9])+'
|
||||
@@ -643,7 +660,7 @@ def gen_parser(args):
|
||||
parser.add_argument(
|
||||
'--max-size-log',
|
||||
type=int,
|
||||
default=13,
|
||||
default=18,
|
||||
help='Maximum sample size to generate')
|
||||
parser.add_argument(
|
||||
'--seed',
|
||||
@@ -699,10 +716,11 @@ def gen(args):
|
||||
'-o{}'.format(decompressed),
|
||||
]
|
||||
|
||||
if 'block_' in args.TARGET:
|
||||
info = TARGET_INFO[args.TARGET]
|
||||
if info.frame_type == FrameType.BLOCK:
|
||||
cmd += [
|
||||
'--gen-blocks',
|
||||
'--max-block-size-log={}'.format(args.max_size_log)
|
||||
'--max-block-size-log={}'.format(min(args.max_size_log, 17))
|
||||
]
|
||||
else:
|
||||
cmd += ['--max-content-size-log={}'.format(args.max_size_log)]
|
||||
@@ -710,10 +728,11 @@ def gen(args):
|
||||
print(' '.join(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))
|
||||
samples = decompressed
|
||||
elif '_decompress' in args.TARGET:
|
||||
else:
|
||||
assert info.input_type == InputType.COMPRESSED_DATA
|
||||
print('using compressed data in {}'.format(compressed))
|
||||
samples = compressed
|
||||
|
||||
@@ -721,10 +740,8 @@ def gen(args):
|
||||
for name in os.listdir(samples):
|
||||
samplename = abs_join(samples, name)
|
||||
outname = abs_join(seed, name)
|
||||
rng_seed = os.urandom(args.fuzz_rng_seed_size)
|
||||
with open(samplename, 'rb') as sample:
|
||||
with open(outname, 'wb') as out:
|
||||
out.write(rng_seed)
|
||||
CHUNK_SIZE = 131072
|
||||
chunk = sample.read(CHUNK_SIZE)
|
||||
while len(chunk) > 0:
|
||||
|
||||
@@ -0,0 +1,85 @@
|
||||
/*
|
||||
* Copyright (c) 2016-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under both the BSD-style license (found in the
|
||||
* LICENSE file in the root directory of this source tree) and the GPLv2 (found
|
||||
* in the COPYING file in the root directory of this source tree).
|
||||
*/
|
||||
|
||||
#include "fuzz_data_producer.h"
|
||||
|
||||
struct FUZZ_dataProducer_s{
|
||||
const uint8_t *data;
|
||||
size_t size;
|
||||
};
|
||||
|
||||
FUZZ_dataProducer_t *FUZZ_dataProducer_create(const uint8_t *data, size_t size) {
|
||||
FUZZ_dataProducer_t *producer = malloc(sizeof(FUZZ_dataProducer_t));
|
||||
|
||||
FUZZ_ASSERT(producer != NULL);
|
||||
|
||||
producer->data = data;
|
||||
producer->size = size;
|
||||
return producer;
|
||||
}
|
||||
|
||||
void FUZZ_dataProducer_free(FUZZ_dataProducer_t *producer) { free(producer); }
|
||||
|
||||
uint32_t FUZZ_dataProducer_uint32Range(FUZZ_dataProducer_t *producer, uint32_t min,
|
||||
uint32_t max) {
|
||||
FUZZ_ASSERT(min <= max);
|
||||
|
||||
uint32_t range = max - min;
|
||||
uint32_t rolling = range;
|
||||
uint32_t result = 0;
|
||||
|
||||
while (rolling > 0 && producer->size > 0) {
|
||||
uint8_t next = *(producer->data + producer->size - 1);
|
||||
producer->size -= 1;
|
||||
result = (result << 8) | next;
|
||||
rolling >>= 8;
|
||||
}
|
||||
|
||||
if (range == 0xffffffff) {
|
||||
return result;
|
||||
}
|
||||
|
||||
return min + result % (range + 1);
|
||||
}
|
||||
|
||||
uint32_t FUZZ_dataProducer_uint32(FUZZ_dataProducer_t *producer) {
|
||||
return FUZZ_dataProducer_uint32Range(producer, 0, 0xffffffff);
|
||||
}
|
||||
|
||||
int32_t FUZZ_dataProducer_int32Range(FUZZ_dataProducer_t *producer,
|
||||
int32_t min, int32_t max)
|
||||
{
|
||||
FUZZ_ASSERT(min <= max);
|
||||
|
||||
if (min < 0)
|
||||
return (int)FUZZ_dataProducer_uint32Range(producer, 0, max - min) + min;
|
||||
|
||||
return FUZZ_dataProducer_uint32Range(producer, min, max);
|
||||
}
|
||||
|
||||
size_t FUZZ_dataProducer_remainingBytes(FUZZ_dataProducer_t *producer){
|
||||
return producer->size;
|
||||
}
|
||||
|
||||
size_t FUZZ_dataProducer_contract(FUZZ_dataProducer_t *producer, size_t newSize)
|
||||
{
|
||||
newSize = newSize > producer->size ? producer->size : newSize;
|
||||
|
||||
size_t remaining = producer->size - newSize;
|
||||
producer->data = producer->data + remaining;
|
||||
producer->size = newSize;
|
||||
return remaining;
|
||||
}
|
||||
|
||||
size_t FUZZ_dataProducer_reserveDataPrefix(FUZZ_dataProducer_t *producer)
|
||||
{
|
||||
size_t producerSliceSize = FUZZ_dataProducer_uint32Range(
|
||||
producer, 0, producer->size);
|
||||
return FUZZ_dataProducer_contract(producer, producerSliceSize);
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
/*
|
||||
* Copyright (c) 2016-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under both the BSD-style license (found in the
|
||||
* LICENSE file in the root directory of this source tree) and the GPLv2 (found
|
||||
* in the COPYING file in the root directory of this source tree).
|
||||
*/
|
||||
|
||||
/**
|
||||
* Helper APIs for generating random data from input data stream.
|
||||
The producer reads bytes from the end of the input and appends them together
|
||||
to generate a random number in the requested range. If it runs out of input
|
||||
data, it will keep returning the same value (min) over and over again.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef FUZZ_DATA_PRODUCER_H
|
||||
#define FUZZ_DATA_PRODUCER_H
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "fuzz_helpers.h"
|
||||
|
||||
/* Struct used for maintaining the state of the data */
|
||||
typedef struct FUZZ_dataProducer_s FUZZ_dataProducer_t;
|
||||
|
||||
/* Returns a data producer state struct. Use for producer initialization. */
|
||||
FUZZ_dataProducer_t *FUZZ_dataProducer_create(const uint8_t *data, size_t size);
|
||||
|
||||
/* Frees the data producer */
|
||||
void FUZZ_dataProducer_free(FUZZ_dataProducer_t *producer);
|
||||
|
||||
/* Returns value between [min, max] */
|
||||
uint32_t FUZZ_dataProducer_uint32Range(FUZZ_dataProducer_t *producer, uint32_t min,
|
||||
uint32_t max);
|
||||
|
||||
/* Returns a uint32 value */
|
||||
uint32_t FUZZ_dataProducer_uint32(FUZZ_dataProducer_t *producer);
|
||||
|
||||
/* Returns a signed value between [min, max] */
|
||||
int32_t FUZZ_dataProducer_int32Range(FUZZ_dataProducer_t *producer,
|
||||
int32_t min, int32_t max);
|
||||
|
||||
/* Returns the size of the remaining bytes of data in the producer */
|
||||
size_t FUZZ_dataProducer_remainingBytes(FUZZ_dataProducer_t *producer);
|
||||
|
||||
/* Restricts the producer to only the last newSize bytes of data.
|
||||
If newSize > current data size, nothing happens. Returns the number of bytes
|
||||
the producer won't use anymore, after contracting. */
|
||||
size_t FUZZ_dataProducer_contract(FUZZ_dataProducer_t *producer, size_t newSize);
|
||||
|
||||
/* Restricts the producer to use only the last X bytes of data, where X is
|
||||
a random number in the interval [0, data_size]. Returns the size of the
|
||||
remaining data the producer won't use anymore (the prefix). */
|
||||
size_t FUZZ_dataProducer_reserveDataPrefix(FUZZ_dataProducer_t *producer);
|
||||
#endif // FUZZ_DATA_PRODUCER_H
|
||||
@@ -14,6 +14,7 @@
|
||||
#ifndef FUZZ_HELPERS_H
|
||||
#define FUZZ_HELPERS_H
|
||||
|
||||
#include "debug.h"
|
||||
#include "fuzz.h"
|
||||
#include "xxhash.h"
|
||||
#include "zstd.h"
|
||||
@@ -54,37 +55,6 @@ extern "C" {
|
||||
#define FUZZ_STATIC static
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Deterministically constructs a seed based on the fuzz input.
|
||||
* Consumes up to the first FUZZ_RNG_SEED_SIZE bytes of the input.
|
||||
*/
|
||||
FUZZ_STATIC uint32_t FUZZ_seed(uint8_t const **src, size_t* size) {
|
||||
uint8_t const *data = *src;
|
||||
size_t const toHash = MIN(FUZZ_RNG_SEED_SIZE, *size);
|
||||
*size -= toHash;
|
||||
*src += toHash;
|
||||
return XXH32(data, toHash, 0);
|
||||
}
|
||||
|
||||
#define FUZZ_rotl32(x, r) (((x) << (r)) | ((x) >> (32 - (r))))
|
||||
|
||||
FUZZ_STATIC uint32_t FUZZ_rand(uint32_t *state) {
|
||||
static const uint32_t prime1 = 2654435761U;
|
||||
static const uint32_t prime2 = 2246822519U;
|
||||
uint32_t rand32 = *state;
|
||||
rand32 *= prime1;
|
||||
rand32 += prime2;
|
||||
rand32 = FUZZ_rotl32(rand32, 13);
|
||||
*state = rand32;
|
||||
return rand32 >> 5;
|
||||
}
|
||||
|
||||
/* Returns a random numer in the range [min, max]. */
|
||||
FUZZ_STATIC uint32_t FUZZ_rand32(uint32_t *state, uint32_t min, uint32_t max) {
|
||||
uint32_t random = FUZZ_rand(state);
|
||||
return min + (random % (max - min + 1));
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -36,6 +36,7 @@ int main(int argc, char const **argv) {
|
||||
fprintf(stderr, "WARNING: No files passed to %s\n", argv[0]);
|
||||
for (i = 0; i < numFiles; ++i) {
|
||||
char const *fileName = files[i];
|
||||
DEBUGLOG(3, "Running %s", fileName);
|
||||
size_t const fileSize = UTIL_getFileSize(fileName);
|
||||
size_t readSize;
|
||||
FILE *file;
|
||||
|
||||
@@ -18,28 +18,33 @@
|
||||
#include <stdio.h>
|
||||
#include "fuzz_helpers.h"
|
||||
#include "zstd.h"
|
||||
#include "zstd_helpers.h"
|
||||
#include "fuzz_data_producer.h"
|
||||
|
||||
static ZSTD_CCtx *cctx = NULL;
|
||||
|
||||
int LLVMFuzzerTestOneInput(const uint8_t *src, size_t size)
|
||||
{
|
||||
uint32_t seed = FUZZ_seed(&src, &size);
|
||||
/* Give a random portion of src data to the producer, to use for
|
||||
parameter generation. The rest will be used for (de)compression */
|
||||
FUZZ_dataProducer_t *producer = FUZZ_dataProducer_create(src, size);
|
||||
size = FUZZ_dataProducer_reserveDataPrefix(producer);
|
||||
|
||||
size_t const maxSize = ZSTD_compressBound(size);
|
||||
int i;
|
||||
size_t const bufSize = FUZZ_dataProducer_uint32Range(producer, 0, maxSize);
|
||||
|
||||
int const cLevel = FUZZ_dataProducer_int32Range(producer, kMinClevel, kMaxClevel);
|
||||
|
||||
if (!cctx) {
|
||||
cctx = ZSTD_createCCtx();
|
||||
FUZZ_ASSERT(cctx);
|
||||
}
|
||||
/* Run it 10 times over 10 output sizes. Reuse the context. */
|
||||
for (i = 0; i < 10; ++i) {
|
||||
int const level = (int)FUZZ_rand32(&seed, 0, 19 + 3) - 3; /* [-3, 19] */
|
||||
size_t const bufSize = FUZZ_rand32(&seed, 0, maxSize);
|
||||
void* rBuf = malloc(bufSize);
|
||||
FUZZ_ASSERT(rBuf);
|
||||
ZSTD_compressCCtx(cctx, rBuf, bufSize, src, size, level);
|
||||
free(rBuf);
|
||||
}
|
||||
|
||||
void *rBuf = malloc(bufSize);
|
||||
FUZZ_ASSERT(rBuf);
|
||||
ZSTD_compressCCtx(cctx, rBuf, bufSize, src, size, cLevel);
|
||||
free(rBuf);
|
||||
FUZZ_dataProducer_free(producer);
|
||||
#ifndef STATEFUL_FUZZING
|
||||
ZSTD_freeCCtx(cctx); cctx = NULL;
|
||||
#endif
|
||||
|
||||
@@ -17,26 +17,30 @@
|
||||
#include <stdio.h>
|
||||
#include "fuzz_helpers.h"
|
||||
#include "zstd.h"
|
||||
#include "fuzz_data_producer.h"
|
||||
|
||||
static ZSTD_DCtx *dctx = NULL;
|
||||
|
||||
int LLVMFuzzerTestOneInput(const uint8_t *src, size_t size)
|
||||
{
|
||||
/* Give a random portion of src data to the producer, to use for
|
||||
parameter generation. The rest will be used for (de)compression */
|
||||
FUZZ_dataProducer_t *producer = FUZZ_dataProducer_create(src, size);
|
||||
size = FUZZ_dataProducer_reserveDataPrefix(producer);
|
||||
|
||||
uint32_t seed = FUZZ_seed(&src, &size);
|
||||
int i;
|
||||
if (!dctx) {
|
||||
dctx = ZSTD_createDCtx();
|
||||
FUZZ_ASSERT(dctx);
|
||||
}
|
||||
/* Run it 10 times over 10 output sizes. Reuse the context. */
|
||||
for (i = 0; i < 10; ++i) {
|
||||
size_t const bufSize = FUZZ_rand32(&seed, 0, 2 * size);
|
||||
void* rBuf = malloc(bufSize);
|
||||
FUZZ_ASSERT(rBuf);
|
||||
ZSTD_decompressDCtx(dctx, rBuf, bufSize, src, size);
|
||||
free(rBuf);
|
||||
}
|
||||
|
||||
size_t const bufSize = FUZZ_dataProducer_uint32Range(producer, 0, 10 * size);
|
||||
void *rBuf = malloc(bufSize);
|
||||
FUZZ_ASSERT(rBuf);
|
||||
|
||||
ZSTD_decompressDCtx(dctx, rBuf, bufSize, src, size);
|
||||
free(rBuf);
|
||||
|
||||
FUZZ_dataProducer_free(producer);
|
||||
|
||||
#ifndef STATEFUL_FUZZING
|
||||
ZSTD_freeDCtx(dctx); dctx = NULL;
|
||||
|
||||
@@ -20,23 +20,23 @@
|
||||
#include <string.h>
|
||||
#include "fuzz_helpers.h"
|
||||
#include "zstd_helpers.h"
|
||||
|
||||
static const int kMaxClevel = 19;
|
||||
#include "fuzz_data_producer.h"
|
||||
|
||||
static ZSTD_CCtx *cctx = NULL;
|
||||
static ZSTD_DCtx *dctx = NULL;
|
||||
static uint32_t seed;
|
||||
|
||||
static size_t roundTripTest(void *result, size_t resultCapacity,
|
||||
void *compressed, size_t compressedCapacity,
|
||||
const void *src, size_t srcSize)
|
||||
const void *src, size_t srcSize,
|
||||
FUZZ_dataProducer_t *producer)
|
||||
{
|
||||
size_t cSize;
|
||||
if (FUZZ_rand(&seed) & 1) {
|
||||
FUZZ_setRandomParameters(cctx, srcSize, &seed);
|
||||
if (FUZZ_dataProducer_uint32Range(producer, 0, 1)) {
|
||||
FUZZ_setRandomParameters(cctx, srcSize, producer);
|
||||
cSize = ZSTD_compress2(cctx, compressed, compressedCapacity, src, srcSize);
|
||||
} else {
|
||||
int const cLevel = FUZZ_rand(&seed) % kMaxClevel;
|
||||
int const cLevel = FUZZ_dataProducer_int32Range(producer, kMinClevel, kMaxClevel);
|
||||
|
||||
cSize = ZSTD_compressCCtx(
|
||||
cctx, compressed, compressedCapacity, src, srcSize, cLevel);
|
||||
}
|
||||
@@ -51,12 +51,17 @@ int LLVMFuzzerTestOneInput(const uint8_t *src, size_t size)
|
||||
size_t cBufSize = ZSTD_compressBound(size);
|
||||
void* cBuf;
|
||||
|
||||
seed = FUZZ_seed(&src, &size);
|
||||
/* Give a random portion of src data to the producer, to use for
|
||||
parameter generation. The rest will be used for (de)compression */
|
||||
FUZZ_dataProducer_t *producer = FUZZ_dataProducer_create(src, size);
|
||||
size = FUZZ_dataProducer_reserveDataPrefix(producer);
|
||||
|
||||
/* Half of the time fuzz with a 1 byte smaller output size.
|
||||
* This will still succeed because we don't use a dictionary, so the dictID
|
||||
* field is empty, giving us 4 bytes of overhead.
|
||||
*/
|
||||
cBufSize -= FUZZ_rand32(&seed, 0, 1);
|
||||
cBufSize -= FUZZ_dataProducer_uint32Range(producer, 0, 1);
|
||||
|
||||
cBuf = malloc(cBufSize);
|
||||
|
||||
FUZZ_ASSERT(cBuf && rBuf);
|
||||
@@ -72,13 +77,14 @@ int LLVMFuzzerTestOneInput(const uint8_t *src, size_t size)
|
||||
|
||||
{
|
||||
size_t const result =
|
||||
roundTripTest(rBuf, rBufSize, cBuf, cBufSize, src, size);
|
||||
roundTripTest(rBuf, rBufSize, cBuf, cBufSize, src, size, producer);
|
||||
FUZZ_ZASSERT(result);
|
||||
FUZZ_ASSERT_MSG(result == size, "Incorrect regenerated size");
|
||||
FUZZ_ASSERT_MSG(!memcmp(src, rBuf, size), "Corruption!");
|
||||
}
|
||||
free(rBuf);
|
||||
free(cBuf);
|
||||
FUZZ_dataProducer_free(producer);
|
||||
#ifndef STATEFUL_FUZZING
|
||||
ZSTD_freeCCtx(cctx); cctx = NULL;
|
||||
ZSTD_freeDCtx(dctx); dctx = NULL;
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
#include <stdio.h>
|
||||
#include "fuzz_helpers.h"
|
||||
#include "zstd.h"
|
||||
#include "fuzz_data_producer.h"
|
||||
|
||||
static size_t const kBufSize = ZSTD_BLOCKSIZE_MAX;
|
||||
|
||||
@@ -26,22 +27,23 @@ static ZSTD_DStream *dstream = NULL;
|
||||
static void* buf = NULL;
|
||||
uint32_t seed;
|
||||
|
||||
static ZSTD_outBuffer makeOutBuffer(void)
|
||||
static ZSTD_outBuffer makeOutBuffer(FUZZ_dataProducer_t *producer)
|
||||
{
|
||||
ZSTD_outBuffer buffer = { buf, 0, 0 };
|
||||
|
||||
buffer.size = (FUZZ_rand(&seed) % kBufSize) + 1;
|
||||
buffer.size = (FUZZ_dataProducer_uint32Range(producer, 1, kBufSize));
|
||||
FUZZ_ASSERT(buffer.size <= kBufSize);
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
||||
static ZSTD_inBuffer makeInBuffer(const uint8_t **src, size_t *size)
|
||||
static ZSTD_inBuffer makeInBuffer(const uint8_t **src, size_t *size,
|
||||
FUZZ_dataProducer_t *producer)
|
||||
{
|
||||
ZSTD_inBuffer buffer = { *src, 0, 0 };
|
||||
|
||||
FUZZ_ASSERT(*size > 0);
|
||||
buffer.size = (FUZZ_rand(&seed) % *size) + 1;
|
||||
buffer.size = (FUZZ_dataProducer_uint32Range(producer, 1, *size));
|
||||
FUZZ_ASSERT(buffer.size <= *size);
|
||||
*src += buffer.size;
|
||||
*size -= buffer.size;
|
||||
@@ -51,13 +53,16 @@ static ZSTD_inBuffer makeInBuffer(const uint8_t **src, size_t *size)
|
||||
|
||||
int LLVMFuzzerTestOneInput(const uint8_t *src, size_t size)
|
||||
{
|
||||
seed = FUZZ_seed(&src, &size);
|
||||
/* Give a random portion of src data to the producer, to use for
|
||||
parameter generation. The rest will be used for (de)compression */
|
||||
FUZZ_dataProducer_t *producer = FUZZ_dataProducer_create(src, size);
|
||||
size = FUZZ_dataProducer_reserveDataPrefix(producer);
|
||||
|
||||
/* Allocate all buffers and contexts if not already allocated */
|
||||
if (!buf) {
|
||||
buf = malloc(kBufSize);
|
||||
FUZZ_ASSERT(buf);
|
||||
}
|
||||
FUZZ_ASSERT(buf);
|
||||
}
|
||||
|
||||
if (!dstream) {
|
||||
dstream = ZSTD_createDStream();
|
||||
@@ -67,9 +72,9 @@ int LLVMFuzzerTestOneInput(const uint8_t *src, size_t size)
|
||||
}
|
||||
|
||||
while (size > 0) {
|
||||
ZSTD_inBuffer in = makeInBuffer(&src, &size);
|
||||
ZSTD_inBuffer in = makeInBuffer(&src, &size, producer);
|
||||
while (in.pos != in.size) {
|
||||
ZSTD_outBuffer out = makeOutBuffer();
|
||||
ZSTD_outBuffer out = makeOutBuffer(producer);
|
||||
size_t const rc = ZSTD_decompressStream(dstream, &out, &in);
|
||||
if (ZSTD_isError(rc)) goto error;
|
||||
}
|
||||
@@ -79,5 +84,6 @@ error:
|
||||
#ifndef STATEFUL_FUZZING
|
||||
ZSTD_freeDStream(dstream); dstream = NULL;
|
||||
#endif
|
||||
FUZZ_dataProducer_free(producer);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -20,31 +20,33 @@
|
||||
#include <string.h>
|
||||
#include "fuzz_helpers.h"
|
||||
#include "zstd_helpers.h"
|
||||
#include "fuzz_data_producer.h"
|
||||
|
||||
ZSTD_CCtx *cctx = NULL;
|
||||
static ZSTD_DCtx *dctx = NULL;
|
||||
static uint8_t* cBuf = NULL;
|
||||
static uint8_t* rBuf = NULL;
|
||||
static size_t bufSize = 0;
|
||||
static uint32_t seed;
|
||||
|
||||
static ZSTD_outBuffer makeOutBuffer(uint8_t *dst, size_t capacity)
|
||||
static ZSTD_outBuffer makeOutBuffer(uint8_t *dst, size_t capacity,
|
||||
FUZZ_dataProducer_t *producer)
|
||||
{
|
||||
ZSTD_outBuffer buffer = { dst, 0, 0 };
|
||||
|
||||
FUZZ_ASSERT(capacity > 0);
|
||||
buffer.size = (FUZZ_rand(&seed) % capacity) + 1;
|
||||
buffer.size = (FUZZ_dataProducer_uint32Range(producer, 1, capacity));
|
||||
FUZZ_ASSERT(buffer.size <= capacity);
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
||||
static ZSTD_inBuffer makeInBuffer(const uint8_t **src, size_t *size)
|
||||
static ZSTD_inBuffer makeInBuffer(const uint8_t **src, size_t *size,
|
||||
FUZZ_dataProducer_t *producer)
|
||||
{
|
||||
ZSTD_inBuffer buffer = { *src, 0, 0 };
|
||||
|
||||
FUZZ_ASSERT(*size > 0);
|
||||
buffer.size = (FUZZ_rand(&seed) % *size) + 1;
|
||||
buffer.size = (FUZZ_dataProducer_uint32Range(producer, 1, *size));
|
||||
FUZZ_ASSERT(buffer.size <= *size);
|
||||
*src += buffer.size;
|
||||
*size -= buffer.size;
|
||||
@@ -53,23 +55,24 @@ static ZSTD_inBuffer makeInBuffer(const uint8_t **src, size_t *size)
|
||||
}
|
||||
|
||||
static size_t compress(uint8_t *dst, size_t capacity,
|
||||
const uint8_t *src, size_t srcSize)
|
||||
const uint8_t *src, size_t srcSize,
|
||||
FUZZ_dataProducer_t *producer)
|
||||
{
|
||||
size_t dstSize = 0;
|
||||
ZSTD_CCtx_reset(cctx, ZSTD_reset_session_only);
|
||||
FUZZ_setRandomParameters(cctx, srcSize, &seed);
|
||||
FUZZ_setRandomParameters(cctx, srcSize, producer);
|
||||
|
||||
while (srcSize > 0) {
|
||||
ZSTD_inBuffer in = makeInBuffer(&src, &srcSize);
|
||||
ZSTD_inBuffer in = makeInBuffer(&src, &srcSize, producer);
|
||||
/* Mode controls the action. If mode == -1 we pick a new mode */
|
||||
int mode = -1;
|
||||
while (in.pos < in.size || mode != -1) {
|
||||
ZSTD_outBuffer out = makeOutBuffer(dst, capacity);
|
||||
ZSTD_outBuffer out = makeOutBuffer(dst, capacity, producer);
|
||||
/* Previous action finished, pick a new mode. */
|
||||
if (mode == -1) mode = FUZZ_rand(&seed) % 10;
|
||||
if (mode == -1) mode = FUZZ_dataProducer_uint32Range(producer, 0, 9);
|
||||
switch (mode) {
|
||||
case 0: /* fall-though */
|
||||
case 1: /* fall-though */
|
||||
case 0: /* fall-through */
|
||||
case 1: /* fall-through */
|
||||
case 2: {
|
||||
size_t const ret =
|
||||
ZSTD_compressStream2(cctx, &out, &in, ZSTD_e_flush);
|
||||
@@ -85,9 +88,9 @@ static size_t compress(uint8_t *dst, size_t capacity,
|
||||
/* Reset the compressor when the frame is finished */
|
||||
if (ret == 0) {
|
||||
ZSTD_CCtx_reset(cctx, ZSTD_reset_session_only);
|
||||
if ((FUZZ_rand(&seed) & 7) == 0) {
|
||||
if (FUZZ_dataProducer_uint32Range(producer, 0, 7) == 0) {
|
||||
size_t const remaining = in.size - in.pos;
|
||||
FUZZ_setRandomParameters(cctx, remaining, &seed);
|
||||
FUZZ_setRandomParameters(cctx, remaining, producer);
|
||||
}
|
||||
mode = -1;
|
||||
}
|
||||
@@ -107,7 +110,7 @@ static size_t compress(uint8_t *dst, size_t capacity,
|
||||
}
|
||||
for (;;) {
|
||||
ZSTD_inBuffer in = {NULL, 0, 0};
|
||||
ZSTD_outBuffer out = makeOutBuffer(dst, capacity);
|
||||
ZSTD_outBuffer out = makeOutBuffer(dst, capacity, producer);
|
||||
size_t const ret = ZSTD_compressStream2(cctx, &out, &in, ZSTD_e_end);
|
||||
FUZZ_ZASSERT(ret);
|
||||
|
||||
@@ -122,10 +125,13 @@ static size_t compress(uint8_t *dst, size_t capacity,
|
||||
|
||||
int LLVMFuzzerTestOneInput(const uint8_t *src, size_t size)
|
||||
{
|
||||
size_t neededBufSize;
|
||||
/* Give a random portion of src data to the producer, to use for
|
||||
parameter generation. The rest will be used for (de)compression */
|
||||
FUZZ_dataProducer_t *producer = FUZZ_dataProducer_create(src, size);
|
||||
size = FUZZ_dataProducer_reserveDataPrefix(producer);
|
||||
|
||||
seed = FUZZ_seed(&src, &size);
|
||||
neededBufSize = ZSTD_compressBound(size) * 2;
|
||||
size_t neededBufSize;
|
||||
neededBufSize = ZSTD_compressBound(size) * 5;
|
||||
|
||||
/* Allocate all buffers and contexts if not already allocated */
|
||||
if (neededBufSize > bufSize) {
|
||||
@@ -146,7 +152,7 @@ int LLVMFuzzerTestOneInput(const uint8_t *src, size_t size)
|
||||
}
|
||||
|
||||
{
|
||||
size_t const cSize = compress(cBuf, neededBufSize, src, size);
|
||||
size_t const cSize = compress(cBuf, neededBufSize, src, size, producer);
|
||||
size_t const rSize =
|
||||
ZSTD_decompressDCtx(dctx, rBuf, neededBufSize, cBuf, cSize);
|
||||
FUZZ_ZASSERT(rSize);
|
||||
@@ -154,6 +160,7 @@ int LLVMFuzzerTestOneInput(const uint8_t *src, size_t size)
|
||||
FUZZ_ASSERT_MSG(!memcmp(src, rBuf, size), "Corruption!");
|
||||
}
|
||||
|
||||
FUZZ_dataProducer_free(producer);
|
||||
#ifndef STATEFUL_FUZZING
|
||||
ZSTD_freeCCtx(cctx); cctx = NULL;
|
||||
ZSTD_freeDCtx(dctx); dctx = NULL;
|
||||
|
||||
@@ -21,10 +21,6 @@
|
||||
int LLVMFuzzerTestOneInput(const uint8_t *src, size_t size)
|
||||
{
|
||||
ZSTD_frameHeader zfh;
|
||||
/* Consume the seed to be compatible with the corpora of other decompression
|
||||
* fuzzers.
|
||||
*/
|
||||
FUZZ_seed(&src, &size);
|
||||
/* You can fuzz any helper functions here that are fast, and take zstd
|
||||
* compressed data as input. E.g. don't expect the input to be a dictionary,
|
||||
* so don't fuzz ZSTD_getDictID_fromDict().
|
||||
|
||||
+40
-34
@@ -17,53 +17,56 @@
|
||||
#include "zstd.h"
|
||||
#include "zdict.h"
|
||||
|
||||
const int kMinClevel = -3;
|
||||
const int kMaxClevel = 19;
|
||||
|
||||
static void set(ZSTD_CCtx *cctx, ZSTD_cParameter param, int value)
|
||||
{
|
||||
FUZZ_ZASSERT(ZSTD_CCtx_setParameter(cctx, param, value));
|
||||
}
|
||||
|
||||
static void setRand(ZSTD_CCtx *cctx, ZSTD_cParameter param, unsigned min,
|
||||
unsigned max, uint32_t *state) {
|
||||
unsigned const value = FUZZ_rand32(state, min, max);
|
||||
unsigned max, FUZZ_dataProducer_t *producer) {
|
||||
unsigned const value = FUZZ_dataProducer_uint32Range(producer, min, max);
|
||||
set(cctx, param, value);
|
||||
}
|
||||
|
||||
ZSTD_compressionParameters FUZZ_randomCParams(size_t srcSize, uint32_t *state)
|
||||
ZSTD_compressionParameters FUZZ_randomCParams(size_t srcSize, FUZZ_dataProducer_t *producer)
|
||||
{
|
||||
/* Select compression parameters */
|
||||
ZSTD_compressionParameters cParams;
|
||||
cParams.windowLog = FUZZ_rand32(state, ZSTD_WINDOWLOG_MIN, 15);
|
||||
cParams.hashLog = FUZZ_rand32(state, ZSTD_HASHLOG_MIN, 15);
|
||||
cParams.chainLog = FUZZ_rand32(state, ZSTD_CHAINLOG_MIN, 16);
|
||||
cParams.searchLog = FUZZ_rand32(state, ZSTD_SEARCHLOG_MIN, 9);
|
||||
cParams.minMatch = FUZZ_rand32(state, ZSTD_MINMATCH_MIN,
|
||||
cParams.windowLog = FUZZ_dataProducer_uint32Range(producer, ZSTD_WINDOWLOG_MIN, 15);
|
||||
cParams.hashLog = FUZZ_dataProducer_uint32Range(producer, ZSTD_HASHLOG_MIN, 15);
|
||||
cParams.chainLog = FUZZ_dataProducer_uint32Range(producer, ZSTD_CHAINLOG_MIN, 16);
|
||||
cParams.searchLog = FUZZ_dataProducer_uint32Range(producer, ZSTD_SEARCHLOG_MIN, 9);
|
||||
cParams.minMatch = FUZZ_dataProducer_uint32Range(producer, ZSTD_MINMATCH_MIN,
|
||||
ZSTD_MINMATCH_MAX);
|
||||
cParams.targetLength = FUZZ_rand32(state, 0, 512);
|
||||
cParams.strategy = FUZZ_rand32(state, ZSTD_STRATEGY_MIN, ZSTD_STRATEGY_MAX);
|
||||
cParams.targetLength = FUZZ_dataProducer_uint32Range(producer, 0, 512);
|
||||
cParams.strategy = FUZZ_dataProducer_uint32Range(producer, ZSTD_STRATEGY_MIN, ZSTD_STRATEGY_MAX);
|
||||
return ZSTD_adjustCParams(cParams, srcSize, 0);
|
||||
}
|
||||
|
||||
ZSTD_frameParameters FUZZ_randomFParams(uint32_t *state)
|
||||
ZSTD_frameParameters FUZZ_randomFParams(FUZZ_dataProducer_t *producer)
|
||||
{
|
||||
/* Select frame parameters */
|
||||
ZSTD_frameParameters fParams;
|
||||
fParams.contentSizeFlag = FUZZ_rand32(state, 0, 1);
|
||||
fParams.checksumFlag = FUZZ_rand32(state, 0, 1);
|
||||
fParams.noDictIDFlag = FUZZ_rand32(state, 0, 1);
|
||||
fParams.contentSizeFlag = FUZZ_dataProducer_uint32Range(producer, 0, 1);
|
||||
fParams.checksumFlag = FUZZ_dataProducer_uint32Range(producer, 0, 1);
|
||||
fParams.noDictIDFlag = FUZZ_dataProducer_uint32Range(producer, 0, 1);
|
||||
return fParams;
|
||||
}
|
||||
|
||||
ZSTD_parameters FUZZ_randomParams(size_t srcSize, uint32_t *state)
|
||||
ZSTD_parameters FUZZ_randomParams(size_t srcSize, FUZZ_dataProducer_t *producer)
|
||||
{
|
||||
ZSTD_parameters params;
|
||||
params.cParams = FUZZ_randomCParams(srcSize, state);
|
||||
params.fParams = FUZZ_randomFParams(state);
|
||||
params.cParams = FUZZ_randomCParams(srcSize, producer);
|
||||
params.fParams = FUZZ_randomFParams(producer);
|
||||
return params;
|
||||
}
|
||||
|
||||
void FUZZ_setRandomParameters(ZSTD_CCtx *cctx, size_t srcSize, uint32_t *state)
|
||||
void FUZZ_setRandomParameters(ZSTD_CCtx *cctx, size_t srcSize, FUZZ_dataProducer_t *producer)
|
||||
{
|
||||
ZSTD_compressionParameters cParams = FUZZ_randomCParams(srcSize, state);
|
||||
ZSTD_compressionParameters cParams = FUZZ_randomCParams(srcSize, producer);
|
||||
set(cctx, ZSTD_c_windowLog, cParams.windowLog);
|
||||
set(cctx, ZSTD_c_hashLog, cParams.hashLog);
|
||||
set(cctx, ZSTD_c_chainLog, cParams.chainLog);
|
||||
@@ -72,27 +75,30 @@ void FUZZ_setRandomParameters(ZSTD_CCtx *cctx, size_t srcSize, uint32_t *state)
|
||||
set(cctx, ZSTD_c_targetLength, cParams.targetLength);
|
||||
set(cctx, ZSTD_c_strategy, cParams.strategy);
|
||||
/* Select frame parameters */
|
||||
setRand(cctx, ZSTD_c_contentSizeFlag, 0, 1, state);
|
||||
setRand(cctx, ZSTD_c_checksumFlag, 0, 1, state);
|
||||
setRand(cctx, ZSTD_c_dictIDFlag, 0, 1, state);
|
||||
setRand(cctx, ZSTD_c_contentSizeFlag, 0, 1, producer);
|
||||
setRand(cctx, ZSTD_c_checksumFlag, 0, 1, producer);
|
||||
setRand(cctx, ZSTD_c_dictIDFlag, 0, 1, producer);
|
||||
/* Select long distance matching parameters */
|
||||
setRand(cctx, ZSTD_c_enableLongDistanceMatching, 0, 1, state);
|
||||
setRand(cctx, ZSTD_c_ldmHashLog, ZSTD_HASHLOG_MIN, 16, state);
|
||||
setRand(cctx, ZSTD_c_enableLongDistanceMatching, 0, 1, producer);
|
||||
setRand(cctx, ZSTD_c_ldmHashLog, ZSTD_HASHLOG_MIN, 16, producer);
|
||||
setRand(cctx, ZSTD_c_ldmMinMatch, ZSTD_LDM_MINMATCH_MIN,
|
||||
ZSTD_LDM_MINMATCH_MAX, state);
|
||||
ZSTD_LDM_MINMATCH_MAX, producer);
|
||||
setRand(cctx, ZSTD_c_ldmBucketSizeLog, 0, ZSTD_LDM_BUCKETSIZELOG_MAX,
|
||||
state);
|
||||
producer);
|
||||
setRand(cctx, ZSTD_c_ldmHashRateLog, ZSTD_LDM_HASHRATELOG_MIN,
|
||||
ZSTD_LDM_HASHRATELOG_MAX, state);
|
||||
ZSTD_LDM_HASHRATELOG_MAX, producer);
|
||||
/* Set misc parameters */
|
||||
setRand(cctx, ZSTD_c_nbWorkers, 0, 2, state);
|
||||
setRand(cctx, ZSTD_c_rsyncable, 0, 1, state);
|
||||
setRand(cctx, ZSTD_c_forceMaxWindow, 0, 1, state);
|
||||
setRand(cctx, ZSTD_c_literalCompressionMode, 0, 2, state);
|
||||
setRand(cctx, ZSTD_c_forceAttachDict, 0, 2, state);
|
||||
setRand(cctx, ZSTD_c_nbWorkers, 0, 2, producer);
|
||||
setRand(cctx, ZSTD_c_rsyncable, 0, 1, producer);
|
||||
setRand(cctx, ZSTD_c_forceMaxWindow, 0, 1, producer);
|
||||
setRand(cctx, ZSTD_c_literalCompressionMode, 0, 2, producer);
|
||||
setRand(cctx, ZSTD_c_forceAttachDict, 0, 2, producer);
|
||||
if (FUZZ_dataProducer_uint32Range(producer, 0, 1) == 0) {
|
||||
setRand(cctx, ZSTD_c_srcSizeHint, ZSTD_SRCSIZEHINT_MIN, 2 * srcSize, producer);
|
||||
}
|
||||
}
|
||||
|
||||
FUZZ_dict_t FUZZ_train(void const* src, size_t srcSize, uint32_t *state)
|
||||
FUZZ_dict_t FUZZ_train(void const* src, size_t srcSize, FUZZ_dataProducer_t *producer)
|
||||
{
|
||||
size_t const dictSize = MAX(srcSize / 8, 1024);
|
||||
size_t const totalSampleSize = dictSize * 11;
|
||||
@@ -107,7 +113,7 @@ FUZZ_dict_t FUZZ_train(void const* src, size_t srcSize, uint32_t *state)
|
||||
|
||||
for (sample = 0; sample < nbSamples; ++sample) {
|
||||
size_t const remaining = totalSampleSize - pos;
|
||||
size_t const offset = FUZZ_rand32(state, 0, MAX(srcSize, 1) - 1);
|
||||
size_t const offset = FUZZ_dataProducer_uint32Range(producer, 0, MAX(srcSize, 1) - 1);
|
||||
size_t const limit = MIN(srcSize - offset, remaining);
|
||||
size_t const toCopy = MIN(limit, remaining / (nbSamples - sample));
|
||||
memcpy(samples + pos, src + offset, toCopy);
|
||||
|
||||
@@ -17,17 +17,21 @@
|
||||
#define ZSTD_STATIC_LINKING_ONLY
|
||||
|
||||
#include "zstd.h"
|
||||
#include "fuzz_data_producer.h"
|
||||
#include <stdint.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
void FUZZ_setRandomParameters(ZSTD_CCtx *cctx, size_t srcSize, uint32_t *state);
|
||||
extern const int kMinClevel;
|
||||
extern const int kMaxClevel;
|
||||
|
||||
ZSTD_compressionParameters FUZZ_randomCParams(size_t srcSize, uint32_t *state);
|
||||
ZSTD_frameParameters FUZZ_randomFParams(uint32_t *state);
|
||||
ZSTD_parameters FUZZ_randomParams(size_t srcSize, uint32_t *state);
|
||||
void FUZZ_setRandomParameters(ZSTD_CCtx *cctx, size_t srcSize, FUZZ_dataProducer_t *producer);
|
||||
|
||||
ZSTD_compressionParameters FUZZ_randomCParams(size_t srcSize, FUZZ_dataProducer_t *producer);
|
||||
ZSTD_frameParameters FUZZ_randomFParams(FUZZ_dataProducer_t *producer);
|
||||
ZSTD_parameters FUZZ_randomParams(size_t srcSize, FUZZ_dataProducer_t *producer);
|
||||
|
||||
typedef struct {
|
||||
void* buff;
|
||||
@@ -38,8 +42,7 @@ typedef struct {
|
||||
* NOTE: Don't use this to train production dictionaries, it is only optimized
|
||||
* for speed, and doesn't care about dictionary quality.
|
||||
*/
|
||||
FUZZ_dict_t FUZZ_train(void const* src, size_t srcSize, uint32_t *state);
|
||||
|
||||
FUZZ_dict_t FUZZ_train(void const* src, size_t srcSize, FUZZ_dataProducer_t *producer);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
||||
+88
-3
@@ -401,7 +401,7 @@ static int basicUnitTests(U32 const seed, double compressibility)
|
||||
DISPLAYLEVEL(3, "test%3i : check decompressed result : ", testNb++);
|
||||
{ size_t u;
|
||||
for (u=0; u<CNBuffSize; u++) {
|
||||
if (((BYTE*)decodedBuffer)[u] != ((BYTE*)CNBuffer)[u]) goto _output_error;;
|
||||
if (((BYTE*)decodedBuffer)[u] != ((BYTE*)CNBuffer)[u]) goto _output_error;
|
||||
} }
|
||||
DISPLAYLEVEL(3, "OK \n");
|
||||
|
||||
@@ -758,7 +758,7 @@ static int basicUnitTests(U32 const seed, double compressibility)
|
||||
{ size_t u;
|
||||
for (u=0; u<CNBuffSize; u++) {
|
||||
if (((BYTE*)decodedBuffer)[u] != ((BYTE*)CNBuffer)[u])
|
||||
goto _output_error;;
|
||||
goto _output_error;
|
||||
} }
|
||||
DISPLAYLEVEL(3, "OK \n");
|
||||
|
||||
@@ -839,7 +839,7 @@ static int basicUnitTests(U32 const seed, double compressibility)
|
||||
DISPLAYLEVEL(3, "test%3i : check decompressed result : ", testNb++);
|
||||
{ size_t u;
|
||||
for (u=0; u<CNBuffSize; u++) {
|
||||
if (((BYTE*)decodedBuffer)[u] != ((BYTE*)CNBuffer)[u]) goto _output_error;;
|
||||
if (((BYTE*)decodedBuffer)[u] != ((BYTE*)CNBuffer)[u]) goto _output_error;
|
||||
} }
|
||||
DISPLAYLEVEL(3, "OK \n");
|
||||
|
||||
@@ -1965,6 +1965,18 @@ static int basicUnitTests(U32 const seed, double compressibility)
|
||||
assert(ZSTD_getSequences(ZSTD_createCCtx(), compressedBuffer, 1000000,
|
||||
CNBuffer, 1000000) == 1000000 / 131071 + 1);
|
||||
|
||||
/* Multiple blocks of zeros test */
|
||||
#define LONGZEROSLENGTH 1000000 /* 1MB of zeros */
|
||||
DISPLAYLEVEL(3, "test%3i : compress %u zeroes : ", testNb++, LONGZEROSLENGTH);
|
||||
memset(CNBuffer, 0, LONGZEROSLENGTH);
|
||||
CHECK_VAR(cSize, ZSTD_compress(compressedBuffer, ZSTD_compressBound(LONGZEROSLENGTH), CNBuffer, LONGZEROSLENGTH, 1) );
|
||||
DISPLAYLEVEL(3, "OK (%u bytes : %.2f%%)\n", (unsigned)cSize, (double)cSize/LONGZEROSLENGTH*100);
|
||||
|
||||
DISPLAYLEVEL(3, "test%3i : decompress %u zeroes : ", testNb++, LONGZEROSLENGTH);
|
||||
{ CHECK_NEWV(r, ZSTD_decompress(decodedBuffer, LONGZEROSLENGTH, compressedBuffer, cSize) );
|
||||
if (r != LONGZEROSLENGTH) goto _output_error; }
|
||||
DISPLAYLEVEL(3, "OK \n");
|
||||
|
||||
/* All zeroes test (test bug #137) */
|
||||
#define ZEROESLENGTH 100
|
||||
DISPLAYLEVEL(3, "test%3i : compress %u zeroes : ", testNb++, ZEROESLENGTH);
|
||||
@@ -2142,6 +2154,79 @@ static int basicUnitTests(U32 const seed, double compressibility)
|
||||
}
|
||||
DISPLAYLEVEL(3, "OK \n");
|
||||
|
||||
DISPLAYLEVEL(3, "test%3i : table cleanliness through index reduction : ", testNb++);
|
||||
{
|
||||
int cLevel;
|
||||
size_t approxIndex = 0;
|
||||
size_t maxIndex = ((3U << 29) + (1U << ZSTD_WINDOWLOG_MAX)); /* ZSTD_CURRENT_MAX from zstd_compress_internal.h */
|
||||
|
||||
/* vastly overprovision space in a static context so that we can do all
|
||||
* this without ever reallocating, which would reset the indices */
|
||||
size_t const staticCCtxSize = 2 * ZSTD_estimateCCtxSize(22);
|
||||
void* const staticCCtxBuffer = malloc(staticCCtxSize);
|
||||
ZSTD_CCtx* cctx = ZSTD_initStaticCCtx(staticCCtxBuffer, staticCCtxSize);
|
||||
|
||||
/* bump the indices so the following compressions happen at high
|
||||
* indices. */
|
||||
{
|
||||
ZSTD_outBuffer out = { compressedBuffer, compressedBufferSize, 0 };
|
||||
ZSTD_inBuffer in = { CNBuffer, CNBuffSize, 0 };
|
||||
ZSTD_CCtx_reset(cctx, ZSTD_reset_session_and_parameters);
|
||||
CHECK_Z(ZSTD_CCtx_setParameter(cctx, ZSTD_c_compressionLevel, -500));
|
||||
while (approxIndex <= (maxIndex / 4) * 3) {
|
||||
CHECK_Z(ZSTD_compressStream2(cctx, &out, &in, ZSTD_e_flush));
|
||||
approxIndex += in.pos;
|
||||
CHECK(in.pos == in.size);
|
||||
in.pos = 0;
|
||||
out.pos = 0;
|
||||
}
|
||||
CHECK_Z(ZSTD_compressStream2(cctx, &out, &in, ZSTD_e_end));
|
||||
}
|
||||
|
||||
/* spew a bunch of stuff into the table area */
|
||||
for (cLevel = 1; cLevel <= 22; cLevel++) {
|
||||
ZSTD_outBuffer out = { compressedBuffer, compressedBufferSize / cLevel, 0 };
|
||||
ZSTD_inBuffer in = { CNBuffer, CNBuffSize, 0 };
|
||||
ZSTD_CCtx_reset(cctx, ZSTD_reset_session_and_parameters);
|
||||
CHECK_Z(ZSTD_CCtx_setParameter(cctx, ZSTD_c_compressionLevel, cLevel));
|
||||
CHECK_Z(ZSTD_compressStream2(cctx, &out, &in, ZSTD_e_flush));
|
||||
CHECK_Z(ZSTD_compressStream2(cctx, &out, &in, ZSTD_e_end));
|
||||
approxIndex += in.pos;
|
||||
}
|
||||
|
||||
/* now crank the indices so we overflow */
|
||||
{
|
||||
ZSTD_outBuffer out = { compressedBuffer, compressedBufferSize, 0 };
|
||||
ZSTD_inBuffer in = { CNBuffer, CNBuffSize, 0 };
|
||||
ZSTD_CCtx_reset(cctx, ZSTD_reset_session_and_parameters);
|
||||
CHECK_Z(ZSTD_CCtx_setParameter(cctx, ZSTD_c_compressionLevel, -500));
|
||||
while (approxIndex <= maxIndex) {
|
||||
CHECK_Z(ZSTD_compressStream2(cctx, &out, &in, ZSTD_e_flush));
|
||||
approxIndex += in.pos;
|
||||
CHECK(in.pos == in.size);
|
||||
in.pos = 0;
|
||||
out.pos = 0;
|
||||
}
|
||||
CHECK_Z(ZSTD_compressStream2(cctx, &out, &in, ZSTD_e_end));
|
||||
}
|
||||
|
||||
/* do a bunch of compressions again in low indices and ensure we don't
|
||||
* hit untracked invalid indices */
|
||||
for (cLevel = 1; cLevel <= 22; cLevel++) {
|
||||
ZSTD_outBuffer out = { compressedBuffer, compressedBufferSize / cLevel, 0 };
|
||||
ZSTD_inBuffer in = { CNBuffer, CNBuffSize, 0 };
|
||||
ZSTD_CCtx_reset(cctx, ZSTD_reset_session_and_parameters);
|
||||
CHECK_Z(ZSTD_CCtx_setParameter(cctx, ZSTD_c_compressionLevel, cLevel));
|
||||
CHECK_Z(ZSTD_compressStream2(cctx, &out, &in, ZSTD_e_flush));
|
||||
CHECK_Z(ZSTD_compressStream2(cctx, &out, &in, ZSTD_e_end));
|
||||
approxIndex += in.pos;
|
||||
}
|
||||
|
||||
ZSTD_freeCCtx(cctx);
|
||||
free(staticCCtxBuffer);
|
||||
}
|
||||
DISPLAYLEVEL(3, "OK \n");
|
||||
|
||||
_end:
|
||||
free(CNBuffer);
|
||||
free(compressedBuffer);
|
||||
|
||||
Binary file not shown.
+63
-3
@@ -108,7 +108,6 @@ else
|
||||
fi
|
||||
|
||||
|
||||
|
||||
println "\n===> simple tests "
|
||||
|
||||
./datagen > tmp
|
||||
@@ -242,6 +241,11 @@ $ZSTD -f tmp && die "attempt to compress a non existing file"
|
||||
test -f tmp.zst # destination file should still be present
|
||||
rm tmp*
|
||||
|
||||
println "\n===> decompression only tests "
|
||||
head -c 1048576 /dev/zero > tmp
|
||||
$ZSTD -d -o tmp1 "$TESTDIR/golden-decompression/rle-first-block.zst"
|
||||
$DIFF -s tmp1 tmp
|
||||
rm tmp*
|
||||
|
||||
println "test : compress multiple files"
|
||||
println hello > tmp1
|
||||
@@ -409,6 +413,53 @@ println "compress multiple files including a missing one (notHere) : "
|
||||
$ZSTD -f tmp1 notHere tmp2 && die "missing file not detected!"
|
||||
|
||||
|
||||
println "\n===> stream-size mode"
|
||||
|
||||
./datagen -g11000 > tmp
|
||||
println "test : basic file compression vs sized streaming compression"
|
||||
file_size=$($ZSTD -14 -f tmp -o tmp.zst && wc -c < tmp.zst)
|
||||
stream_size=$(cat tmp | $ZSTD -14 --stream-size=11000 | wc -c)
|
||||
if [ "$stream_size" -gt "$file_size" ]; then
|
||||
die "hinted compression larger than expected"
|
||||
fi
|
||||
println "test : sized streaming compression and decompression"
|
||||
cat tmp | $ZSTD -14 -f tmp -o --stream-size=11000 tmp.zst
|
||||
$ZSTD -df tmp.zst -o tmp_decompress
|
||||
cmp tmp tmp_decompress || die "difference between original and decompressed file"
|
||||
println "test : incorrect stream size"
|
||||
cat tmp | $ZSTD -14 -f -o tmp.zst --stream-size=11001 && die "should fail with incorrect stream size"
|
||||
|
||||
|
||||
println "\n===> size-hint mode"
|
||||
|
||||
./datagen -g11000 > tmp
|
||||
./datagen -g11000 > tmp2
|
||||
./datagen > tmpDict
|
||||
println "test : basic file compression vs hinted streaming compression"
|
||||
file_size=$($ZSTD -14 -f tmp -o tmp.zst && wc -c < tmp.zst)
|
||||
stream_size=$(cat tmp | $ZSTD -14 --size-hint=11000 | wc -c)
|
||||
if [ "$stream_size" -ge "$file_size" ]; then
|
||||
die "hinted compression larger than expected"
|
||||
fi
|
||||
println "test : hinted streaming compression and decompression"
|
||||
cat tmp | $ZSTD -14 -f -o tmp.zst --size-hint=11000
|
||||
$ZSTD -df tmp.zst -o tmp_decompress
|
||||
cmp tmp tmp_decompress || die "difference between original and decompressed file"
|
||||
println "test : hinted streaming compression with dictionary"
|
||||
cat tmp | $ZSTD -14 -f -D tmpDict --size-hint=11000 | $ZSTD -t -D tmpDict
|
||||
println "test : multiple file compression with hints and dictionary"
|
||||
$ZSTD -14 -f -D tmpDict --size-hint=11000 tmp tmp2
|
||||
$ZSTD -14 -f -o tmp1_.zst -D tmpDict --size-hint=11000 tmp
|
||||
$ZSTD -14 -f -o tmp2_.zst -D tmpDict --size-hint=11000 tmp2
|
||||
cmp tmp.zst tmp1_.zst || die "first file's output differs"
|
||||
cmp tmp2.zst tmp2_.zst || die "second file's output differs"
|
||||
println "test : incorrect hinted stream sizes"
|
||||
cat tmp | $ZSTD -14 -f --size-hint=11050 | $ZSTD -t # slightly too high
|
||||
cat tmp | $ZSTD -14 -f --size-hint=10950 | $ZSTD -t # slightly too low
|
||||
cat tmp | $ZSTD -14 -f --size-hint=22000 | $ZSTD -t # considerably too high
|
||||
cat tmp | $ZSTD -14 -f --size-hint=5500 | $ZSTD -t # considerably too low
|
||||
|
||||
|
||||
println "\n===> dictionary tests "
|
||||
|
||||
println "- test with raw dict (content only) "
|
||||
@@ -480,6 +531,15 @@ $ZSTD -o tmpDict --train "$TESTDIR"/*.c "$PRGDIR"/*.c
|
||||
test -f tmpDict
|
||||
$ZSTD --train "$TESTDIR"/*.c "$PRGDIR"/*.c
|
||||
test -f dictionary
|
||||
println "- Test dictionary training fails"
|
||||
echo "000000000000000000000000000000000" > tmpz
|
||||
$ZSTD --train tmpz tmpz tmpz tmpz tmpz tmpz tmpz tmpz tmpz && die "Dictionary training should fail : source is all zeros"
|
||||
if [ -n "$hasMT" ]
|
||||
then
|
||||
$ZSTD --train -T0 tmpz tmpz tmpz tmpz tmpz tmpz tmpz tmpz tmpz && die "Dictionary training should fail : source is all zeros"
|
||||
println "- Create dictionary with multithreading enabled"
|
||||
$ZSTD --train -T0 "$TESTDIR"/*.c "$PRGDIR"/*.c -o tmpDict
|
||||
fi
|
||||
rm tmp* dictionary
|
||||
|
||||
|
||||
@@ -583,8 +643,8 @@ $ZSTD -t tmpSplit.* && die "bad file not detected !"
|
||||
|
||||
println "\n===> golden files tests "
|
||||
|
||||
$ZSTD -t -r "$TESTDIR/files"
|
||||
$ZSTD -c -r "$TESTDIR/files" | $ZSTD -t
|
||||
$ZSTD -t -r "$TESTDIR/golden-compression"
|
||||
$ZSTD -c -r "$TESTDIR/golden-compression" | $ZSTD -t
|
||||
|
||||
|
||||
println "\n===> benchmark mode tests "
|
||||
|
||||
@@ -33,7 +33,7 @@ silesia, level 19, compress
|
||||
silesia, long distance mode, compress cctx, 4849491
|
||||
silesia, multithreaded, compress cctx, 4849491
|
||||
silesia, multithreaded long distance mode, compress cctx, 4849491
|
||||
silesia, small window log, compress cctx, 7112784
|
||||
silesia, small window log, compress cctx, 7112472
|
||||
silesia, small hash log, compress cctx, 6554898
|
||||
silesia, small chain log, compress cctx, 4931093
|
||||
silesia, explicit params, compress cctx, 4794609
|
||||
@@ -97,7 +97,7 @@ silesia, level 19, zstdcli,
|
||||
silesia, long distance mode, zstdcli, 4839698
|
||||
silesia, multithreaded, zstdcli, 4849539
|
||||
silesia, multithreaded long distance mode, zstdcli, 4839698
|
||||
silesia, small window log, zstdcli, 7123892
|
||||
silesia, small window log, zstdcli, 7123580
|
||||
silesia, small hash log, zstdcli, 6554946
|
||||
silesia, small chain log, zstdcli, 4931141
|
||||
silesia, explicit params, zstdcli, 4797048
|
||||
@@ -123,7 +123,7 @@ silesia.tar, no source size, zstdcli,
|
||||
silesia.tar, long distance mode, zstdcli, 4853140
|
||||
silesia.tar, multithreaded, zstdcli, 4861462
|
||||
silesia.tar, multithreaded long distance mode, zstdcli, 4853140
|
||||
silesia.tar, small window log, zstdcli, 7127964
|
||||
silesia.tar, small window log, zstdcli, 7127589
|
||||
silesia.tar, small hash log, zstdcli, 6587841
|
||||
silesia.tar, small chain log, zstdcli, 4943269
|
||||
silesia.tar, explicit params, zstdcli, 4822318
|
||||
@@ -188,7 +188,7 @@ silesia, no source size, advanced
|
||||
silesia, long distance mode, advanced one pass, 4839650
|
||||
silesia, multithreaded, advanced one pass, 4849491
|
||||
silesia, multithreaded long distance mode, advanced one pass, 4839650
|
||||
silesia, small window log, advanced one pass, 7123844
|
||||
silesia, small window log, advanced one pass, 7123532
|
||||
silesia, small hash log, advanced one pass, 6554898
|
||||
silesia, small chain log, advanced one pass, 4931093
|
||||
silesia, explicit params, advanced one pass, 4797035
|
||||
@@ -214,7 +214,7 @@ silesia.tar, no source size, advanced
|
||||
silesia.tar, long distance mode, advanced one pass, 4848046
|
||||
silesia.tar, multithreaded, advanced one pass, 4860726
|
||||
silesia.tar, multithreaded long distance mode, advanced one pass, 4847343
|
||||
silesia.tar, small window log, advanced one pass, 7127924
|
||||
silesia.tar, small window log, advanced one pass, 7127549
|
||||
silesia.tar, small hash log, advanced one pass, 6587833
|
||||
silesia.tar, small chain log, advanced one pass, 4943266
|
||||
silesia.tar, explicit params, advanced one pass, 4808543
|
||||
@@ -280,7 +280,7 @@ silesia, no source size, advanced
|
||||
silesia, long distance mode, advanced one pass small out, 4839650
|
||||
silesia, multithreaded, advanced one pass small out, 4849491
|
||||
silesia, multithreaded long distance mode, advanced one pass small out, 4839650
|
||||
silesia, small window log, advanced one pass small out, 7123844
|
||||
silesia, small window log, advanced one pass small out, 7123532
|
||||
silesia, small hash log, advanced one pass small out, 6554898
|
||||
silesia, small chain log, advanced one pass small out, 4931093
|
||||
silesia, explicit params, advanced one pass small out, 4797035
|
||||
@@ -306,7 +306,7 @@ silesia.tar, no source size, advanced
|
||||
silesia.tar, long distance mode, advanced one pass small out, 4848046
|
||||
silesia.tar, multithreaded, advanced one pass small out, 4860726
|
||||
silesia.tar, multithreaded long distance mode, advanced one pass small out, 4847343
|
||||
silesia.tar, small window log, advanced one pass small out, 7127924
|
||||
silesia.tar, small window log, advanced one pass small out, 7127549
|
||||
silesia.tar, small hash log, advanced one pass small out, 6587833
|
||||
silesia.tar, small chain log, advanced one pass small out, 4943266
|
||||
silesia.tar, explicit params, advanced one pass small out, 4808543
|
||||
@@ -372,7 +372,7 @@ silesia, no source size, advanced
|
||||
silesia, long distance mode, advanced streaming, 4839650
|
||||
silesia, multithreaded, advanced streaming, 4849491
|
||||
silesia, multithreaded long distance mode, advanced streaming, 4839650
|
||||
silesia, small window log, advanced streaming, 7123846
|
||||
silesia, small window log, advanced streaming, 7123534
|
||||
silesia, small hash log, advanced streaming, 6554898
|
||||
silesia, small chain log, advanced streaming, 4931093
|
||||
silesia, explicit params, advanced streaming, 4797048
|
||||
@@ -398,7 +398,7 @@ silesia.tar, no source size, advanced
|
||||
silesia.tar, long distance mode, advanced streaming, 4848046
|
||||
silesia.tar, multithreaded, advanced streaming, 4861458
|
||||
silesia.tar, multithreaded long distance mode, advanced streaming, 4853136
|
||||
silesia.tar, small window log, advanced streaming, 7127924
|
||||
silesia.tar, small window log, advanced streaming, 7127549
|
||||
silesia.tar, small hash log, advanced streaming, 6587834
|
||||
silesia.tar, small chain log, advanced streaming, 4943271
|
||||
silesia.tar, explicit params, advanced streaming, 4808570
|
||||
|
||||
|
+2
-2
@@ -184,7 +184,7 @@ static int basicUnitTests(U32 seed, double compressibility, ZSTD_customMem custo
|
||||
DISPLAYLEVEL(4, "test%3i : check decompressed result : ", testNb++);
|
||||
{ size_t i;
|
||||
for (i=0; i<CNBufferSize; i++) {
|
||||
if (((BYTE*)decodedBuffer)[i] != ((BYTE*)CNBuffer)[i]) goto _output_error;;
|
||||
if (((BYTE*)decodedBuffer)[i] != ((BYTE*)CNBuffer)[i]) goto _output_error;
|
||||
} }
|
||||
DISPLAYLEVEL(4, "OK \n");
|
||||
|
||||
@@ -213,7 +213,7 @@ static int basicUnitTests(U32 seed, double compressibility, ZSTD_customMem custo
|
||||
DISPLAYLEVEL(4, "test%3i : check decompressed result : ", testNb++);
|
||||
{ size_t i;
|
||||
for (i=0; i<CNBufferSize; i++) {
|
||||
if (((BYTE*)decodedBuffer)[i] != ((BYTE*)CNBuffer)[i]) goto _output_error;;
|
||||
if (((BYTE*)decodedBuffer)[i] != ((BYTE*)CNBuffer)[i]) goto _output_error;
|
||||
} }
|
||||
DISPLAYLEVEL(4, "OK \n");
|
||||
|
||||
|
||||
+2
-1
@@ -481,7 +481,7 @@ static int basicUnitTests(U32 seed, double compressibility)
|
||||
DISPLAYLEVEL(3, "test%3i : check decompressed result : ", testNb++);
|
||||
{ size_t i;
|
||||
for (i=0; i<CNBufferSize; i++) {
|
||||
if (((BYTE*)decodedBuffer)[i] != ((BYTE*)CNBuffer)[i]) goto _output_error;;
|
||||
if (((BYTE*)decodedBuffer)[i] != ((BYTE*)CNBuffer)[i]) goto _output_error;
|
||||
} }
|
||||
DISPLAYLEVEL(3, "OK \n");
|
||||
|
||||
@@ -2106,6 +2106,7 @@ static int fuzzerTests_newAPI(U32 seed, int nbTests, int startTest,
|
||||
if (FUZ_rand(&lseed) & 3) CHECK_Z( setCCtxParameter(zc, cctxParams, ZSTD_c_ldmMinMatch, FUZ_randomClampedLength(&lseed, ZSTD_LDM_MINMATCH_MIN, ZSTD_LDM_MINMATCH_MAX), opaqueAPI) );
|
||||
if (FUZ_rand(&lseed) & 3) CHECK_Z( setCCtxParameter(zc, cctxParams, ZSTD_c_ldmBucketSizeLog, FUZ_randomClampedLength(&lseed, ZSTD_LDM_BUCKETSIZELOG_MIN, ZSTD_LDM_BUCKETSIZELOG_MAX), opaqueAPI) );
|
||||
if (FUZ_rand(&lseed) & 3) CHECK_Z( setCCtxParameter(zc, cctxParams, ZSTD_c_ldmHashRateLog, FUZ_randomClampedLength(&lseed, ZSTD_LDM_HASHRATELOG_MIN, ZSTD_LDM_HASHRATELOG_MAX), opaqueAPI) );
|
||||
if (FUZ_rand(&lseed) & 3) CHECK_Z( setCCtxParameter(zc, cctxParams, ZSTD_c_srcSizeHint, FUZ_randomClampedLength(&lseed, ZSTD_SRCSIZEHINT_MIN, ZSTD_SRCSIZEHINT_MAX), opaqueAPI) );
|
||||
}
|
||||
|
||||
/* mess with frame parameters */
|
||||
|
||||
Reference in New Issue
Block a user