2017-08-18 16:52:05 -07:00
/*
2016-08-30 10:04:33 -07:00
* Copyright ( c ) 2016 - present , Yann Collet , Facebook , Inc .
* All rights reserved .
*
2017-08-18 16:52:05 -07:00
* 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 ) .
2017-09-08 00:09:23 -07:00
* You may select , at your option , one of the above - listed licenses .
2016-08-30 10:04:33 -07:00
*/
2016-08-12 07:48:02 -07:00
/*-************************************
* Compiler specific
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
# ifdef _MSC_VER /* Visual Studio */
2017-05-12 16:29:19 -07:00
# define _CRT_SECURE_NO_WARNINGS /* fgets */
# pragma warning(disable : 4127) /* disable: C4127: conditional expression is constant */
# pragma warning(disable : 4146) /* disable: C4146: minus unsigned expression */
2016-08-12 07:48:02 -07:00
# endif
/*-************************************
* Includes
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
# include <stdlib.h> /* free */
# include <stdio.h> /* fgets, sscanf */
# include <string.h> /* strcmp */
2017-06-16 17:56:41 -07:00
# include <assert.h> /* assert */
2016-08-12 07:48:02 -07:00
# include "mem.h"
2017-05-12 16:29:19 -07:00
# define ZSTD_STATIC_LINKING_ONLY /* ZSTD_maxCLevel, ZSTD_customMem, ZSTD_getDictID_fromFrame */
2016-08-12 07:48:02 -07:00
# include "zstd.h" /* ZSTD_compressBound */
2016-12-13 07:39:36 -08:00
# include "zstd_errors.h" /* ZSTD_error_srcSize_wrong */
2017-01-19 12:12:50 -08:00
# include "zstdmt_compress.h"
2017-01-16 19:46:22 -08:00
# include "zdict.h" /* ZDICT_trainFromBuffer */
2016-08-12 07:48:02 -07:00
# include "datagen.h" /* RDG_genBuffer */
2016-09-01 16:44:48 -07:00
# define XXH_STATIC_LINKING_ONLY /* XXH64_state_t */
2016-08-12 07:48:02 -07:00
# include "xxhash.h" /* XXH64_* */
2017-10-16 17:18:43 -07:00
# include "seqgen.h"
2017-11-29 19:11:12 -08:00
# include "util.h"
2016-08-12 07:48:02 -07:00
/*-************************************
* Constants
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
# define KB *(1U<<10)
# define MB *(1U<<20)
# define GB *(1U<<30)
static const U32 nbTestsDefault = 10000 ;
2017-06-21 23:35:58 -07:00
static const U32 g_cLevelMax_smallTests = 10 ;
2016-08-12 07:48:02 -07:00
# define COMPRESSIBLE_NOISE_LENGTH (10 MB)
# define FUZ_COMPRESSIBILITY_DEFAULT 50
2017-01-16 19:46:22 -08:00
static const U32 prime32 = 2654435761U ;
2016-08-12 07:48:02 -07:00
/*-************************************
* Display Macros
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
# define DISPLAY(...) fprintf(stderr, __VA_ARGS__)
2017-05-08 16:08:01 -07:00
# define DISPLAYLEVEL(l, ...) if (g_displayLevel>=l) { \
DISPLAY ( __VA_ARGS__ ) ; \
if ( g_displayLevel > = 4 ) fflush ( stderr ) ; }
2016-08-12 07:48:02 -07:00
static U32 g_displayLevel = 2 ;
2017-11-29 19:11:12 -08:00
static const U64 g_refreshRate = SEC_TO_MICRO / 6 ;
static UTIL_time_t g_displayClock = UTIL_TIME_INITIALIZER ;
2016-08-12 07:48:02 -07:00
# define DISPLAYUPDATE(l, ...) if (g_displayLevel>=l) { \
2017-11-29 19:11:12 -08:00
if ( ( UTIL_clockSpanMicro ( g_displayClock ) > g_refreshRate ) | | ( g_displayLevel > = 4 ) ) \
{ g_displayClock = UTIL_getTime ( ) ; DISPLAY ( __VA_ARGS__ ) ; \
if ( g_displayLevel > = 4 ) fflush ( stderr ) ; } }
2016-08-12 07:48:02 -07:00
2017-11-29 19:11:12 -08:00
static U64 g_clockTime = 0 ;
2016-08-12 07:48:02 -07:00
/*-*******************************************************
* Fuzzer functions
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2017-11-29 19:11:12 -08:00
# undef MIN
# undef MAX
# define MIN(a,b) ((a)<(b)?(a):(b))
2016-08-12 07:48:02 -07:00
# define MAX(a,b) ((a)>(b)?(a):(b))
/*! FUZ_rand() :
@ return : a 27 bits random value , from a 32 - bits ` seed ` .
` seed ` is also modified */
2016-10-25 16:19:52 -07:00
# define FUZ_rotl32(x,r) ((x << r) | (x >> (32 - r)))
2016-08-12 07:48:02 -07:00
unsigned int FUZ_rand ( unsigned int * seedPtr )
{
2017-01-16 19:46:22 -08:00
static const U32 prime2 = 2246822519U ;
2016-08-12 07:48:02 -07:00
U32 rand32 = * seedPtr ;
2017-01-16 19:46:22 -08:00
rand32 * = prime32 ;
2016-08-12 07:48:02 -07:00
rand32 + = prime2 ;
rand32 = FUZ_rotl32 ( rand32 , 13 ) ;
* seedPtr = rand32 ;
return rand32 > > 5 ;
}
2017-10-16 17:18:43 -07:00
# define CHECK(cond, ...) { \
if ( cond ) { \
DISPLAY ( " Error => " ) ; \
DISPLAY ( __VA_ARGS__ ) ; \
DISPLAY ( " (seed %u, test nb %u, line %u) \n " , \
seed , testNb , __LINE__ ) ; \
2017-09-28 02:14:48 -07:00
goto _output_error ; \
} }
2017-10-16 17:18:43 -07:00
# define CHECK_Z(f) { \
size_t const err = f ; \
CHECK ( ZSTD_isError ( err ) , " %s : %s " , \
# f, ZSTD_getErrorName(err)); \
}
2016-08-22 15:30:31 -07:00
/*======================================================
* Basic Unit tests
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */
2017-01-16 19:46:22 -08:00
typedef struct {
void * start ;
size_t size ;
size_t filled ;
} buffer_t ;
static const buffer_t g_nullBuffer = { NULL , 0 , 0 } ;
static buffer_t FUZ_createDictionary ( const void * src , size_t srcSize , size_t blockSize , size_t requestedDictSize )
{
buffer_t dict = { NULL , 0 , 0 } ;
size_t const nbBlocks = ( srcSize + ( blockSize - 1 ) ) / blockSize ;
size_t * const blockSizes = ( size_t * ) malloc ( nbBlocks * sizeof ( size_t ) ) ;
if ( ! blockSizes ) return dict ;
dict . start = malloc ( requestedDictSize ) ;
if ( ! dict . start ) { free ( blockSizes ) ; return dict ; }
{ size_t nb ;
for ( nb = 0 ; nb < nbBlocks - 1 ; nb + + ) blockSizes [ nb ] = blockSize ;
blockSizes [ nbBlocks - 1 ] = srcSize - ( blockSize * ( nbBlocks - 1 ) ) ;
}
{ size_t const dictSize = ZDICT_trainFromBuffer ( dict . start , requestedDictSize , src , blockSizes , ( unsigned ) nbBlocks ) ;
free ( blockSizes ) ;
2017-04-18 22:52:41 -07:00
if ( ZDICT_isError ( dictSize ) ) { free ( dict . start ) ; return g_nullBuffer ; }
2017-01-16 19:46:22 -08:00
dict . size = requestedDictSize ;
dict . filled = dictSize ;
return dict ; /* how to return dictSize ? */
}
}
static void FUZ_freeDictionary ( buffer_t dict )
{
free ( dict . start ) ;
}
2017-10-16 17:18:43 -07:00
/* Round trips data and updates xxh with the decompressed data produced */
static size_t SEQ_roundTrip ( ZSTD_CCtx * cctx , ZSTD_DCtx * dctx ,
XXH64_state_t * xxh , void * data , size_t size ,
ZSTD_EndDirective endOp )
{
static BYTE compressed [ 1024 ] ;
static BYTE uncompressed [ 1024 ] ;
ZSTD_inBuffer cin = { data , size , 0 } ;
size_t cret ;
do {
ZSTD_outBuffer cout = { compressed , sizeof ( compressed ) , 0 } ;
ZSTD_inBuffer din = { compressed , 0 , 0 } ;
ZSTD_outBuffer dout = { uncompressed , 0 , 0 } ;
cret = ZSTD_compress_generic ( cctx , & cout , & cin , endOp ) ;
if ( ZSTD_isError ( cret ) )
return cret ;
din . size = cout . pos ;
while ( din . pos < din . size | | ( endOp = = ZSTD_e_end & & cret = = 0 ) ) {
size_t dret ;
dout . pos = 0 ;
dout . size = sizeof ( uncompressed ) ;
dret = ZSTD_decompressStream ( dctx , & dout , & din ) ;
if ( ZSTD_isError ( dret ) )
return dret ;
XXH64_update ( xxh , dout . dst , dout . pos ) ;
if ( dret = = 0 )
break ;
}
} while ( cin . pos < cin . size | | ( endOp ! = ZSTD_e_continue & & cret ! = 0 ) ) ;
return 0 ;
}
/* Generates some data and round trips it */
static size_t SEQ_generateRoundTrip ( ZSTD_CCtx * cctx , ZSTD_DCtx * dctx ,
XXH64_state_t * xxh , SEQ_stream * seq ,
SEQ_gen_type type , unsigned value )
{
static BYTE data [ 1024 ] ;
size_t gen ;
do {
SEQ_outBuffer sout = { data , sizeof ( data ) , 0 } ;
size_t ret ;
gen = SEQ_gen ( seq , type , value , & sout ) ;
ret = SEQ_roundTrip ( cctx , dctx , xxh , sout . dst , sout . pos , ZSTD_e_continue ) ;
if ( ZSTD_isError ( ret ) )
return ret ;
} while ( gen ! = 0 ) ;
return 0 ;
}
2017-01-16 19:46:22 -08:00
2017-11-27 12:15:23 -08:00
static int basicUnitTests ( U32 seed , double compressibility )
2016-08-12 07:48:02 -07:00
{
2016-09-09 07:44:16 -07:00
size_t const CNBufferSize = COMPRESSIBLE_NOISE_LENGTH ;
2016-08-12 07:48:02 -07:00
void * CNBuffer = malloc ( CNBufferSize ) ;
2017-11-01 13:10:03 -07:00
size_t const skippableFrameSize = 200 KB ;
2016-08-12 07:48:02 -07:00
size_t const compressedBufferSize = ( 8 + skippableFrameSize ) + ZSTD_compressBound ( COMPRESSIBLE_NOISE_LENGTH ) ;
void * compressedBuffer = malloc ( compressedBufferSize ) ;
size_t const decodedBufferSize = CNBufferSize ;
void * decodedBuffer = malloc ( decodedBufferSize ) ;
size_t cSize ;
2016-09-09 07:44:16 -07:00
int testResult = 0 ;
2017-05-08 16:08:01 -07:00
U32 testNb = 1 ;
2017-11-27 12:15:23 -08:00
ZSTD_CStream * zc = ZSTD_createCStream ( ) ;
ZSTD_DStream * zd = ZSTD_createDStream ( ) ;
2017-08-30 14:36:54 -07:00
ZSTDMT_CCtx * mtctx = ZSTDMT_createCCtx ( 2 ) ;
2016-12-02 18:37:38 -08:00
ZSTD_inBuffer inBuff , inBuff2 ;
2016-08-16 16:39:22 -07:00
ZSTD_outBuffer outBuff ;
2017-01-16 19:46:22 -08:00
buffer_t dictionary = g_nullBuffer ;
2017-05-10 11:30:19 -07:00
size_t const dictSize = 128 KB ;
2017-01-16 19:46:22 -08:00
unsigned dictID = 0 ;
2016-08-12 07:48:02 -07:00
/* Create compressible test buffer */
if ( ! CNBuffer | | ! compressedBuffer | | ! decodedBuffer | | ! zc | | ! zd ) {
2017-01-16 19:46:22 -08:00
DISPLAY ( " Not enough memory, aborting \n " ) ;
2016-08-12 07:48:02 -07:00
goto _output_error ;
}
RDG_genBuffer ( CNBuffer , CNBufferSize , compressibility , 0. , seed ) ;
2017-01-16 19:46:22 -08:00
/* Create dictionary */
2017-09-28 18:34:38 -07:00
DISPLAYLEVEL ( 3 , " creating dictionary for unit tests \n " ) ;
dictionary = FUZ_createDictionary ( CNBuffer , CNBufferSize / 2 , 8 KB , 40 KB ) ;
2017-01-16 19:46:22 -08:00
if ( ! dictionary . start ) {
DISPLAY ( " Error creating dictionary, aborting \n " ) ;
goto _output_error ;
}
dictID = ZDICT_getDictID ( dictionary . start , dictionary . filled ) ;
2016-08-12 07:48:02 -07:00
/* generate skippable frame */
MEM_writeLE32 ( compressedBuffer , ZSTD_MAGIC_SKIPPABLE_START ) ;
MEM_writeLE32 ( ( ( char * ) compressedBuffer ) + 4 , ( U32 ) skippableFrameSize ) ;
cSize = skippableFrameSize + 8 ;
/* Basic compression test */
2017-01-19 12:12:50 -08:00
DISPLAYLEVEL ( 3 , " test%3i : compress %u bytes : " , testNb + + , COMPRESSIBLE_NOISE_LENGTH ) ;
2017-10-13 18:32:06 -07:00
CHECK_Z ( ZSTD_initCStream_usingDict ( zc , CNBuffer , dictSize , 1 /* cLevel */ ) ) ;
2016-08-16 16:39:22 -07:00
outBuff . dst = ( char * ) ( compressedBuffer ) + cSize ;
2017-10-13 18:32:06 -07:00
assert ( compressedBufferSize > cSize ) ;
outBuff . size = compressedBufferSize - cSize ;
2016-08-16 16:39:22 -07:00
outBuff . pos = 0 ;
inBuff . src = CNBuffer ;
inBuff . size = CNBufferSize ;
inBuff . pos = 0 ;
2017-09-28 02:14:48 -07:00
CHECK_Z ( ZSTD_compressStream ( zc , & outBuff , & inBuff ) ) ;
2016-08-16 16:39:22 -07:00
if ( inBuff . pos ! = inBuff . size ) goto _output_error ; /* entire input should be consumed */
{ size_t const r = ZSTD_endStream ( zc , & outBuff ) ;
2016-08-26 00:05:06 -07:00
if ( r ! = 0 ) goto _output_error ; } /* error, or some data not flushed */
2016-08-16 16:39:22 -07:00
cSize + = outBuff . pos ;
2017-01-19 12:12:50 -08:00
DISPLAYLEVEL ( 3 , " OK (%u bytes : %.2f%%) \n " , ( U32 ) cSize , ( double ) cSize / COMPRESSIBLE_NOISE_LENGTH * 100 ) ;
2016-08-12 07:48:02 -07:00
2017-05-10 11:30:19 -07:00
/* context size functions */
DISPLAYLEVEL ( 3 , " test%3i : estimate CStream size : " , testNb + + ) ;
{ ZSTD_compressionParameters const cParams = ZSTD_getCParams ( 1 , CNBufferSize , dictSize ) ;
2017-09-24 16:47:02 -07:00
size_t const cstreamSize = ZSTD_estimateCStreamSize_usingCParams ( cParams ) ;
size_t const cdictSize = ZSTD_estimateCDictSize_advanced ( dictSize , cParams , ZSTD_dlm_byCopy ) ; /* uses ZSTD_initCStream_usingDict() */
if ( ZSTD_isError ( cstreamSize ) ) goto _output_error ;
if ( ZSTD_isError ( cdictSize ) ) goto _output_error ;
DISPLAYLEVEL ( 3 , " OK (%u bytes) \n " , ( U32 ) ( cstreamSize + cdictSize ) ) ;
2017-05-10 11:30:19 -07:00
}
DISPLAYLEVEL ( 3 , " test%3i : check actual CStream size : " , testNb + + ) ;
2017-06-21 15:53:42 -07:00
{ size_t const s = ZSTD_sizeof_CStream ( zc ) ;
if ( ZSTD_isError ( s ) ) goto _output_error ;
DISPLAYLEVEL ( 3 , " OK (%u bytes) \n " , ( U32 ) s ) ;
2016-08-22 15:30:31 -07:00
}
2017-04-10 17:50:44 -07:00
/* Attempt bad compression parameters */
DISPLAYLEVEL ( 3 , " test%3i : use bad compression parameters : " , testNb + + ) ;
{ size_t r ;
ZSTD_parameters params = ZSTD_getParams ( 1 , 0 , 0 ) ;
params . cParams . searchLength = 2 ;
r = ZSTD_initCStream_advanced ( zc , NULL , 0 , params , 0 ) ;
if ( ! ZSTD_isError ( r ) ) goto _output_error ;
DISPLAYLEVEL ( 3 , " init error : %s \n " , ZSTD_getErrorName ( r ) ) ;
}
2016-08-12 07:48:02 -07:00
/* skippable frame test */
2017-01-19 12:12:50 -08:00
DISPLAYLEVEL ( 3 , " test%3i : decompress skippable frame : " , testNb + + ) ;
2017-09-28 02:14:48 -07:00
CHECK_Z ( ZSTD_initDStream_usingDict ( zd , CNBuffer , dictSize ) ) ;
2016-08-16 16:39:22 -07:00
inBuff . src = compressedBuffer ;
inBuff . size = cSize ;
inBuff . pos = 0 ;
outBuff . dst = decodedBuffer ;
outBuff . size = CNBufferSize ;
outBuff . pos = 0 ;
2017-06-21 15:53:42 -07:00
{ size_t const r = ZSTD_decompressStream ( zd , & outBuff , & inBuff ) ;
DISPLAYLEVEL ( 5 , " ( ZSTD_decompressStream => %u ) " , ( U32 ) r ) ;
if ( r ! = 0 ) goto _output_error ;
}
2017-02-28 01:15:28 -08:00
if ( outBuff . pos ! = 0 ) goto _output_error ; /* skippable frame output len is 0 */
2017-01-19 12:12:50 -08:00
DISPLAYLEVEL ( 3 , " OK \n " ) ;
2016-08-12 07:48:02 -07:00
/* Basic decompression test */
2016-12-02 18:37:38 -08:00
inBuff2 = inBuff ;
2017-01-19 12:12:50 -08:00
DISPLAYLEVEL ( 3 , " test%3i : decompress %u bytes : " , testNb + + , COMPRESSIBLE_NOISE_LENGTH ) ;
2017-05-10 11:30:19 -07:00
ZSTD_initDStream_usingDict ( zd , CNBuffer , dictSize ) ;
2017-09-28 02:14:48 -07:00
CHECK_Z ( ZSTD_setDStreamParameter ( zd , DStream_p_maxWindowSize , 1000000000 ) ) ; /* large limit */
2016-12-02 18:37:38 -08:00
{ size_t const remaining = ZSTD_decompressStream ( zd , & outBuff , & inBuff ) ;
if ( remaining ! = 0 ) goto _output_error ; } /* should reach end of frame == 0; otherwise, some data left, or an error */
if ( outBuff . pos ! = CNBufferSize ) goto _output_error ; /* should regenerate the same amount */
if ( inBuff . pos ! = inBuff . size ) goto _output_error ; /* should have read the entire frame */
2017-01-19 12:12:50 -08:00
DISPLAYLEVEL ( 3 , " OK \n " ) ;
2016-12-02 18:37:38 -08:00
/* Re-use without init */
2017-01-19 12:12:50 -08:00
DISPLAYLEVEL ( 3 , " test%3i : decompress again without init (re-use previous settings): " , testNb + + ) ;
2016-12-02 18:37:38 -08:00
outBuff . pos = 0 ;
{ size_t const remaining = ZSTD_decompressStream ( zd , & outBuff , & inBuff2 ) ;
if ( remaining ! = 0 ) goto _output_error ; } /* should reach end of frame == 0; otherwise, some data left, or an error */
2016-08-16 16:39:22 -07:00
if ( outBuff . pos ! = CNBufferSize ) goto _output_error ; /* should regenerate the same amount */
if ( inBuff . pos ! = inBuff . size ) goto _output_error ; /* should have read the entire frame */
2017-01-19 12:12:50 -08:00
DISPLAYLEVEL ( 3 , " OK \n " ) ;
2016-08-12 07:48:02 -07:00
/* check regenerated data is byte exact */
2017-01-19 12:12:50 -08:00
DISPLAYLEVEL ( 3 , " test%3i : check decompressed result : " , testNb + + ) ;
2016-08-12 07:48:02 -07:00
{ size_t i ;
for ( i = 0 ; i < CNBufferSize ; i + + ) {
if ( ( ( BYTE * ) decodedBuffer ) [ i ] ! = ( ( BYTE * ) CNBuffer ) [ i ] ) goto _output_error ;
} }
2017-01-19 12:12:50 -08:00
DISPLAYLEVEL ( 3 , " OK \n " ) ;
2016-08-12 07:48:02 -07:00
2017-05-09 16:18:17 -07:00
/* context size functions */
DISPLAYLEVEL ( 3 , " test%3i : estimate DStream size : " , testNb + + ) ;
{ ZSTD_frameHeader fhi ;
const void * cStart = ( char * ) compressedBuffer + ( skippableFrameSize + 8 ) ;
size_t const gfhError = ZSTD_getFrameHeader ( & fhi , cStart , cSize ) ;
if ( gfhError ! = 0 ) goto _output_error ;
2017-06-26 17:44:26 -07:00
DISPLAYLEVEL ( 5 , " (windowSize : %u) " , ( U32 ) fhi . windowSize ) ;
{ size_t const s = ZSTD_estimateDStreamSize ( fhi . windowSize )
2017-05-25 15:07:37 -07:00
/* uses ZSTD_initDStream_usingDict() */
2017-08-29 11:55:02 -07:00
+ ZSTD_estimateDDictSize ( dictSize , ZSTD_dlm_byCopy ) ;
2017-05-09 16:18:17 -07:00
if ( ZSTD_isError ( s ) ) goto _output_error ;
DISPLAYLEVEL ( 3 , " OK (%u bytes) \n " , ( U32 ) s ) ;
} }
DISPLAYLEVEL ( 3 , " test%3i : check actual DStream size : " , testNb + + ) ;
2016-08-22 16:18:06 -07:00
{ size_t const s = ZSTD_sizeof_DStream ( zd ) ;
2016-08-22 15:30:31 -07:00
if ( ZSTD_isError ( s ) ) goto _output_error ;
2017-01-19 12:12:50 -08:00
DISPLAYLEVEL ( 3 , " OK (%u bytes) \n " , ( U32 ) s ) ;
2016-08-22 15:30:31 -07:00
}
2016-08-12 07:48:02 -07:00
/* Byte-by-byte decompression test */
2017-01-19 12:12:50 -08:00
DISPLAYLEVEL ( 3 , " test%3i : decompress byte-by-byte : " , testNb + + ) ;
2016-09-14 08:26:59 -07:00
{ /* skippable frame */
size_t r = 1 ;
2017-05-10 11:30:19 -07:00
ZSTD_initDStream_usingDict ( zd , CNBuffer , dictSize ) ;
2016-08-16 16:39:22 -07:00
inBuff . src = compressedBuffer ;
outBuff . dst = decodedBuffer ;
inBuff . pos = 0 ;
outBuff . pos = 0 ;
2016-08-12 07:48:02 -07:00
while ( r ) { /* skippable frame */
2016-08-16 16:39:22 -07:00
inBuff . size = inBuff . pos + 1 ;
outBuff . size = outBuff . pos + 1 ;
r = ZSTD_decompressStream ( zd , & outBuff , & inBuff ) ;
2016-08-12 07:48:02 -07:00
if ( ZSTD_isError ( r ) ) goto _output_error ;
}
2016-09-14 08:26:59 -07:00
/* normal frame */
2017-05-10 11:30:19 -07:00
ZSTD_initDStream_usingDict ( zd , CNBuffer , dictSize ) ;
2016-08-12 07:48:02 -07:00
r = 1 ;
2016-09-14 08:26:59 -07:00
while ( r ) {
2016-08-16 16:39:22 -07:00
inBuff . size = inBuff . pos + 1 ;
outBuff . size = outBuff . pos + 1 ;
r = ZSTD_decompressStream ( zd , & outBuff , & inBuff ) ;
2016-08-12 07:48:02 -07:00
if ( ZSTD_isError ( r ) ) goto _output_error ;
}
}
2016-08-16 16:39:22 -07:00
if ( outBuff . pos ! = CNBufferSize ) goto _output_error ; /* should regenerate the same amount */
if ( inBuff . pos ! = cSize ) goto _output_error ; /* should have read the entire frame */
2017-01-19 12:12:50 -08:00
DISPLAYLEVEL ( 3 , " OK \n " ) ;
2016-08-12 07:48:02 -07:00
/* check regenerated data is byte exact */
2017-01-19 12:12:50 -08:00
DISPLAYLEVEL ( 3 , " test%3i : check decompressed result : " , testNb + + ) ;
2016-08-12 07:48:02 -07:00
{ size_t i ;
for ( i = 0 ; i < CNBufferSize ; i + + ) {
if ( ( ( BYTE * ) decodedBuffer ) [ i ] ! = ( ( BYTE * ) CNBuffer ) [ i ] ) goto _output_error ; ;
} }
2017-01-19 12:12:50 -08:00
DISPLAYLEVEL ( 3 , " OK \n " ) ;
2016-08-12 07:48:02 -07:00
2016-12-13 07:39:36 -08:00
/* _srcSize compression test */
2017-01-19 12:12:50 -08:00
DISPLAYLEVEL ( 3 , " test%3i : compress_srcSize %u bytes : " , testNb + + , COMPRESSIBLE_NOISE_LENGTH ) ;
2016-12-13 07:39:36 -08:00
ZSTD_initCStream_srcSize ( zc , 1 , CNBufferSize ) ;
2016-12-18 12:39:15 -08:00
outBuff . dst = ( char * ) ( compressedBuffer ) ;
2016-12-13 07:39:36 -08:00
outBuff . size = compressedBufferSize ;
outBuff . pos = 0 ;
inBuff . src = CNBuffer ;
inBuff . size = CNBufferSize ;
inBuff . pos = 0 ;
2017-09-28 02:14:48 -07:00
CHECK_Z ( ZSTD_compressStream ( zc , & outBuff , & inBuff ) ) ;
2016-12-13 07:39:36 -08:00
if ( inBuff . pos ! = inBuff . size ) goto _output_error ; /* entire input should be consumed */
{ size_t const r = ZSTD_endStream ( zc , & outBuff ) ;
if ( r ! = 0 ) goto _output_error ; } /* error, or some data not flushed */
2017-02-07 13:50:09 -08:00
{ unsigned long long origSize = ZSTD_findDecompressedSize ( outBuff . dst , outBuff . pos ) ;
2016-12-18 12:39:15 -08:00
if ( ( size_t ) origSize ! = CNBufferSize ) goto _output_error ; } /* exact original size must be present */
2017-01-19 12:12:50 -08:00
DISPLAYLEVEL ( 3 , " OK (%u bytes : %.2f%%) \n " , ( U32 ) cSize , ( double ) cSize / COMPRESSIBLE_NOISE_LENGTH * 100 ) ;
2016-12-13 07:39:36 -08:00
/* wrong _srcSize compression test */
2017-01-19 12:12:50 -08:00
DISPLAYLEVEL ( 3 , " test%3i : wrong srcSize : %u bytes : " , testNb + + , COMPRESSIBLE_NOISE_LENGTH - 1 ) ;
2016-12-13 07:39:36 -08:00
ZSTD_initCStream_srcSize ( zc , 1 , CNBufferSize - 1 ) ;
2016-12-18 12:39:15 -08:00
outBuff . dst = ( char * ) ( compressedBuffer ) ;
2016-12-13 07:39:36 -08:00
outBuff . size = compressedBufferSize ;
outBuff . pos = 0 ;
inBuff . src = CNBuffer ;
inBuff . size = CNBufferSize ;
inBuff . pos = 0 ;
2017-09-28 02:14:48 -07:00
CHECK_Z ( ZSTD_compressStream ( zc , & outBuff , & inBuff ) ) ;
2016-12-13 07:39:36 -08:00
if ( inBuff . pos ! = inBuff . size ) goto _output_error ; /* entire input should be consumed */
{ size_t const r = ZSTD_endStream ( zc , & outBuff ) ;
if ( ZSTD_getErrorCode ( r ) ! = ZSTD_error_srcSize_wrong ) goto _output_error ; /* must fail : wrong srcSize */
2017-01-19 12:12:50 -08:00
DISPLAYLEVEL ( 3 , " OK (error detected : %s) \n " , ZSTD_getErrorName ( r ) ) ; }
2016-12-13 07:39:36 -08:00
2016-09-06 06:01:51 -07:00
/* Complex context re-use scenario */
2017-01-19 12:12:50 -08:00
DISPLAYLEVEL ( 3 , " test%3i : context re-use : " , testNb + + ) ;
2016-09-06 06:01:51 -07:00
ZSTD_freeCStream ( zc ) ;
2017-11-27 12:15:23 -08:00
zc = ZSTD_createCStream ( ) ;
2016-09-06 06:01:51 -07:00
if ( zc = = NULL ) goto _output_error ; /* memory allocation issue */
/* use 1 */
{ size_t const inSize = 513 ;
2017-05-08 16:08:01 -07:00
DISPLAYLEVEL ( 5 , " use1 " ) ;
2016-09-06 06:01:51 -07:00
ZSTD_initCStream_advanced ( zc , NULL , 0 , ZSTD_getParams ( 19 , inSize , 0 ) , inSize ) ; /* needs btopt + search3 to trigger hashLog3 */
inBuff . src = CNBuffer ;
inBuff . size = inSize ;
inBuff . pos = 0 ;
outBuff . dst = ( char * ) ( compressedBuffer ) + cSize ;
outBuff . size = ZSTD_compressBound ( inSize ) ;
outBuff . pos = 0 ;
2017-05-08 16:08:01 -07:00
DISPLAYLEVEL ( 5 , " compress1 " ) ;
2017-09-28 02:14:48 -07:00
CHECK_Z ( ZSTD_compressStream ( zc , & outBuff , & inBuff ) ) ;
2016-09-06 06:01:51 -07:00
if ( inBuff . pos ! = inBuff . size ) goto _output_error ; /* entire input should be consumed */
2017-05-08 16:08:01 -07:00
DISPLAYLEVEL ( 5 , " end1 " ) ;
2016-09-06 06:01:51 -07:00
{ size_t const r = ZSTD_endStream ( zc , & outBuff ) ;
if ( r ! = 0 ) goto _output_error ; } /* error, or some data not flushed */
}
/* use 2 */
{ size_t const inSize = 1025 ; /* will not continue, because tables auto-adjust and are therefore different size */
2017-05-08 16:08:01 -07:00
DISPLAYLEVEL ( 5 , " use2 " ) ;
2016-09-06 06:01:51 -07:00
ZSTD_initCStream_advanced ( zc , NULL , 0 , ZSTD_getParams ( 19 , inSize , 0 ) , inSize ) ; /* needs btopt + search3 to trigger hashLog3 */
inBuff . src = CNBuffer ;
inBuff . size = inSize ;
inBuff . pos = 0 ;
outBuff . dst = ( char * ) ( compressedBuffer ) + cSize ;
outBuff . size = ZSTD_compressBound ( inSize ) ;
outBuff . pos = 0 ;
2017-05-08 16:08:01 -07:00
DISPLAYLEVEL ( 5 , " compress2 " ) ;
2017-09-28 02:14:48 -07:00
CHECK_Z ( ZSTD_compressStream ( zc , & outBuff , & inBuff ) ) ;
2016-09-06 06:01:51 -07:00
if ( inBuff . pos ! = inBuff . size ) goto _output_error ; /* entire input should be consumed */
2017-05-08 16:08:01 -07:00
DISPLAYLEVEL ( 5 , " end2 " ) ;
2016-09-06 06:01:51 -07:00
{ size_t const r = ZSTD_endStream ( zc , & outBuff ) ;
if ( r ! = 0 ) goto _output_error ; } /* error, or some data not flushed */
}
2017-01-19 12:12:50 -08:00
DISPLAYLEVEL ( 3 , " OK \n " ) ;
2016-09-06 06:01:51 -07:00
2016-10-25 16:19:52 -07:00
/* CDict scenario */
2017-01-19 12:12:50 -08:00
DISPLAYLEVEL ( 3 , " test%3i : digested dictionary : " , testNb + + ) ;
2017-06-27 17:09:12 -07:00
{ ZSTD_CDict * const cdict = ZSTD_createCDict ( dictionary . start , dictionary . filled , 1 /*byRef*/ ) ;
2016-10-25 16:19:52 -07:00
size_t const initError = ZSTD_initCStream_usingCDict ( zc , cdict ) ;
2017-11-16 15:02:28 -08:00
DISPLAYLEVEL ( 5 , " ZSTD_initCStream_usingCDict result : %u " , ( U32 ) initError ) ;
2016-10-25 16:19:52 -07:00
if ( ZSTD_isError ( initError ) ) goto _output_error ;
cSize = 0 ;
outBuff . dst = compressedBuffer ;
outBuff . size = compressedBufferSize ;
outBuff . pos = 0 ;
inBuff . src = CNBuffer ;
inBuff . size = CNBufferSize ;
inBuff . pos = 0 ;
2017-11-16 15:02:28 -08:00
DISPLAYLEVEL ( 5 , " - starting ZSTD_compressStream " ) ;
2017-09-28 02:14:48 -07:00
CHECK_Z ( ZSTD_compressStream ( zc , & outBuff , & inBuff ) ) ;
2016-10-25 16:19:52 -07:00
if ( inBuff . pos ! = inBuff . size ) goto _output_error ; /* entire input should be consumed */
2017-11-16 15:02:28 -08:00
{ size_t const r = ZSTD_endStream ( zc , & outBuff ) ;
DISPLAYLEVEL ( 5 , " - ZSTD_endStream result : %u " , ( U32 ) r ) ;
if ( r ! = 0 ) goto _output_error ; /* error, or some data not flushed */
}
2016-10-25 16:19:52 -07:00
cSize = outBuff . pos ;
ZSTD_freeCDict ( cdict ) ;
2017-01-19 12:12:50 -08:00
DISPLAYLEVEL ( 3 , " OK (%u bytes : %.2f%%) \n " , ( U32 ) cSize , ( double ) cSize / CNBufferSize * 100 ) ;
2016-10-25 16:19:52 -07:00
}
2017-01-19 12:12:50 -08:00
DISPLAYLEVEL ( 3 , " test%3i : check CStream size : " , testNb + + ) ;
2016-09-06 06:01:51 -07:00
{ size_t const s = ZSTD_sizeof_CStream ( zc ) ;
if ( ZSTD_isError ( s ) ) goto _output_error ;
2017-01-19 12:12:50 -08:00
DISPLAYLEVEL ( 3 , " OK (%u bytes) \n " , ( U32 ) s ) ;
2016-09-06 06:01:51 -07:00
}
2017-01-16 19:46:22 -08:00
DISPLAYLEVEL ( 4 , " test%3i : check Dictionary ID : " , testNb + + ) ;
{ unsigned const dID = ZSTD_getDictID_fromFrame ( compressedBuffer , cSize ) ;
if ( dID ! = dictID ) goto _output_error ;
DISPLAYLEVEL ( 4 , " OK (%u) \n " , dID ) ;
}
2016-10-25 17:47:02 -07:00
/* DDict scenario */
2017-01-19 12:12:50 -08:00
DISPLAYLEVEL ( 3 , " test%3i : decompress %u bytes with digested dictionary : " , testNb + + , ( U32 ) CNBufferSize ) ;
2017-01-16 19:46:22 -08:00
{ ZSTD_DDict * const ddict = ZSTD_createDDict ( dictionary . start , dictionary . filled ) ;
2016-10-25 17:47:02 -07:00
size_t const initError = ZSTD_initDStream_usingDDict ( zd , ddict ) ;
if ( ZSTD_isError ( initError ) ) goto _output_error ;
inBuff . src = compressedBuffer ;
inBuff . size = cSize ;
inBuff . pos = 0 ;
outBuff . dst = decodedBuffer ;
outBuff . size = CNBufferSize ;
outBuff . pos = 0 ;
{ size_t const r = ZSTD_decompressStream ( zd , & outBuff , & inBuff ) ;
if ( r ! = 0 ) goto _output_error ; } /* should reach end of frame == 0; otherwise, some data left, or an error */
if ( outBuff . pos ! = CNBufferSize ) goto _output_error ; /* should regenerate the same amount */
if ( inBuff . pos ! = inBuff . size ) goto _output_error ; /* should have read the entire frame */
ZSTD_freeDDict ( ddict ) ;
2017-01-19 12:12:50 -08:00
DISPLAYLEVEL ( 3 , " OK \n " ) ;
2016-10-25 17:47:02 -07:00
}
2016-09-06 06:01:51 -07:00
/* test ZSTD_setDStreamParameter() resilience */
2017-01-19 12:12:50 -08:00
DISPLAYLEVEL ( 3 , " test%3i : wrong parameter for ZSTD_setDStreamParameter(): " , testNb + + ) ;
2016-08-23 07:58:10 -07:00
{ size_t const r = ZSTD_setDStreamParameter ( zd , ( ZSTD_DStreamParameter_e ) 999 , 1 ) ; /* large limit */
if ( ! ZSTD_isError ( r ) ) goto _output_error ; }
2017-01-19 12:12:50 -08:00
DISPLAYLEVEL ( 3 , " OK \n " ) ;
2016-08-23 07:58:10 -07:00
/* Memory restriction */
2017-01-19 12:12:50 -08:00
DISPLAYLEVEL ( 3 , " test%3i : maxWindowSize < frame requirement : " , testNb + + ) ;
2017-05-10 11:30:19 -07:00
ZSTD_initDStream_usingDict ( zd , CNBuffer , dictSize ) ;
2017-09-28 02:14:48 -07:00
CHECK_Z ( ZSTD_setDStreamParameter ( zd , DStream_p_maxWindowSize , 1000 ) ) ; /* too small limit */
2016-08-23 07:58:10 -07:00
inBuff . src = compressedBuffer ;
inBuff . size = cSize ;
inBuff . pos = 0 ;
outBuff . dst = decodedBuffer ;
outBuff . size = CNBufferSize ;
outBuff . pos = 0 ;
{ size_t const r = ZSTD_decompressStream ( zd , & outBuff , & inBuff ) ;
if ( ! ZSTD_isError ( r ) ) goto _output_error ; /* must fail : frame requires > 100 bytes */
2017-01-19 12:12:50 -08:00
DISPLAYLEVEL ( 3 , " OK (%s) \n " , ZSTD_getErrorName ( r ) ) ; }
2016-08-23 07:58:10 -07:00
2017-04-27 14:48:34 -07:00
DISPLAYLEVEL ( 3 , " test%3i : ZSTD_initCStream_usingCDict_advanced with masked dictID : " , testNb + + ) ;
{ ZSTD_compressionParameters const cParams = ZSTD_getCParams ( 1 , CNBufferSize , dictionary . filled ) ;
ZSTD_frameParameters const fParams = { 1 /* contentSize */ , 1 /* checksum */ , 1 /* noDictID */ } ;
2017-11-27 12:15:23 -08:00
ZSTD_CDict * const cdict = ZSTD_createCDict_advanced ( dictionary . start , dictionary . filled , ZSTD_dlm_byRef , ZSTD_dm_auto , cParams , ZSTD_defaultCMem ) ;
2017-06-03 01:15:02 -07:00
size_t const initError = ZSTD_initCStream_usingCDict_advanced ( zc , cdict , fParams , CNBufferSize ) ;
2017-04-27 14:48:34 -07:00
if ( ZSTD_isError ( initError ) ) goto _output_error ;
2017-04-03 20:56:39 -07:00
cSize = 0 ;
outBuff . dst = compressedBuffer ;
outBuff . size = compressedBufferSize ;
outBuff . pos = 0 ;
inBuff . src = CNBuffer ;
inBuff . size = CNBufferSize ;
inBuff . pos = 0 ;
2017-09-28 02:14:48 -07:00
CHECK_Z ( ZSTD_compressStream ( zc , & outBuff , & inBuff ) ) ;
2017-06-03 01:15:02 -07:00
if ( inBuff . pos ! = inBuff . size ) goto _output_error ; /* entire input should be consumed */
2017-04-03 20:56:39 -07:00
{ size_t const r = ZSTD_endStream ( zc , & outBuff ) ;
if ( r ! = 0 ) goto _output_error ; } /* error, or some data not flushed */
cSize = outBuff . pos ;
ZSTD_freeCDict ( cdict ) ;
DISPLAYLEVEL ( 3 , " OK (%u bytes : %.2f%%) \n " , ( U32 ) cSize , ( double ) cSize / CNBufferSize * 100 ) ;
2017-04-11 11:59:44 -07:00
}
2017-04-03 20:56:39 -07:00
2017-04-27 15:08:56 -07:00
DISPLAYLEVEL ( 3 , " test%3i : try retrieving dictID from frame : " , testNb + + ) ;
{ U32 const did = ZSTD_getDictID_fromFrame ( compressedBuffer , cSize ) ;
if ( did ! = 0 ) goto _output_error ;
}
DISPLAYLEVEL ( 3 , " OK (not detected) \n " ) ;
2017-04-11 11:59:44 -07:00
DISPLAYLEVEL ( 3 , " test%3i : decompress without dictionary : " , testNb + + ) ;
{ size_t const r = ZSTD_decompress ( decodedBuffer , CNBufferSize , compressedBuffer , cSize ) ;
if ( ! ZSTD_isError ( r ) ) goto _output_error ; /* must fail : dictionary not used */
DISPLAYLEVEL ( 3 , " OK (%s) \n " , ZSTD_getErrorName ( r ) ) ;
2017-04-03 20:56:39 -07:00
}
2017-06-28 16:25:13 -07:00
DISPLAYLEVEL ( 3 , " test%3i : compress with ZSTD_CCtx_refPrefix : " , testNb + + ) ;
2017-09-28 02:14:48 -07:00
CHECK_Z ( ZSTD_CCtx_refPrefix ( zc , dictionary . start , dictionary . filled ) ) ;
2017-06-28 16:25:13 -07:00
outBuff . dst = compressedBuffer ;
outBuff . size = compressedBufferSize ;
outBuff . pos = 0 ;
inBuff . src = CNBuffer ;
inBuff . size = CNBufferSize ;
inBuff . pos = 0 ;
2017-09-28 02:14:48 -07:00
CHECK_Z ( ZSTD_compress_generic ( zc , & outBuff , & inBuff , ZSTD_e_end ) ) ;
2017-06-28 16:25:13 -07:00
if ( inBuff . pos ! = inBuff . size ) goto _output_error ; /* entire input should be consumed */
cSize = outBuff . pos ;
DISPLAYLEVEL ( 3 , " OK (%u bytes : %.2f%%) \n " , ( U32 ) cSize , ( double ) cSize / CNBufferSize * 100 ) ;
DISPLAYLEVEL ( 3 , " test%3i : decompress with dictionary : " , testNb + + ) ;
{ size_t const r = ZSTD_decompress_usingDict ( zd ,
decodedBuffer , CNBufferSize ,
compressedBuffer , cSize ,
dictionary . start , dictionary . filled ) ;
if ( ZSTD_isError ( r ) ) goto _output_error ; /* must fail : dictionary not used */
DISPLAYLEVEL ( 3 , " OK \n " ) ;
}
DISPLAYLEVEL ( 3 , " test%3i : decompress without dictionary (should fail): " , testNb + + ) ;
{ size_t const r = ZSTD_decompress ( decodedBuffer , CNBufferSize , compressedBuffer , cSize ) ;
if ( ! ZSTD_isError ( r ) ) goto _output_error ; /* must fail : dictionary not used */
DISPLAYLEVEL ( 3 , " OK (%s) \n " , ZSTD_getErrorName ( r ) ) ;
}
DISPLAYLEVEL ( 3 , " test%3i : compress again with ZSTD_compress_generic : " , testNb + + ) ;
outBuff . dst = compressedBuffer ;
outBuff . size = compressedBufferSize ;
outBuff . pos = 0 ;
inBuff . src = CNBuffer ;
inBuff . size = CNBufferSize ;
inBuff . pos = 0 ;
2017-09-28 02:14:48 -07:00
CHECK_Z ( ZSTD_compress_generic ( zc , & outBuff , & inBuff , ZSTD_e_end ) ) ;
2017-06-28 16:25:13 -07:00
if ( inBuff . pos ! = inBuff . size ) goto _output_error ; /* entire input should be consumed */
cSize = outBuff . pos ;
DISPLAYLEVEL ( 3 , " OK (%u bytes : %.2f%%) \n " , ( U32 ) cSize , ( double ) cSize / CNBufferSize * 100 ) ;
DISPLAYLEVEL ( 3 , " test%3i : decompress without dictionary (should work): " , testNb + + ) ;
2017-09-28 02:14:48 -07:00
CHECK_Z ( ZSTD_decompress ( decodedBuffer , CNBufferSize , compressedBuffer , cSize ) ) ;
DISPLAYLEVEL ( 3 , " OK \n " ) ;
2017-06-28 16:25:13 -07:00
2017-04-18 15:08:52 -07:00
/* Empty srcSize */
DISPLAYLEVEL ( 3 , " test%3i : ZSTD_initCStream_advanced with pledgedSrcSize=0 and dict : " , testNb + + ) ;
{ ZSTD_parameters params = ZSTD_getParams ( 5 , 0 , 0 ) ;
params . fParams . contentSizeFlag = 1 ;
2017-10-13 19:01:58 -07:00
CHECK_Z ( ZSTD_initCStream_advanced ( zc , dictionary . start , dictionary . filled , params , 0 /* pledgedSrcSize==0 means "empty" when params.fParams.contentSizeFlag is set */ ) ) ;
2017-04-18 15:08:52 -07:00
} /* cstream advanced shall write content size = 0 */
inBuff . src = CNBuffer ;
inBuff . size = 0 ;
inBuff . pos = 0 ;
outBuff . dst = compressedBuffer ;
outBuff . size = compressedBufferSize ;
outBuff . pos = 0 ;
2017-09-28 02:14:48 -07:00
CHECK_Z ( ZSTD_compressStream ( zc , & outBuff , & inBuff ) ) ;
2017-04-18 15:08:52 -07:00
if ( ZSTD_endStream ( zc , & outBuff ) ! = 0 ) goto _output_error ;
cSize = outBuff . pos ;
if ( ZSTD_findDecompressedSize ( compressedBuffer , cSize ) ! = 0 ) goto _output_error ;
DISPLAYLEVEL ( 3 , " OK \n " ) ;
2017-02-09 10:50:43 -08:00
DISPLAYLEVEL ( 3 , " test%3i : pledgedSrcSize == 0 behaves properly : " , testNb + + ) ;
{ ZSTD_parameters params = ZSTD_getParams ( 5 , 0 , 0 ) ;
params . fParams . contentSizeFlag = 1 ;
2017-09-28 02:14:48 -07:00
CHECK_Z ( ZSTD_initCStream_advanced ( zc , NULL , 0 , params , 0 ) ) ;
2017-04-11 11:59:44 -07:00
} /* cstream advanced shall write content size = 0 */
2017-02-09 10:50:43 -08:00
inBuff . src = CNBuffer ;
inBuff . size = 0 ;
inBuff . pos = 0 ;
outBuff . dst = compressedBuffer ;
outBuff . size = compressedBufferSize ;
outBuff . pos = 0 ;
2017-09-28 02:14:48 -07:00
CHECK_Z ( ZSTD_compressStream ( zc , & outBuff , & inBuff ) ) ;
2017-02-09 10:50:43 -08:00
if ( ZSTD_endStream ( zc , & outBuff ) ! = 0 ) goto _output_error ;
cSize = outBuff . pos ;
if ( ZSTD_findDecompressedSize ( compressedBuffer , cSize ) ! = 0 ) goto _output_error ;
ZSTD_resetCStream ( zc , 0 ) ; /* resetCStream should treat 0 as unknown */
inBuff . src = CNBuffer ;
inBuff . size = 0 ;
inBuff . pos = 0 ;
outBuff . dst = compressedBuffer ;
outBuff . size = compressedBufferSize ;
outBuff . pos = 0 ;
2017-09-28 02:14:48 -07:00
CHECK_Z ( ZSTD_compressStream ( zc , & outBuff , & inBuff ) ) ;
2017-02-09 10:50:43 -08:00
if ( ZSTD_endStream ( zc , & outBuff ) ! = 0 ) goto _output_error ;
cSize = outBuff . pos ;
if ( ZSTD_findDecompressedSize ( compressedBuffer , cSize ) ! = ZSTD_CONTENTSIZE_UNKNOWN ) goto _output_error ;
DISPLAYLEVEL ( 3 , " OK \n " ) ;
2016-08-23 07:58:10 -07:00
2017-08-30 14:36:54 -07:00
/* Basic multithreading compression test */
DISPLAYLEVEL ( 3 , " test%3i : compress %u bytes with multiple threads : " , testNb + + , COMPRESSIBLE_NOISE_LENGTH ) ;
2017-09-28 02:14:48 -07:00
{ ZSTD_parameters const params = ZSTD_getParams ( 1 , 0 , 0 ) ;
CHECK_Z ( ZSTDMT_initCStream_advanced ( mtctx , CNBuffer , dictSize , params , CNBufferSize ) ) ;
}
2017-08-30 14:36:54 -07:00
outBuff . dst = ( char * ) ( compressedBuffer ) ;
outBuff . size = compressedBufferSize ;
outBuff . pos = 0 ;
inBuff . src = CNBuffer ;
inBuff . size = CNBufferSize ;
inBuff . pos = 0 ;
2017-09-28 02:14:48 -07:00
CHECK_Z ( ZSTDMT_compressStream_generic ( mtctx , & outBuff , & inBuff , ZSTD_e_end ) ) ;
2017-08-30 14:36:54 -07:00
if ( inBuff . pos ! = inBuff . size ) goto _output_error ; /* entire input should be consumed */
{ size_t const r = ZSTDMT_endStream ( mtctx , & outBuff ) ;
if ( r ! = 0 ) goto _output_error ; } /* error, or some data not flushed */
DISPLAYLEVEL ( 3 , " OK \n " ) ;
2017-10-16 17:18:43 -07:00
DISPLAYLEVEL ( 3 , " test%3i : check dictionary FSE tables can represent every code : " , testNb + + ) ;
{ unsigned const kMaxWindowLog = 24 ;
unsigned value ;
ZSTD_compressionParameters cParams = ZSTD_getCParams ( 3 , 1U < < kMaxWindowLog , 1024 ) ;
ZSTD_CDict * cdict ;
ZSTD_DDict * ddict ;
SEQ_stream seq = SEQ_initStream ( 0x87654321 ) ;
SEQ_gen_type type ;
XXH64_state_t xxh ;
XXH64_reset ( & xxh , 0 ) ;
cParams . windowLog = kMaxWindowLog ;
cdict = ZSTD_createCDict_advanced ( dictionary . start , dictionary . filled , ZSTD_dlm_byRef , ZSTD_dm_fullDict , cParams , ZSTD_defaultCMem ) ;
ddict = ZSTD_createDDict ( dictionary . start , dictionary . filled ) ;
if ( ! cdict | | ! ddict ) goto _output_error ;
ZSTD_CCtx_reset ( zc ) ;
ZSTD_resetDStream ( zd ) ;
CHECK_Z ( ZSTD_CCtx_refCDict ( zc , cdict ) ) ;
CHECK_Z ( ZSTD_initDStream_usingDDict ( zd , ddict ) ) ;
CHECK_Z ( ZSTD_setDStreamParameter ( zd , DStream_p_maxWindowSize , 1U < < kMaxWindowLog ) ) ;
/* Test all values < 300 */
for ( value = 0 ; value < 300 ; + + value ) {
for ( type = ( SEQ_gen_type ) 0 ; type < SEQ_gen_max ; + + type ) {
CHECK_Z ( SEQ_generateRoundTrip ( zc , zd , & xxh , & seq , type , value ) ) ;
}
}
/* Test values 2^8 to 2^17 */
for ( value = ( 1 < < 8 ) ; value < ( 1 < < 17 ) ; value < < = 1 ) {
for ( type = ( SEQ_gen_type ) 0 ; type < SEQ_gen_max ; + + type ) {
CHECK_Z ( SEQ_generateRoundTrip ( zc , zd , & xxh , & seq , type , value ) ) ;
CHECK_Z ( SEQ_generateRoundTrip ( zc , zd , & xxh , & seq , type , value + ( value > > 2 ) ) ) ;
}
}
/* Test offset values up to the max window log */
for ( value = 8 ; value < = kMaxWindowLog ; + + value ) {
CHECK_Z ( SEQ_generateRoundTrip ( zc , zd , & xxh , & seq , SEQ_gen_of , ( 1U < < value ) - 1 ) ) ;
}
CHECK_Z ( SEQ_roundTrip ( zc , zd , & xxh , NULL , 0 , ZSTD_e_end ) ) ;
CHECK ( SEQ_digest ( & seq ) ! = XXH64_digest ( & xxh ) , " SEQ XXH64 does not match " ) ;
ZSTD_freeCDict ( cdict ) ;
ZSTD_freeDDict ( ddict ) ;
}
DISPLAYLEVEL ( 3 , " OK \n " ) ;
2017-08-30 14:36:54 -07:00
2017-02-15 16:43:45 -08:00
/* Overlen overwriting window data bug */
DISPLAYLEVEL ( 3 , " test%3i : wildcopy doesn't overwrite potential match data : " , testNb + + ) ;
2017-02-16 13:29:47 -08:00
{ /* This test has a window size of 1024 bytes and consists of 3 blocks:
1. ' a ' repeated 517 times
2. ' b ' repeated 516 times
3. a compressed block with no literals and 3 sequence commands :
litlength = 0 , offset = 24 , match length = 24
litlength = 0 , offset = 24 , match length = 3 ( this one creates an overlength write of length 2 * WILDCOPY_OVERLENGTH - 3 )
litlength = 0 , offset = 1021 , match length = 3 ( this one will try to read from overwritten data if the buffer is too small ) */
const char * testCase =
" \x28 \xB5 \x2F \xFD \x04 \x00 \x4C \x00 \x00 \x10 \x61 \x61 \x01 \x00 \x00 \x2A "
" \x80 \x05 \x44 \x00 \x00 \x08 \x62 \x01 \x00 \x00 \x2A \x20 \x04 \x5D \x00 \x00 "
" \x00 \x03 \x40 \x00 \x00 \x64 \x60 \x27 \xB0 \xE0 \x0C \x67 \x62 \xCE \xE0 " ;
2017-09-28 02:14:48 -07:00
ZSTD_DStream * const zds = ZSTD_createDStream ( ) ;
if ( zds = = NULL ) goto _output_error ;
2017-02-15 16:43:45 -08:00
2017-09-28 02:14:48 -07:00
CHECK_Z ( ZSTD_initDStream ( zds ) ) ;
2017-02-15 16:43:45 -08:00
inBuff . src = testCase ;
2017-02-16 13:29:47 -08:00
inBuff . size = 47 ;
2017-02-15 16:43:45 -08:00
inBuff . pos = 0 ;
outBuff . dst = decodedBuffer ;
outBuff . size = CNBufferSize ;
outBuff . pos = 0 ;
while ( inBuff . pos < inBuff . size ) {
2017-09-28 02:14:48 -07:00
CHECK_Z ( ZSTD_decompressStream ( zds , & outBuff , & inBuff ) ) ;
2017-02-15 16:43:45 -08:00
}
2017-02-21 09:17:24 -08:00
ZSTD_freeDStream ( zds ) ;
2017-02-15 16:43:45 -08:00
}
DISPLAYLEVEL ( 3 , " OK \n " ) ;
2016-08-12 07:48:02 -07:00
_end :
2017-01-16 19:46:22 -08:00
FUZ_freeDictionary ( dictionary ) ;
2016-08-12 07:48:02 -07:00
ZSTD_freeCStream ( zc ) ;
ZSTD_freeDStream ( zd ) ;
2017-08-30 14:36:54 -07:00
ZSTDMT_freeCCtx ( mtctx ) ;
2016-08-12 07:48:02 -07:00
free ( CNBuffer ) ;
free ( compressedBuffer ) ;
free ( decodedBuffer ) ;
return testResult ;
_output_error :
testResult = 1 ;
DISPLAY ( " Error detected in Unit tests ! \n " ) ;
goto _end ;
}
2016-09-14 08:26:59 -07:00
/* ====== Fuzzer tests ====== */
2016-08-12 07:48:02 -07:00
static size_t findDiff ( const void * buf1 , const void * buf2 , size_t max )
{
const BYTE * b1 = ( const BYTE * ) buf1 ;
const BYTE * b2 = ( const BYTE * ) buf2 ;
size_t u ;
for ( u = 0 ; u < max ; u + + ) {
if ( b1 [ u ] ! = b2 [ u ] ) break ;
}
2017-01-19 12:12:50 -08:00
DISPLAY ( " Error at position %u / %u \n " , ( U32 ) u , ( U32 ) max ) ;
2017-01-25 16:25:38 -08:00
DISPLAY ( " %02X %02X %02X :%02X: %02X %02X %02X %02X %02X \n " ,
b1 [ u - 3 ] , b1 [ u - 2 ] , b1 [ u - 1 ] , b1 [ u - 0 ] , b1 [ u + 1 ] , b1 [ u + 2 ] , b1 [ u + 3 ] , b1 [ u + 4 ] , b1 [ u + 5 ] ) ;
DISPLAY ( " %02X %02X %02X :%02X: %02X %02X %02X %02X %02X \n " ,
b2 [ u - 3 ] , b2 [ u - 2 ] , b2 [ u - 1 ] , b2 [ u - 0 ] , b2 [ u + 1 ] , b2 [ u + 2 ] , b2 [ u + 3 ] , b2 [ u + 4 ] , b2 [ u + 5 ] ) ;
2016-08-12 07:48:02 -07:00
return u ;
}
static size_t FUZ_rLogLength ( U32 * seed , U32 logLength )
{
size_t const lengthMask = ( ( size_t ) 1 < < logLength ) - 1 ;
return ( lengthMask + 1 ) + ( FUZ_rand ( seed ) & lengthMask ) ;
}
static size_t FUZ_randomLength ( U32 * seed , U32 maxLog )
{
U32 const logLength = FUZ_rand ( seed ) % maxLog ;
return FUZ_rLogLength ( seed , logLength ) ;
}
2017-09-06 08:39:46 -07:00
/* Return value in range minVal <= v <= maxVal */
static U32 FUZ_randomClampedLength ( U32 * seed , U32 minVal , U32 maxVal )
{
U32 const mod = maxVal < minVal ? 1 : ( maxVal + 1 ) - minVal ;
return ( U32 ) ( ( FUZ_rand ( seed ) % mod ) + minVal ) ;
}
2017-03-20 11:25:00 -07:00
static int fuzzerTests ( U32 seed , U32 nbTests , unsigned startTest , double compressibility , int bigTests )
2016-08-12 07:48:02 -07:00
{
2017-06-21 23:35:58 -07:00
U32 const maxSrcLog = bigTests ? 24 : 22 ;
2016-08-12 07:48:02 -07:00
static const U32 maxSampleLog = 19 ;
2016-09-24 16:34:03 -07:00
size_t const srcBufferSize = ( size_t ) 1 < < maxSrcLog ;
2016-08-12 07:48:02 -07:00
BYTE * cNoiseBuffer [ 5 ] ;
2017-09-27 17:27:38 -07:00
size_t const copyBufferSize = srcBufferSize + ( 1 < < maxSampleLog ) ;
2016-09-24 16:34:03 -07:00
BYTE * const copyBuffer = ( BYTE * ) malloc ( copyBufferSize ) ;
2017-09-27 17:27:38 -07:00
size_t const cBufferSize = ZSTD_compressBound ( srcBufferSize ) ;
2016-09-24 16:34:03 -07:00
BYTE * const cBuffer = ( BYTE * ) malloc ( cBufferSize ) ;
size_t const dstBufferSize = srcBufferSize ;
BYTE * const dstBuffer = ( BYTE * ) malloc ( dstBufferSize ) ;
2016-08-12 07:48:02 -07:00
U32 result = 0 ;
U32 testNb = 0 ;
U32 coreSeed = seed ;
2017-09-27 17:27:38 -07:00
ZSTD_CStream * zc = ZSTD_createCStream ( ) ; /* will be re-created sometimes */
ZSTD_DStream * zd = ZSTD_createDStream ( ) ; /* will be re-created sometimes */
2016-09-24 16:34:03 -07:00
ZSTD_DStream * const zd_noise = ZSTD_createDStream ( ) ;
2017-11-29 19:11:12 -08:00
UTIL_time_t const startClock = UTIL_getTime ( ) ;
2017-09-27 17:27:38 -07:00
const BYTE * dict = NULL ; /* can keep same dict on 2 consecutive tests */
2016-09-26 07:41:05 -07:00
size_t dictSize = 0 ;
U32 oldTestLog = 0 ;
2017-06-21 18:43:39 -07:00
U32 const cLevelMax = bigTests ? ( U32 ) ZSTD_maxCLevel ( ) : g_cLevelMax_smallTests ;
2016-08-12 07:48:02 -07:00
/* allocations */
cNoiseBuffer [ 0 ] = ( BYTE * ) malloc ( srcBufferSize ) ;
cNoiseBuffer [ 1 ] = ( BYTE * ) malloc ( srcBufferSize ) ;
cNoiseBuffer [ 2 ] = ( BYTE * ) malloc ( srcBufferSize ) ;
cNoiseBuffer [ 3 ] = ( BYTE * ) malloc ( srcBufferSize ) ;
cNoiseBuffer [ 4 ] = ( BYTE * ) malloc ( srcBufferSize ) ;
CHECK ( ! cNoiseBuffer [ 0 ] | | ! cNoiseBuffer [ 1 ] | | ! cNoiseBuffer [ 2 ] | | ! cNoiseBuffer [ 3 ] | | ! cNoiseBuffer [ 4 ] | |
2016-09-24 16:34:03 -07:00
! copyBuffer | | ! dstBuffer | | ! cBuffer | | ! zc | | ! zd | | ! zd_noise ,
2016-08-12 07:48:02 -07:00
" Not enough memory, fuzzer tests cancelled " ) ;
/* Create initial samples */
RDG_genBuffer ( cNoiseBuffer [ 0 ] , srcBufferSize , 0.00 , 0. , coreSeed ) ; /* pure noise */
RDG_genBuffer ( cNoiseBuffer [ 1 ] , srcBufferSize , 0.05 , 0. , coreSeed ) ; /* barely compressible */
RDG_genBuffer ( cNoiseBuffer [ 2 ] , srcBufferSize , compressibility , 0. , coreSeed ) ;
RDG_genBuffer ( cNoiseBuffer [ 3 ] , srcBufferSize , 0.95 , 0. , coreSeed ) ; /* highly compressible */
RDG_genBuffer ( cNoiseBuffer [ 4 ] , srcBufferSize , 1.00 , 0. , coreSeed ) ; /* sparse content */
memset ( copyBuffer , 0x65 , copyBufferSize ) ; /* make copyBuffer considered initialized */
2016-09-24 16:34:03 -07:00
ZSTD_initDStream_usingDict ( zd , NULL , 0 ) ; /* ensure at least one init */
2016-08-12 07:48:02 -07:00
/* catch up testNb */
for ( testNb = 1 ; testNb < startTest ; testNb + + )
FUZ_rand ( & coreSeed ) ;
/* test loop */
2017-11-29 19:11:12 -08:00
for ( ; ( testNb < = nbTests ) | | ( UTIL_clockSpanMicro ( startClock ) < g_clockTime ) ; testNb + + ) {
2016-08-12 07:48:02 -07:00
U32 lseed ;
const BYTE * srcBuffer ;
2016-09-24 16:34:03 -07:00
size_t totalTestSize , totalGenSize , cSize ;
2016-08-12 07:48:02 -07:00
XXH64_state_t xxhState ;
U64 crcOrig ;
2016-09-24 16:34:03 -07:00
U32 resetAllowed = 1 ;
2016-09-26 07:41:05 -07:00
size_t maxTestSize ;
2016-08-12 07:48:02 -07:00
/* init */
2016-11-01 11:13:22 -07:00
if ( nbTests > = testNb ) { DISPLAYUPDATE ( 2 , " \r %6u/%6u " , testNb , nbTests ) ; }
else { DISPLAYUPDATE ( 2 , " \r %6u " , testNb ) ; }
2016-08-12 07:48:02 -07:00
FUZ_rand ( & coreSeed ) ;
2017-01-16 19:46:22 -08:00
lseed = coreSeed ^ prime32 ;
2016-08-12 07:48:02 -07:00
2016-09-14 08:26:59 -07:00
/* states full reset (deliberately not synchronized) */
/* some issues can only happen when reusing states */
2017-06-19 11:07:33 -07:00
if ( ( FUZ_rand ( & lseed ) & 0xFF ) = = 131 ) {
ZSTD_freeCStream ( zc ) ;
zc = ZSTD_createCStream ( ) ;
2017-06-21 15:53:42 -07:00
CHECK ( zc = = NULL , " ZSTD_createCStream : allocation error " ) ;
2017-06-19 11:07:33 -07:00
resetAllowed = 0 ;
}
if ( ( FUZ_rand ( & lseed ) & 0xFF ) = = 132 ) {
ZSTD_freeDStream ( zd ) ;
zd = ZSTD_createDStream ( ) ;
2017-06-21 15:53:42 -07:00
CHECK ( zd = = NULL , " ZSTD_createDStream : allocation error " ) ;
CHECK_Z ( ZSTD_initDStream_usingDict ( zd , NULL , 0 ) ) ; /* ensure at least one init */
2017-06-19 11:07:33 -07:00
}
2016-08-12 07:48:02 -07:00
/* srcBuffer selection [0-4] */
{ U32 buffNb = FUZ_rand ( & lseed ) & 0x7F ;
if ( buffNb & 7 ) buffNb = 2 ; /* most common : compressible (P) */
else {
buffNb > > = 3 ;
if ( buffNb & 7 ) {
const U32 tnb [ 2 ] = { 1 , 3 } ; /* barely/highly compressible */
buffNb = tnb [ buffNb > > 3 ] ;
} else {
const U32 tnb [ 2 ] = { 0 , 4 } ; /* not compressible / sparse */
buffNb = tnb [ buffNb > > 3 ] ;
} }
srcBuffer = cNoiseBuffer [ buffNb ] ;
}
/* compression init */
2016-09-26 07:41:05 -07:00
if ( ( FUZ_rand ( & lseed ) & 1 ) /* at beginning, to keep same nb of rand */
& & oldTestLog /* at least one test happened */ & & resetAllowed ) {
maxTestSize = FUZ_randomLength ( & lseed , oldTestLog + 2 ) ;
2017-09-27 17:27:38 -07:00
maxTestSize = MIN ( maxTestSize , srcBufferSize - 16 ) ;
2016-09-26 07:41:05 -07:00
{ U64 const pledgedSrcSize = ( FUZ_rand ( & lseed ) & 3 ) ? 0 : maxTestSize ;
2017-06-16 17:56:41 -07:00
CHECK_Z ( ZSTD_resetCStream ( zc , pledgedSrcSize ) ) ;
2016-09-26 07:41:05 -07:00
}
2016-09-24 16:34:03 -07:00
} else {
U32 const testLog = FUZ_rand ( & lseed ) % maxSrcLog ;
2017-03-15 15:04:54 -07:00
U32 const dictLog = FUZ_rand ( & lseed ) % maxSrcLog ;
2017-06-21 17:57:14 -07:00
U32 const cLevelCandidate = ( FUZ_rand ( & lseed ) %
2017-03-20 11:25:00 -07:00
( ZSTD_maxCLevel ( ) -
2017-06-21 17:57:14 -07:00
( MAX ( testLog , dictLog ) / 3 ) ) )
2017-04-05 16:34:09 -07:00
+ 1 ;
2017-06-21 17:57:14 -07:00
U32 const cLevel = MIN ( cLevelCandidate , cLevelMax ) ;
2016-08-12 07:48:02 -07:00
maxTestSize = FUZ_rLogLength ( & lseed , testLog ) ;
2016-09-26 07:41:05 -07:00
oldTestLog = testLog ;
2016-08-12 07:48:02 -07:00
/* random dictionary selection */
2017-06-21 23:35:58 -07:00
dictSize = ( ( FUZ_rand ( & lseed ) & 7 ) = = 1 ) ? FUZ_rLogLength ( & lseed , dictLog ) : 0 ;
2016-08-12 07:48:02 -07:00
{ size_t const dictStart = FUZ_rand ( & lseed ) % ( srcBufferSize - dictSize ) ;
dict = srcBuffer + dictStart ;
}
2017-10-13 19:01:58 -07:00
{ U64 const pledgedSrcSize = ( FUZ_rand ( & lseed ) & 3 ) ? ZSTD_CONTENTSIZE_UNKNOWN : maxTestSize ;
2016-09-26 07:41:05 -07:00
ZSTD_parameters params = ZSTD_getParams ( cLevel , pledgedSrcSize , dictSize ) ;
2016-08-12 07:48:02 -07:00
params . fParams . checksumFlag = FUZ_rand ( & lseed ) & 1 ;
params . fParams . noDictIDFlag = FUZ_rand ( & lseed ) & 1 ;
2017-10-13 19:01:58 -07:00
params . fParams . contentSizeFlag = FUZ_rand ( & lseed ) & 1 ;
2017-06-16 17:56:41 -07:00
CHECK_Z ( ZSTD_initCStream_advanced ( zc , dict , dictSize , params , pledgedSrcSize ) ) ;
} }
2016-08-12 07:48:02 -07:00
/* multi-segments compression test */
XXH64_reset ( & xxhState , 0 ) ;
2016-09-26 05:06:08 -07:00
{ ZSTD_outBuffer outBuff = { cBuffer , cBufferSize , 0 } ;
2016-09-24 16:34:03 -07:00
U32 n ;
2016-09-26 05:06:08 -07:00
for ( n = 0 , cSize = 0 , totalTestSize = 0 ; totalTestSize < maxTestSize ; n + + ) {
2016-12-13 07:39:36 -08:00
/* compress random chunks into randomly sized dst buffers */
2016-09-26 05:06:08 -07:00
{ size_t const randomSrcSize = FUZ_randomLength ( & lseed , maxSampleLog ) ;
2017-11-01 16:57:48 -07:00
size_t const srcSize = MIN ( maxTestSize - totalTestSize , randomSrcSize ) ;
2016-09-26 05:06:08 -07:00
size_t const srcStart = FUZ_rand ( & lseed ) % ( srcBufferSize - srcSize ) ;
2016-08-12 07:48:02 -07:00
size_t const randomDstSize = FUZ_randomLength ( & lseed , maxSampleLog ) ;
size_t const dstBuffSize = MIN ( cBufferSize - cSize , randomDstSize ) ;
2016-09-26 05:06:08 -07:00
ZSTD_inBuffer inBuff = { srcBuffer + srcStart , srcSize , 0 } ;
2016-08-16 16:39:22 -07:00
outBuff . size = outBuff . pos + dstBuffSize ;
2016-08-12 07:48:02 -07:00
2017-06-19 11:07:33 -07:00
CHECK_Z ( ZSTD_compressStream ( zc , & outBuff , & inBuff ) ) ;
2016-08-12 07:48:02 -07:00
2016-08-16 16:39:22 -07:00
XXH64_update ( & xxhState , srcBuffer + srcStart , inBuff . pos ) ;
memcpy ( copyBuffer + totalTestSize , srcBuffer + srcStart , inBuff . pos ) ;
totalTestSize + = inBuff . pos ;
2016-08-12 07:48:02 -07:00
}
/* random flush operation, to mess around */
if ( ( FUZ_rand ( & lseed ) & 15 ) = = 0 ) {
size_t const randomDstSize = FUZ_randomLength ( & lseed , maxSampleLog ) ;
2016-08-16 16:39:22 -07:00
size_t const adjustedDstSize = MIN ( cBufferSize - cSize , randomDstSize ) ;
outBuff . size = outBuff . pos + adjustedDstSize ;
2017-06-19 11:07:33 -07:00
CHECK_Z ( ZSTD_flushStream ( zc , & outBuff ) ) ;
} }
2016-08-12 07:48:02 -07:00
/* final frame epilogue */
{ size_t remainingToFlush = ( size_t ) ( - 1 ) ;
while ( remainingToFlush ) {
size_t const randomDstSize = FUZ_randomLength ( & lseed , maxSampleLog ) ;
size_t const adjustedDstSize = MIN ( cBufferSize - cSize , randomDstSize ) ;
2016-08-16 16:39:22 -07:00
outBuff . size = outBuff . pos + adjustedDstSize ;
remainingToFlush = ZSTD_endStream ( zc , & outBuff ) ;
2017-05-19 10:17:59 -07:00
CHECK ( ZSTD_isError ( remainingToFlush ) , " end error : %s " , ZSTD_getErrorName ( remainingToFlush ) ) ;
2016-08-12 07:48:02 -07:00
} }
crcOrig = XXH64_digest ( & xxhState ) ;
2016-08-16 16:39:22 -07:00
cSize = outBuff . pos ;
2016-08-12 07:48:02 -07:00
}
/* multi - fragments decompression test */
2016-09-24 16:34:03 -07:00
if ( ! dictSize /* don't reset if dictionary : could be different */ & & ( FUZ_rand ( & lseed ) & 1 ) ) {
2017-06-21 15:53:42 -07:00
CHECK_Z ( ZSTD_resetDStream ( zd ) ) ;
2016-12-02 18:37:38 -08:00
} else {
2017-06-21 15:53:42 -07:00
CHECK_Z ( ZSTD_initDStream_usingDict ( zd , dict , dictSize ) ) ;
2016-12-02 18:37:38 -08:00
}
2016-08-12 07:48:02 -07:00
{ size_t decompressionResult = 1 ;
2016-08-16 16:39:22 -07:00
ZSTD_inBuffer inBuff = { cBuffer , cSize , 0 } ;
ZSTD_outBuffer outBuff = { dstBuffer , dstBufferSize , 0 } ;
for ( totalGenSize = 0 ; decompressionResult ; ) {
2016-08-12 07:48:02 -07:00
size_t const readCSrcSize = FUZ_randomLength ( & lseed , maxSampleLog ) ;
size_t const randomDstSize = FUZ_randomLength ( & lseed , maxSampleLog ) ;
size_t const dstBuffSize = MIN ( dstBufferSize - totalGenSize , randomDstSize ) ;
2016-08-16 16:39:22 -07:00
inBuff . size = inBuff . pos + readCSrcSize ;
2017-09-27 00:39:41 -07:00
outBuff . size = outBuff . pos + dstBuffSize ;
2016-08-16 16:39:22 -07:00
decompressionResult = ZSTD_decompressStream ( zd , & outBuff , & inBuff ) ;
2017-09-09 14:37:28 -07:00
if ( ZSTD_getErrorCode ( decompressionResult ) = = ZSTD_error_checksum_wrong ) {
DISPLAY ( " checksum error : \n " ) ;
findDiff ( copyBuffer , dstBuffer , totalTestSize ) ;
}
CHECK ( ZSTD_isError ( decompressionResult ) , " decompression error : %s " ,
ZSTD_getErrorName ( decompressionResult ) ) ;
2016-08-12 07:48:02 -07:00
}
CHECK ( decompressionResult ! = 0 , " frame not fully decoded " ) ;
2017-09-09 14:37:28 -07:00
CHECK ( outBuff . pos ! = totalTestSize , " decompressed data : wrong size (%u != %u) " ,
( U32 ) outBuff . pos , ( U32 ) totalTestSize ) ;
2016-08-16 16:39:22 -07:00
CHECK ( inBuff . pos ! = cSize , " compressed data should be fully read " )
2016-08-12 07:48:02 -07:00
{ U64 const crcDest = XXH64 ( dstBuffer , totalTestSize , 0 ) ;
if ( crcDest ! = crcOrig ) findDiff ( copyBuffer , dstBuffer , totalTestSize ) ;
CHECK ( crcDest ! = crcOrig , " decompressed data corrupted " ) ;
} }
/*===== noisy/erroneous src decompression test =====*/
/* add some noise */
{ U32 const nbNoiseChunks = ( FUZ_rand ( & lseed ) & 7 ) + 2 ;
U32 nn ; for ( nn = 0 ; nn < nbNoiseChunks ; nn + + ) {
size_t const randomNoiseSize = FUZ_randomLength ( & lseed , maxSampleLog ) ;
size_t const noiseSize = MIN ( ( cSize / 3 ) , randomNoiseSize ) ;
size_t const noiseStart = FUZ_rand ( & lseed ) % ( srcBufferSize - noiseSize ) ;
size_t const cStart = FUZ_rand ( & lseed ) % ( cSize - noiseSize ) ;
memcpy ( cBuffer + cStart , srcBuffer + noiseStart , noiseSize ) ;
} }
/* try decompression on noisy data */
2017-06-21 15:53:42 -07:00
CHECK_Z ( ZSTD_initDStream ( zd_noise ) ) ; /* note : no dictionary */
2016-08-16 16:39:22 -07:00
{ ZSTD_inBuffer inBuff = { cBuffer , cSize , 0 } ;
ZSTD_outBuffer outBuff = { dstBuffer , dstBufferSize , 0 } ;
while ( outBuff . pos < dstBufferSize ) {
2016-08-12 07:48:02 -07:00
size_t const randomCSrcSize = FUZ_randomLength ( & lseed , maxSampleLog ) ;
size_t const randomDstSize = FUZ_randomLength ( & lseed , maxSampleLog ) ;
2016-08-16 16:39:22 -07:00
size_t const adjustedDstSize = MIN ( dstBufferSize - outBuff . pos , randomDstSize ) ;
2017-01-27 17:25:07 -08:00
size_t const adjustedCSrcSize = MIN ( cSize - inBuff . pos , randomCSrcSize ) ;
2016-08-16 16:39:22 -07:00
outBuff . size = outBuff . pos + adjustedDstSize ;
2017-01-27 17:25:07 -08:00
inBuff . size = inBuff . pos + adjustedCSrcSize ;
2016-08-16 16:39:22 -07:00
{ size_t const decompressError = ZSTD_decompressStream ( zd , & outBuff , & inBuff ) ;
2016-08-12 07:48:02 -07:00
if ( ZSTD_isError ( decompressError ) ) break ; /* error correctly detected */
2017-01-27 17:25:07 -08:00
/* No forward progress possible */
if ( outBuff . pos < outBuff . size & & inBuff . pos = = cSize ) break ;
2016-08-12 07:48:02 -07:00
} } } }
DISPLAY ( " \r %u fuzzer tests completed \n " , testNb ) ;
_cleanup :
ZSTD_freeCStream ( zc ) ;
ZSTD_freeDStream ( zd ) ;
2016-09-24 16:34:03 -07:00
ZSTD_freeDStream ( zd_noise ) ;
2016-08-12 07:48:02 -07:00
free ( cNoiseBuffer [ 0 ] ) ;
free ( cNoiseBuffer [ 1 ] ) ;
free ( cNoiseBuffer [ 2 ] ) ;
free ( cNoiseBuffer [ 3 ] ) ;
free ( cNoiseBuffer [ 4 ] ) ;
free ( copyBuffer ) ;
free ( cBuffer ) ;
free ( dstBuffer ) ;
return result ;
_output_error :
result = 1 ;
goto _cleanup ;
}
2017-01-19 12:12:50 -08:00
/* Multi-threading version of fuzzer Tests */
2017-03-20 11:25:00 -07:00
static int fuzzerTests_MT ( U32 seed , U32 nbTests , unsigned startTest , double compressibility , int bigTests )
2017-01-19 12:12:50 -08:00
{
2017-06-21 23:35:58 -07:00
const U32 maxSrcLog = bigTests ? 24 : 22 ;
2017-01-19 12:12:50 -08:00
static const U32 maxSampleLog = 19 ;
size_t const srcBufferSize = ( size_t ) 1 < < maxSrcLog ;
BYTE * cNoiseBuffer [ 5 ] ;
size_t const copyBufferSize = srcBufferSize + ( 1 < < maxSampleLog ) ;
BYTE * const copyBuffer = ( BYTE * ) malloc ( copyBufferSize ) ;
size_t const cBufferSize = ZSTD_compressBound ( srcBufferSize ) ;
BYTE * const cBuffer = ( BYTE * ) malloc ( cBufferSize ) ;
size_t const dstBufferSize = srcBufferSize ;
BYTE * const dstBuffer = ( BYTE * ) malloc ( dstBufferSize ) ;
U32 result = 0 ;
U32 testNb = 0 ;
U32 coreSeed = seed ;
2017-09-27 17:27:38 -07:00
U32 nbThreads = 2 ;
ZSTDMT_CCtx * zc = ZSTDMT_createCCtx ( nbThreads ) ; /* will be reset sometimes */
2017-01-19 12:12:50 -08:00
ZSTD_DStream * zd = ZSTD_createDStream ( ) ; /* will be reset sometimes */
ZSTD_DStream * const zd_noise = ZSTD_createDStream ( ) ;
2017-11-29 19:11:12 -08:00
UTIL_time_t const startClock = UTIL_getTime ( ) ;
2017-01-19 12:12:50 -08:00
const BYTE * dict = NULL ; /* can keep same dict on 2 consecutive tests */
size_t dictSize = 0 ;
U32 oldTestLog = 0 ;
2017-09-27 17:27:38 -07:00
int const cLevelMax = bigTests ? ( U32 ) ZSTD_maxCLevel ( ) - 1 : g_cLevelMax_smallTests ;
U32 const nbThreadsMax = bigTests ? 4 : 2 ;
2017-01-19 12:12:50 -08:00
/* allocations */
cNoiseBuffer [ 0 ] = ( BYTE * ) malloc ( srcBufferSize ) ;
cNoiseBuffer [ 1 ] = ( BYTE * ) malloc ( srcBufferSize ) ;
cNoiseBuffer [ 2 ] = ( BYTE * ) malloc ( srcBufferSize ) ;
cNoiseBuffer [ 3 ] = ( BYTE * ) malloc ( srcBufferSize ) ;
cNoiseBuffer [ 4 ] = ( BYTE * ) malloc ( srcBufferSize ) ;
CHECK ( ! cNoiseBuffer [ 0 ] | | ! cNoiseBuffer [ 1 ] | | ! cNoiseBuffer [ 2 ] | | ! cNoiseBuffer [ 3 ] | | ! cNoiseBuffer [ 4 ] | |
! copyBuffer | | ! dstBuffer | | ! cBuffer | | ! zc | | ! zd | | ! zd_noise ,
" Not enough memory, fuzzer tests cancelled " ) ;
/* Create initial samples */
RDG_genBuffer ( cNoiseBuffer [ 0 ] , srcBufferSize , 0.00 , 0. , coreSeed ) ; /* pure noise */
RDG_genBuffer ( cNoiseBuffer [ 1 ] , srcBufferSize , 0.05 , 0. , coreSeed ) ; /* barely compressible */
RDG_genBuffer ( cNoiseBuffer [ 2 ] , srcBufferSize , compressibility , 0. , coreSeed ) ;
RDG_genBuffer ( cNoiseBuffer [ 3 ] , srcBufferSize , 0.95 , 0. , coreSeed ) ; /* highly compressible */
RDG_genBuffer ( cNoiseBuffer [ 4 ] , srcBufferSize , 1.00 , 0. , coreSeed ) ; /* sparse content */
memset ( copyBuffer , 0x65 , copyBufferSize ) ; /* make copyBuffer considered initialized */
ZSTD_initDStream_usingDict ( zd , NULL , 0 ) ; /* ensure at least one init */
/* catch up testNb */
for ( testNb = 1 ; testNb < startTest ; testNb + + )
FUZ_rand ( & coreSeed ) ;
/* test loop */
2017-11-29 19:11:12 -08:00
for ( ; ( testNb < = nbTests ) | | ( UTIL_clockSpanMicro ( startClock ) < g_clockTime ) ; testNb + + ) {
2017-01-19 12:12:50 -08:00
U32 lseed ;
const BYTE * srcBuffer ;
size_t totalTestSize , totalGenSize , cSize ;
XXH64_state_t xxhState ;
U64 crcOrig ;
U32 resetAllowed = 1 ;
size_t maxTestSize ;
/* init */
2017-09-27 17:27:38 -07:00
if ( testNb < nbTests ) {
DISPLAYUPDATE ( 2 , " \r %6u/%6u " , testNb , nbTests ) ;
} else { DISPLAYUPDATE ( 2 , " \r %6u " , testNb ) ; }
2017-01-19 12:12:50 -08:00
FUZ_rand ( & coreSeed ) ;
2017-01-20 16:44:50 -08:00
lseed = coreSeed ^ prime32 ;
2017-01-19 12:12:50 -08:00
/* states full reset (deliberately not synchronized) */
/* some issues can only happen when reusing states */
if ( ( FUZ_rand ( & lseed ) & 0xFF ) = = 131 ) {
2017-09-28 01:42:06 -07:00
nbThreads = ( FUZ_rand ( & lseed ) % nbThreadsMax ) + 1 ;
2017-03-31 18:27:03 -07:00
DISPLAYLEVEL ( 5 , " Creating new context with %u threads \n " , nbThreads ) ;
2017-01-19 12:12:50 -08:00
ZSTDMT_freeCCtx ( zc ) ;
zc = ZSTDMT_createCCtx ( nbThreads ) ;
2017-06-21 15:53:42 -07:00
CHECK ( zc = = NULL , " ZSTDMT_createCCtx allocation error " )
2017-01-19 12:12:50 -08:00
resetAllowed = 0 ;
}
if ( ( FUZ_rand ( & lseed ) & 0xFF ) = = 132 ) {
ZSTD_freeDStream ( zd ) ;
zd = ZSTD_createDStream ( ) ;
2017-06-21 15:53:42 -07:00
CHECK ( zd = = NULL , " ZSTDMT_createCCtx allocation error " )
2017-01-19 12:12:50 -08:00
ZSTD_initDStream_usingDict ( zd , NULL , 0 ) ; /* ensure at least one init */
}
/* srcBuffer selection [0-4] */
{ U32 buffNb = FUZ_rand ( & lseed ) & 0x7F ;
if ( buffNb & 7 ) buffNb = 2 ; /* most common : compressible (P) */
else {
buffNb > > = 3 ;
if ( buffNb & 7 ) {
const U32 tnb [ 2 ] = { 1 , 3 } ; /* barely/highly compressible */
buffNb = tnb [ buffNb > > 3 ] ;
} else {
const U32 tnb [ 2 ] = { 0 , 4 } ; /* not compressible / sparse */
buffNb = tnb [ buffNb > > 3 ] ;
} }
srcBuffer = cNoiseBuffer [ buffNb ] ;
}
/* compression init */
if ( ( FUZ_rand ( & lseed ) & 1 ) /* at beginning, to keep same nb of rand */
& & oldTestLog /* at least one test happened */ & & resetAllowed ) {
maxTestSize = FUZ_randomLength ( & lseed , oldTestLog + 2 ) ;
if ( maxTestSize > = srcBufferSize ) maxTestSize = srcBufferSize - 1 ;
{ int const compressionLevel = ( FUZ_rand ( & lseed ) % 5 ) + 1 ;
2017-06-21 15:53:42 -07:00
CHECK_Z ( ZSTDMT_initCStream ( zc , compressionLevel ) ) ;
2017-01-19 12:12:50 -08:00
}
} else {
U32 const testLog = FUZ_rand ( & lseed ) % maxSrcLog ;
2017-03-15 15:04:54 -07:00
U32 const dictLog = FUZ_rand ( & lseed ) % maxSrcLog ;
2017-09-27 17:27:38 -07:00
int const cLevelCandidate = ( FUZ_rand ( & lseed )
% ( ZSTD_maxCLevel ( ) - ( MAX ( testLog , dictLog ) / 2 ) ) )
+ 1 ;
int const cLevelThreadAdjusted = cLevelCandidate - ( nbThreads * 2 ) + 2 ; /* reduce cLevel when multiple threads to reduce memory consumption */
int const cLevelMin = MAX ( cLevelThreadAdjusted , 1 ) ; /* no negative cLevel yet */
int const cLevel = MIN ( cLevelMin , cLevelMax ) ;
2017-01-19 12:12:50 -08:00
maxTestSize = FUZ_rLogLength ( & lseed , testLog ) ;
oldTestLog = testLog ;
/* random dictionary selection */
2017-03-15 15:04:54 -07:00
dictSize = ( ( FUZ_rand ( & lseed ) & 63 ) = = 1 ) ? FUZ_rLogLength ( & lseed , dictLog ) : 0 ;
2017-01-19 15:32:07 -08:00
{ size_t const dictStart = FUZ_rand ( & lseed ) % ( srcBufferSize - dictSize ) ;
dict = srcBuffer + dictStart ;
}
2017-10-13 19:09:30 -07:00
{ U64 const pledgedSrcSize = ( FUZ_rand ( & lseed ) & 3 ) ? ZSTD_CONTENTSIZE_UNKNOWN : maxTestSize ;
2017-01-19 15:32:07 -08:00
ZSTD_parameters params = ZSTD_getParams ( cLevel , pledgedSrcSize , dictSize ) ;
2017-04-05 16:34:09 -07:00
DISPLAYLEVEL ( 5 , " Init with windowLog = %u and pledgedSrcSize = %u \n " ,
params . cParams . windowLog , ( U32 ) pledgedSrcSize ) ;
2017-01-19 15:32:07 -08:00
params . fParams . checksumFlag = FUZ_rand ( & lseed ) & 1 ;
params . fParams . noDictIDFlag = FUZ_rand ( & lseed ) & 1 ;
2017-10-13 19:09:30 -07:00
params . fParams . contentSizeFlag = FUZ_rand ( & lseed ) & 1 ;
2017-04-18 22:52:41 -07:00
DISPLAYLEVEL ( 5 , " checksumFlag : %u \n " , params . fParams . checksumFlag ) ;
2017-06-21 15:53:42 -07:00
CHECK_Z ( ZSTDMT_initCStream_advanced ( zc , dict , dictSize , params , pledgedSrcSize ) ) ;
CHECK_Z ( ZSTDMT_setMTCtxParameter ( zc , ZSTDMT_p_overlapSectionLog , FUZ_rand ( & lseed ) % 12 ) ) ;
CHECK_Z ( ZSTDMT_setMTCtxParameter ( zc , ZSTDMT_p_sectionSize , FUZ_rand ( & lseed ) % ( 2 * maxTestSize + 1 ) ) ) ;
2017-01-30 12:46:35 -08:00
} }
2017-01-19 12:12:50 -08:00
/* multi-segments compression test */
XXH64_reset ( & xxhState , 0 ) ;
{ ZSTD_outBuffer outBuff = { cBuffer , cBufferSize , 0 } ;
U32 n ;
for ( n = 0 , cSize = 0 , totalTestSize = 0 ; totalTestSize < maxTestSize ; n + + ) {
/* compress random chunks into randomly sized dst buffers */
{ size_t const randomSrcSize = FUZ_randomLength ( & lseed , maxSampleLog ) ;
size_t const srcSize = MIN ( maxTestSize - totalTestSize , randomSrcSize ) ;
size_t const srcStart = FUZ_rand ( & lseed ) % ( srcBufferSize - srcSize ) ;
size_t const randomDstSize = FUZ_randomLength ( & lseed , maxSampleLog ) ;
size_t const dstBuffSize = MIN ( cBufferSize - cSize , randomDstSize ) ;
ZSTD_inBuffer inBuff = { srcBuffer + srcStart , srcSize , 0 } ;
outBuff . size = outBuff . pos + dstBuffSize ;
DISPLAYLEVEL ( 5 , " Sending %u bytes to compress \n " , ( U32 ) srcSize ) ;
2017-06-21 15:53:42 -07:00
CHECK_Z ( ZSTDMT_compressStream ( zc , & outBuff , & inBuff ) ) ;
2017-01-19 15:32:07 -08:00
DISPLAYLEVEL ( 5 , " %u bytes read by ZSTDMT_compressStream \n " , ( U32 ) inBuff . pos ) ;
2017-01-19 12:12:50 -08:00
XXH64_update ( & xxhState , srcBuffer + srcStart , inBuff . pos ) ;
memcpy ( copyBuffer + totalTestSize , srcBuffer + srcStart , inBuff . pos ) ;
totalTestSize + = inBuff . pos ;
}
/* random flush operation, to mess around */
if ( ( FUZ_rand ( & lseed ) & 15 ) = = 0 ) {
size_t const randomDstSize = FUZ_randomLength ( & lseed , maxSampleLog ) ;
size_t const adjustedDstSize = MIN ( cBufferSize - cSize , randomDstSize ) ;
outBuff . size = outBuff . pos + adjustedDstSize ;
DISPLAYLEVEL ( 5 , " Flushing into dst buffer of size %u \n " , ( U32 ) adjustedDstSize ) ;
2017-06-21 15:53:42 -07:00
CHECK_Z ( ZSTDMT_flushStream ( zc , & outBuff ) ) ;
} }
2017-01-19 12:12:50 -08:00
/* final frame epilogue */
{ size_t remainingToFlush = ( size_t ) ( - 1 ) ;
while ( remainingToFlush ) {
size_t const randomDstSize = FUZ_randomLength ( & lseed , maxSampleLog ) ;
size_t const adjustedDstSize = MIN ( cBufferSize - cSize , randomDstSize ) ;
outBuff . size = outBuff . pos + adjustedDstSize ;
DISPLAYLEVEL ( 5 , " Ending into dst buffer of size %u \n " , ( U32 ) adjustedDstSize ) ;
remainingToFlush = ZSTDMT_endStream ( zc , & outBuff ) ;
2017-03-31 18:27:03 -07:00
CHECK ( ZSTD_isError ( remainingToFlush ) , " ZSTDMT_endStream error : %s " , ZSTD_getErrorName ( remainingToFlush ) ) ;
2017-01-19 12:12:50 -08:00
DISPLAYLEVEL ( 5 , " endStream : remainingToFlush : %u \n " , ( U32 ) remainingToFlush ) ;
} }
crcOrig = XXH64_digest ( & xxhState ) ;
cSize = outBuff . pos ;
2017-04-18 22:52:41 -07:00
DISPLAYLEVEL ( 5 , " Frame completed : %u bytes \n " , ( U32 ) cSize ) ;
2017-01-19 12:12:50 -08:00
}
/* multi - fragments decompression test */
if ( ! dictSize /* don't reset if dictionary : could be different */ & & ( FUZ_rand ( & lseed ) & 1 ) ) {
2017-06-21 15:53:42 -07:00
CHECK_Z ( ZSTD_resetDStream ( zd ) ) ;
2017-01-19 12:12:50 -08:00
} else {
2017-06-21 15:53:42 -07:00
CHECK_Z ( ZSTD_initDStream_usingDict ( zd , dict , dictSize ) ) ;
2017-01-19 12:12:50 -08:00
}
{ size_t decompressionResult = 1 ;
ZSTD_inBuffer inBuff = { cBuffer , cSize , 0 } ;
ZSTD_outBuffer outBuff = { dstBuffer , dstBufferSize , 0 } ;
for ( totalGenSize = 0 ; decompressionResult ; ) {
size_t const readCSrcSize = FUZ_randomLength ( & lseed , maxSampleLog ) ;
size_t const randomDstSize = FUZ_randomLength ( & lseed , maxSampleLog ) ;
size_t const dstBuffSize = MIN ( dstBufferSize - totalGenSize , randomDstSize ) ;
inBuff . size = inBuff . pos + readCSrcSize ;
2017-09-27 01:01:11 -07:00
outBuff . size = outBuff . pos + dstBuffSize ;
2017-04-05 16:34:09 -07:00
DISPLAYLEVEL ( 5 , " ZSTD_decompressStream input %u bytes \n " , ( U32 ) readCSrcSize ) ;
2017-01-19 12:12:50 -08:00
decompressionResult = ZSTD_decompressStream ( zd , & outBuff , & inBuff ) ;
CHECK ( ZSTD_isError ( decompressionResult ) , " decompression error : %s " , ZSTD_getErrorName ( decompressionResult ) ) ;
2017-04-18 22:52:41 -07:00
DISPLAYLEVEL ( 5 , " inBuff.pos = %u \n " , ( U32 ) readCSrcSize ) ;
2017-01-19 12:12:50 -08:00
}
2017-01-25 16:25:38 -08:00
CHECK ( outBuff . pos ! = totalTestSize , " decompressed data : wrong size (%u != %u) " , ( U32 ) outBuff . pos , ( U32 ) totalTestSize ) ;
CHECK ( inBuff . pos ! = cSize , " compressed data should be fully read (%u != %u) " , ( U32 ) inBuff . pos , ( U32 ) cSize ) ;
2017-01-19 12:12:50 -08:00
{ U64 const crcDest = XXH64 ( dstBuffer , totalTestSize , 0 ) ;
if ( crcDest ! = crcOrig ) findDiff ( copyBuffer , dstBuffer , totalTestSize ) ;
CHECK ( crcDest ! = crcOrig , " decompressed data corrupted " ) ;
} }
/*===== noisy/erroneous src decompression test =====*/
/* add some noise */
{ U32 const nbNoiseChunks = ( FUZ_rand ( & lseed ) & 7 ) + 2 ;
U32 nn ; for ( nn = 0 ; nn < nbNoiseChunks ; nn + + ) {
size_t const randomNoiseSize = FUZ_randomLength ( & lseed , maxSampleLog ) ;
size_t const noiseSize = MIN ( ( cSize / 3 ) , randomNoiseSize ) ;
size_t const noiseStart = FUZ_rand ( & lseed ) % ( srcBufferSize - noiseSize ) ;
size_t const cStart = FUZ_rand ( & lseed ) % ( cSize - noiseSize ) ;
memcpy ( cBuffer + cStart , srcBuffer + noiseStart , noiseSize ) ;
} }
/* try decompression on noisy data */
2017-06-21 15:53:42 -07:00
CHECK_Z ( ZSTD_initDStream ( zd_noise ) ) ; /* note : no dictionary */
2017-01-19 12:12:50 -08:00
{ ZSTD_inBuffer inBuff = { cBuffer , cSize , 0 } ;
ZSTD_outBuffer outBuff = { dstBuffer , dstBufferSize , 0 } ;
while ( outBuff . pos < dstBufferSize ) {
size_t const randomCSrcSize = FUZ_randomLength ( & lseed , maxSampleLog ) ;
size_t const randomDstSize = FUZ_randomLength ( & lseed , maxSampleLog ) ;
size_t const adjustedDstSize = MIN ( dstBufferSize - outBuff . pos , randomDstSize ) ;
2017-01-27 15:42:36 -08:00
size_t const adjustedCSrcSize = MIN ( cSize - inBuff . pos , randomCSrcSize ) ;
2017-01-19 12:12:50 -08:00
outBuff . size = outBuff . pos + adjustedDstSize ;
2017-01-27 15:42:36 -08:00
inBuff . size = inBuff . pos + adjustedCSrcSize ;
2017-01-19 12:12:50 -08:00
{ size_t const decompressError = ZSTD_decompressStream ( zd , & outBuff , & inBuff ) ;
if ( ZSTD_isError ( decompressError ) ) break ; /* error correctly detected */
2017-01-27 15:42:36 -08:00
/* No forward progress possible */
if ( outBuff . pos < outBuff . size & & inBuff . pos = = cSize ) break ;
2017-01-19 12:12:50 -08:00
} } } }
DISPLAY ( " \r %u fuzzer tests completed \n " , testNb ) ;
_cleanup :
ZSTDMT_freeCCtx ( zc ) ;
ZSTD_freeDStream ( zd ) ;
ZSTD_freeDStream ( zd_noise ) ;
free ( cNoiseBuffer [ 0 ] ) ;
free ( cNoiseBuffer [ 1 ] ) ;
free ( cNoiseBuffer [ 2 ] ) ;
free ( cNoiseBuffer [ 3 ] ) ;
free ( cNoiseBuffer [ 4 ] ) ;
free ( copyBuffer ) ;
free ( cBuffer ) ;
free ( dstBuffer ) ;
return result ;
_output_error :
result = 1 ;
goto _cleanup ;
}
2017-08-21 12:41:19 -07:00
/** If useOpaqueAPI, sets param in cctxParams.
* Otherwise , sets the param in zc . */
static size_t setCCtxParameter ( ZSTD_CCtx * zc , ZSTD_CCtx_params * cctxParams ,
ZSTD_cParameter param , unsigned value ,
U32 useOpaqueAPI )
{
if ( useOpaqueAPI ) {
return ZSTD_CCtxParam_setParameter ( cctxParams , param , value ) ;
} else {
return ZSTD_CCtx_setParameter ( zc , param , value ) ;
}
}
2017-01-19 12:12:50 -08:00
2017-06-19 11:53:01 -07:00
/* Tests for ZSTD_compress_generic() API */
2017-08-21 12:41:19 -07:00
static int fuzzerTests_newAPI ( U32 seed , U32 nbTests , unsigned startTest , double compressibility , int bigTests , U32 const useOpaqueAPI )
2017-06-16 17:56:41 -07:00
{
2017-06-21 23:35:58 -07:00
U32 const maxSrcLog = bigTests ? 24 : 22 ;
2017-06-16 17:56:41 -07:00
static const U32 maxSampleLog = 19 ;
size_t const srcBufferSize = ( size_t ) 1 < < maxSrcLog ;
BYTE * cNoiseBuffer [ 5 ] ;
size_t const copyBufferSize = srcBufferSize + ( 1 < < maxSampleLog ) ;
BYTE * const copyBuffer = ( BYTE * ) malloc ( copyBufferSize ) ;
size_t const cBufferSize = ZSTD_compressBound ( srcBufferSize ) ;
BYTE * const cBuffer = ( BYTE * ) malloc ( cBufferSize ) ;
size_t const dstBufferSize = srcBufferSize ;
BYTE * const dstBuffer = ( BYTE * ) malloc ( dstBufferSize ) ;
U32 result = 0 ;
U32 testNb = 0 ;
U32 coreSeed = seed ;
ZSTD_CCtx * zc = ZSTD_createCCtx ( ) ; /* will be reset sometimes */
ZSTD_DStream * zd = ZSTD_createDStream ( ) ; /* will be reset sometimes */
ZSTD_DStream * const zd_noise = ZSTD_createDStream ( ) ;
2017-11-29 19:11:12 -08:00
UTIL_time_t const startClock = UTIL_getTime ( ) ;
2017-06-19 11:53:01 -07:00
const BYTE * dict = NULL ; /* can keep same dict on 2 consecutive tests */
2017-06-16 17:56:41 -07:00
size_t dictSize = 0 ;
U32 oldTestLog = 0 ;
2017-09-27 18:00:15 -07:00
U32 windowLogMalus = 0 ; /* can survive between 2 loops */
U32 const cLevelMax = bigTests ? ( U32 ) ZSTD_maxCLevel ( ) - 1 : g_cLevelMax_smallTests ;
U32 const nbThreadsMax = bigTests ? 4 : 2 ;
2017-08-20 22:55:07 -07:00
ZSTD_CCtx_params * cctxParams = ZSTD_createCCtxParams ( ) ;
2017-06-16 17:56:41 -07:00
/* allocations */
cNoiseBuffer [ 0 ] = ( BYTE * ) malloc ( srcBufferSize ) ;
cNoiseBuffer [ 1 ] = ( BYTE * ) malloc ( srcBufferSize ) ;
cNoiseBuffer [ 2 ] = ( BYTE * ) malloc ( srcBufferSize ) ;
cNoiseBuffer [ 3 ] = ( BYTE * ) malloc ( srcBufferSize ) ;
cNoiseBuffer [ 4 ] = ( BYTE * ) malloc ( srcBufferSize ) ;
CHECK ( ! cNoiseBuffer [ 0 ] | | ! cNoiseBuffer [ 1 ] | | ! cNoiseBuffer [ 2 ] | | ! cNoiseBuffer [ 3 ] | | ! cNoiseBuffer [ 4 ] | |
! copyBuffer | | ! dstBuffer | | ! cBuffer | | ! zc | | ! zd | | ! zd_noise ,
" Not enough memory, fuzzer tests cancelled " ) ;
/* Create initial samples */
RDG_genBuffer ( cNoiseBuffer [ 0 ] , srcBufferSize , 0.00 , 0. , coreSeed ) ; /* pure noise */
RDG_genBuffer ( cNoiseBuffer [ 1 ] , srcBufferSize , 0.05 , 0. , coreSeed ) ; /* barely compressible */
RDG_genBuffer ( cNoiseBuffer [ 2 ] , srcBufferSize , compressibility , 0. , coreSeed ) ;
RDG_genBuffer ( cNoiseBuffer [ 3 ] , srcBufferSize , 0.95 , 0. , coreSeed ) ; /* highly compressible */
RDG_genBuffer ( cNoiseBuffer [ 4 ] , srcBufferSize , 1.00 , 0. , coreSeed ) ; /* sparse content */
memset ( copyBuffer , 0x65 , copyBufferSize ) ; /* make copyBuffer considered initialized */
2017-06-21 15:53:42 -07:00
CHECK_Z ( ZSTD_initDStream_usingDict ( zd , NULL , 0 ) ) ; /* ensure at least one init */
2017-06-16 17:56:41 -07:00
/* catch up testNb */
for ( testNb = 1 ; testNb < startTest ; testNb + + )
FUZ_rand ( & coreSeed ) ;
/* test loop */
2017-11-29 19:11:12 -08:00
for ( ; ( testNb < = nbTests ) | | ( UTIL_clockSpanMicro ( startClock ) < g_clockTime ) ; testNb + + ) {
2017-06-16 17:56:41 -07:00
U32 lseed ;
const BYTE * srcBuffer ;
size_t totalTestSize , totalGenSize , cSize ;
XXH64_state_t xxhState ;
U64 crcOrig ;
U32 resetAllowed = 1 ;
size_t maxTestSize ;
/* init */
if ( nbTests > = testNb ) { DISPLAYUPDATE ( 2 , " \r %6u/%6u " , testNb , nbTests ) ; }
else { DISPLAYUPDATE ( 2 , " \r %6u " , testNb ) ; }
FUZ_rand ( & coreSeed ) ;
lseed = coreSeed ^ prime32 ;
2017-09-28 01:25:40 -07:00
DISPLAYLEVEL ( 5 , " *** Test %u *** \n " , testNb ) ;
2017-06-16 17:56:41 -07:00
/* states full reset (deliberately not synchronized) */
/* some issues can only happen when reusing states */
if ( ( FUZ_rand ( & lseed ) & 0xFF ) = = 131 ) {
DISPLAYLEVEL ( 5 , " Creating new context \n " ) ;
ZSTD_freeCCtx ( zc ) ;
zc = ZSTD_createCCtx ( ) ;
2017-06-21 15:53:42 -07:00
CHECK ( zc = = NULL , " ZSTD_createCCtx allocation error " ) ;
2017-06-16 17:56:41 -07:00
resetAllowed = 0 ;
}
if ( ( FUZ_rand ( & lseed ) & 0xFF ) = = 132 ) {
ZSTD_freeDStream ( zd ) ;
zd = ZSTD_createDStream ( ) ;
2017-06-21 15:53:42 -07:00
CHECK ( zd = = NULL , " ZSTD_createDStream allocation error " ) ;
2017-06-16 17:56:41 -07:00
ZSTD_initDStream_usingDict ( zd , NULL , 0 ) ; /* ensure at least one init */
}
/* srcBuffer selection [0-4] */
{ U32 buffNb = FUZ_rand ( & lseed ) & 0x7F ;
if ( buffNb & 7 ) buffNb = 2 ; /* most common : compressible (P) */
else {
buffNb > > = 3 ;
if ( buffNb & 7 ) {
const U32 tnb [ 2 ] = { 1 , 3 } ; /* barely/highly compressible */
buffNb = tnb [ buffNb > > 3 ] ;
} else {
const U32 tnb [ 2 ] = { 0 , 4 } ; /* not compressible / sparse */
buffNb = tnb [ buffNb > > 3 ] ;
} }
srcBuffer = cNoiseBuffer [ buffNb ] ;
}
/* compression init */
2017-06-27 15:49:12 -07:00
CHECK_Z ( ZSTD_CCtx_loadDictionary ( zc , NULL , 0 ) ) ; /* cancel previous dict /*/
2017-06-16 17:56:41 -07:00
if ( ( FUZ_rand ( & lseed ) & 1 ) /* at beginning, to keep same nb of rand */
& & oldTestLog /* at least one test happened */ & & resetAllowed ) {
maxTestSize = FUZ_randomLength ( & lseed , oldTestLog + 2 ) ;
if ( maxTestSize > = srcBufferSize ) maxTestSize = srcBufferSize - 1 ;
{ int const compressionLevel = ( FUZ_rand ( & lseed ) % 5 ) + 1 ;
2017-08-21 12:41:19 -07:00
CHECK_Z ( setCCtxParameter ( zc , cctxParams , ZSTD_p_compressionLevel , compressionLevel , useOpaqueAPI ) ) ;
2017-06-16 17:56:41 -07:00
}
} else {
U32 const testLog = FUZ_rand ( & lseed ) % maxSrcLog ;
U32 const dictLog = FUZ_rand ( & lseed ) % maxSrcLog ;
2017-06-21 17:57:14 -07:00
U32 const cLevelCandidate = ( FUZ_rand ( & lseed ) %
2017-06-16 17:56:41 -07:00
( ZSTD_maxCLevel ( ) -
2017-09-28 01:42:06 -07:00
( MAX ( testLog , dictLog ) / 2 ) ) ) +
2017-06-16 17:56:41 -07:00
1 ;
2017-06-21 17:57:14 -07:00
U32 const cLevel = MIN ( cLevelCandidate , cLevelMax ) ;
2017-09-28 01:25:40 -07:00
DISPLAYLEVEL ( 5 , " t%u: cLevel : %u \n " , testNb , cLevel ) ;
2017-06-16 17:56:41 -07:00
maxTestSize = FUZ_rLogLength ( & lseed , testLog ) ;
2017-09-28 01:25:40 -07:00
DISPLAYLEVEL ( 5 , " t%u: maxTestSize : %u \n " , testNb , ( U32 ) maxTestSize ) ;
2017-06-16 17:56:41 -07:00
oldTestLog = testLog ;
/* random dictionary selection */
dictSize = ( ( FUZ_rand ( & lseed ) & 63 ) = = 1 ) ? FUZ_rLogLength ( & lseed , dictLog ) : 0 ;
{ size_t const dictStart = FUZ_rand ( & lseed ) % ( srcBufferSize - dictSize ) ;
dict = srcBuffer + dictStart ;
2017-06-19 11:53:01 -07:00
if ( ! dictSize ) dict = NULL ;
2017-06-16 17:56:41 -07:00
}
{ U64 const pledgedSrcSize = ( FUZ_rand ( & lseed ) & 3 ) ? ZSTD_CONTENTSIZE_UNKNOWN : maxTestSize ;
ZSTD_compressionParameters cParams = ZSTD_getCParams ( cLevel , pledgedSrcSize , dictSize ) ;
2017-09-28 11:48:45 -07:00
static const U32 windowLogMax = 24 ;
2017-06-16 17:56:41 -07:00
/* mess with compression parameters */
cParams . windowLog + = ( FUZ_rand ( & lseed ) & 3 ) - 1 ;
2017-09-22 14:04:39 -07:00
cParams . windowLog = MIN ( windowLogMax , cParams . windowLog ) ;
2017-06-16 17:56:41 -07:00
cParams . hashLog + = ( FUZ_rand ( & lseed ) & 3 ) - 1 ;
cParams . chainLog + = ( FUZ_rand ( & lseed ) & 3 ) - 1 ;
cParams . searchLog + = ( FUZ_rand ( & lseed ) & 3 ) - 1 ;
cParams . searchLength + = ( FUZ_rand ( & lseed ) & 3 ) - 1 ;
2017-09-27 18:00:15 -07:00
cParams . targetLength = ( U32 ) ( ( cParams . targetLength + 1 ) * ( 0.5 + ( ( double ) ( FUZ_rand ( & lseed ) & 127 ) / 128 ) ) ) ;
2017-06-16 17:56:41 -07:00
cParams = ZSTD_adjustCParams ( cParams , 0 , 0 ) ;
2017-09-27 18:00:15 -07:00
if ( FUZ_rand ( & lseed ) & 1 ) {
2017-11-29 16:42:20 -08:00
DISPLAYLEVEL ( 5 , " t%u: windowLog : %u \n " , testNb , cParams . windowLog ) ;
2017-09-27 18:00:15 -07:00
CHECK_Z ( setCCtxParameter ( zc , cctxParams , ZSTD_p_windowLog , cParams . windowLog , useOpaqueAPI ) ) ;
assert ( cParams . windowLog > = ZSTD_WINDOWLOG_MIN ) ; /* guaranteed by ZSTD_adjustCParams() */
windowLogMalus = ( cParams . windowLog - ZSTD_WINDOWLOG_MIN ) / 5 ;
2017-09-28 01:25:40 -07:00
}
if ( FUZ_rand ( & lseed ) & 1 ) {
DISPLAYLEVEL ( 5 , " t%u: hashLog : %u \n " , testNb , cParams . hashLog ) ;
2017-11-29 16:42:20 -08:00
CHECK_Z ( setCCtxParameter ( zc , cctxParams , ZSTD_p_hashLog , cParams . hashLog , useOpaqueAPI ) ) ;
2017-09-28 01:25:40 -07:00
}
if ( FUZ_rand ( & lseed ) & 1 ) {
DISPLAYLEVEL ( 5 , " t%u: chainLog : %u \n " , testNb , cParams . chainLog ) ;
2017-11-29 16:42:20 -08:00
CHECK_Z ( setCCtxParameter ( zc , cctxParams , ZSTD_p_chainLog , cParams . chainLog , useOpaqueAPI ) ) ;
2017-09-27 18:00:15 -07:00
}
2017-08-21 12:41:19 -07:00
if ( FUZ_rand ( & lseed ) & 1 ) CHECK_Z ( setCCtxParameter ( zc , cctxParams , ZSTD_p_searchLog , cParams . searchLog , useOpaqueAPI ) ) ;
if ( FUZ_rand ( & lseed ) & 1 ) CHECK_Z ( setCCtxParameter ( zc , cctxParams , ZSTD_p_minMatch , cParams . searchLength , useOpaqueAPI ) ) ;
if ( FUZ_rand ( & lseed ) & 1 ) CHECK_Z ( setCCtxParameter ( zc , cctxParams , ZSTD_p_targetLength , cParams . targetLength , useOpaqueAPI ) ) ;
2017-06-16 17:56:41 -07:00
2017-09-06 08:39:46 -07:00
/* mess with long distance matching parameters */
2017-11-29 16:42:20 -08:00
if ( bigTests ) {
if ( FUZ_rand ( & lseed ) & 1 ) CHECK_Z ( setCCtxParameter ( zc , cctxParams , ZSTD_p_enableLongDistanceMatching , FUZ_rand ( & lseed ) & 63 , useOpaqueAPI ) ) ;
if ( FUZ_rand ( & lseed ) & 3 ) CHECK_Z ( setCCtxParameter ( zc , cctxParams , ZSTD_p_ldmHashLog , FUZ_randomClampedLength ( & lseed , ZSTD_HASHLOG_MIN , 23 ) , useOpaqueAPI ) ) ;
if ( FUZ_rand ( & lseed ) & 3 ) CHECK_Z ( setCCtxParameter ( zc , cctxParams , ZSTD_p_ldmMinMatch , FUZ_randomClampedLength ( & lseed , ZSTD_LDM_MINMATCH_MIN , ZSTD_LDM_MINMATCH_MAX ) , useOpaqueAPI ) ) ;
if ( FUZ_rand ( & lseed ) & 3 ) CHECK_Z ( setCCtxParameter ( zc , cctxParams , ZSTD_p_ldmBucketSizeLog , FUZ_randomClampedLength ( & lseed , 0 , ZSTD_LDM_BUCKETSIZELOG_MAX ) , useOpaqueAPI ) ) ;
if ( FUZ_rand ( & lseed ) & 3 ) CHECK_Z ( setCCtxParameter ( zc , cctxParams , ZSTD_p_ldmHashEveryLog , FUZ_randomClampedLength ( & lseed , 0 , ZSTD_WINDOWLOG_MAX - ZSTD_HASHLOG_MIN ) , useOpaqueAPI ) ) ;
}
2017-07-28 15:51:33 -07:00
2017-06-16 17:56:41 -07:00
/* mess with frame parameters */
2017-08-21 12:41:19 -07:00
if ( FUZ_rand ( & lseed ) & 1 ) CHECK_Z ( setCCtxParameter ( zc , cctxParams , ZSTD_p_checksumFlag , FUZ_rand ( & lseed ) & 1 , useOpaqueAPI ) ) ;
if ( FUZ_rand ( & lseed ) & 1 ) CHECK_Z ( setCCtxParameter ( zc , cctxParams , ZSTD_p_dictIDFlag , FUZ_rand ( & lseed ) & 1 , useOpaqueAPI ) ) ;
if ( FUZ_rand ( & lseed ) & 1 ) CHECK_Z ( setCCtxParameter ( zc , cctxParams , ZSTD_p_contentSizeFlag , FUZ_rand ( & lseed ) & 1 , useOpaqueAPI ) ) ;
2017-11-29 16:42:20 -08:00
if ( FUZ_rand ( & lseed ) & 1 ) {
DISPLAYLEVEL ( 5 , " t%u: pledgedSrcSize : %u \n " , testNb , ( U32 ) pledgedSrcSize ) ;
CHECK_Z ( ZSTD_CCtx_setPledgedSrcSize ( zc , pledgedSrcSize ) ) ;
}
2017-06-16 17:56:41 -07:00
/* multi-threading parameters */
2017-06-21 17:57:14 -07:00
{ U32 const nbThreadsCandidate = ( FUZ_rand ( & lseed ) & 4 ) + 1 ;
2017-09-27 18:00:15 -07:00
U32 const nbThreadsAdjusted = ( windowLogMalus < nbThreadsCandidate ) ? nbThreadsCandidate - windowLogMalus : 1 ;
U32 const nbThreads = MIN ( nbThreadsAdjusted , nbThreadsMax ) ;
2017-09-28 01:25:40 -07:00
DISPLAYLEVEL ( 5 , " t%u: nbThreads : %u \n " , testNb , nbThreads ) ;
2017-11-29 16:42:20 -08:00
CHECK_Z ( setCCtxParameter ( zc , cctxParams , ZSTD_p_nbThreads , nbThreads , useOpaqueAPI ) ) ;
2017-06-16 17:56:41 -07:00
if ( nbThreads > 1 ) {
2017-06-19 11:07:33 -07:00
U32 const jobLog = FUZ_rand ( & lseed ) % ( testLog + 1 ) ;
2017-08-21 12:41:19 -07:00
CHECK_Z ( setCCtxParameter ( zc , cctxParams , ZSTD_p_overlapSizeLog , FUZ_rand ( & lseed ) % 10 , useOpaqueAPI ) ) ;
CHECK_Z ( setCCtxParameter ( zc , cctxParams , ZSTD_p_jobSize , ( U32 ) FUZ_rLogLength ( & lseed , jobLog ) , useOpaqueAPI ) ) ;
2017-08-20 22:55:07 -07:00
}
}
2017-11-29 16:42:20 -08:00
if ( FUZ_rand ( & lseed ) & 1 ) CHECK_Z ( setCCtxParameter ( zc , cctxParams , ZSTD_p_forceMaxWindow , FUZ_rand ( & lseed ) & 1 , useOpaqueAPI ) ) ;
2017-08-20 22:55:07 -07:00
/* Apply parameters */
2017-08-21 12:41:19 -07:00
if ( useOpaqueAPI ) {
2017-11-29 16:42:20 -08:00
DISPLAYLEVEL ( 6 , " t%u: applying CCtxParams \n " , testNb ) ;
2017-08-29 18:03:06 -07:00
CHECK_Z ( ZSTD_CCtx_setParametersUsingCCtxParams ( zc , cctxParams ) ) ;
2017-08-21 12:41:19 -07:00
}
2017-08-20 22:55:07 -07:00
if ( FUZ_rand ( & lseed ) & 1 ) {
2017-08-25 10:48:07 -07:00
if ( FUZ_rand ( & lseed ) & 1 ) {
CHECK_Z ( ZSTD_CCtx_loadDictionary ( zc , dict , dictSize ) ) ;
} else {
CHECK_Z ( ZSTD_CCtx_loadDictionary_byReference ( zc , dict , dictSize ) ) ;
}
2017-08-20 22:55:07 -07:00
if ( dict & & dictSize ) {
/* test that compression parameters are rejected (correctly) after loading a non-NULL dictionary */
2017-08-21 12:41:19 -07:00
if ( useOpaqueAPI ) {
2017-08-29 18:03:06 -07:00
size_t const setError = ZSTD_CCtx_setParametersUsingCCtxParams ( zc , cctxParams ) ;
CHECK ( ! ZSTD_isError ( setError ) , " ZSTD_CCtx_setParametersUsingCCtxParams should have failed " ) ;
2017-08-21 12:41:19 -07:00
} else {
size_t const setError = ZSTD_CCtx_setParameter ( zc , ZSTD_p_windowLog , cParams . windowLog - 1 ) ;
CHECK ( ! ZSTD_isError ( setError ) , " ZSTD_CCtx_setParameter should have failed " ) ;
}
}
} else {
2017-08-20 22:55:07 -07:00
CHECK_Z ( ZSTD_CCtx_refPrefix ( zc , dict , dictSize ) ) ;
}
} }
2017-06-16 17:56:41 -07:00
/* multi-segments compression test */
XXH64_reset ( & xxhState , 0 ) ;
{ ZSTD_outBuffer outBuff = { cBuffer , cBufferSize , 0 } ;
2017-07-11 17:18:26 -07:00
for ( cSize = 0 , totalTestSize = 0 ; ( totalTestSize < maxTestSize ) ; ) {
2017-06-16 17:56:41 -07:00
/* compress random chunks into randomly sized dst buffers */
2017-06-19 11:07:33 -07:00
size_t const randomSrcSize = FUZ_randomLength ( & lseed , maxSampleLog ) ;
size_t const srcSize = MIN ( maxTestSize - totalTestSize , randomSrcSize ) ;
size_t const srcStart = FUZ_rand ( & lseed ) % ( srcBufferSize - srcSize ) ;
2017-07-11 17:18:26 -07:00
size_t const randomDstSize = FUZ_randomLength ( & lseed , maxSampleLog + 1 ) ;
2017-06-19 11:07:33 -07:00
size_t const dstBuffSize = MIN ( cBufferSize - cSize , randomDstSize ) ;
ZSTD_EndDirective const flush = ( FUZ_rand ( & lseed ) & 15 ) ? ZSTD_e_continue : ZSTD_e_flush ;
ZSTD_inBuffer inBuff = { srcBuffer + srcStart , srcSize , 0 } ;
outBuff . size = outBuff . pos + dstBuffSize ;
CHECK_Z ( ZSTD_compress_generic ( zc , & outBuff , & inBuff , flush ) ) ;
2017-11-29 16:42:20 -08:00
DISPLAYLEVEL ( 6 , " t%u: compress consumed %u bytes (total : %u) \n " ,
testNb , ( U32 ) inBuff . pos , ( U32 ) ( totalTestSize + inBuff . pos ) ) ;
2017-06-19 11:07:33 -07:00
XXH64_update ( & xxhState , srcBuffer + srcStart , inBuff . pos ) ;
memcpy ( copyBuffer + totalTestSize , srcBuffer + srcStart , inBuff . pos ) ;
totalTestSize + = inBuff . pos ;
}
2017-06-16 17:56:41 -07:00
/* final frame epilogue */
{ size_t remainingToFlush = ( size_t ) ( - 1 ) ;
while ( remainingToFlush ) {
ZSTD_inBuffer inBuff = { NULL , 0 , 0 } ;
2017-07-11 17:18:26 -07:00
size_t const randomDstSize = FUZ_randomLength ( & lseed , maxSampleLog + 1 ) ;
2017-06-16 17:56:41 -07:00
size_t const adjustedDstSize = MIN ( cBufferSize - cSize , randomDstSize ) ;
outBuff . size = outBuff . pos + adjustedDstSize ;
2017-09-28 02:14:48 -07:00
DISPLAYLEVEL ( 6 , " End-flush into dst buffer of size %u \n " , ( U32 ) adjustedDstSize ) ;
2017-06-16 17:56:41 -07:00
remainingToFlush = ZSTD_compress_generic ( zc , & outBuff , & inBuff , ZSTD_e_end ) ;
2017-09-28 02:14:48 -07:00
CHECK ( ZSTD_isError ( remainingToFlush ) ,
" ZSTD_compress_generic w/ ZSTD_e_end error : %s " ,
ZSTD_getErrorName ( remainingToFlush ) ) ;
2017-06-16 17:56:41 -07:00
} }
crcOrig = XXH64_digest ( & xxhState ) ;
cSize = outBuff . pos ;
DISPLAYLEVEL ( 5 , " Frame completed : %u bytes \n " , ( U32 ) cSize ) ;
}
/* multi - fragments decompression test */
if ( ! dictSize /* don't reset if dictionary : could be different */ & & ( FUZ_rand ( & lseed ) & 1 ) ) {
2017-06-28 11:09:43 -07:00
DISPLAYLEVEL ( 5 , " resetting DCtx (dict:%08X) \n " , ( U32 ) ( size_t ) dict ) ;
2017-06-21 15:53:42 -07:00
CHECK_Z ( ZSTD_resetDStream ( zd ) ) ;
2017-06-16 17:56:41 -07:00
} else {
2017-06-28 11:09:43 -07:00
DISPLAYLEVEL ( 5 , " using dict of size %u \n " , ( U32 ) dictSize ) ;
2017-06-21 15:53:42 -07:00
CHECK_Z ( ZSTD_initDStream_usingDict ( zd , dict , dictSize ) ) ;
2017-06-16 17:56:41 -07:00
}
{ size_t decompressionResult = 1 ;
ZSTD_inBuffer inBuff = { cBuffer , cSize , 0 } ;
ZSTD_outBuffer outBuff = { dstBuffer , dstBufferSize , 0 } ;
for ( totalGenSize = 0 ; decompressionResult ; ) {
size_t const readCSrcSize = FUZ_randomLength ( & lseed , maxSampleLog ) ;
size_t const randomDstSize = FUZ_randomLength ( & lseed , maxSampleLog ) ;
size_t const dstBuffSize = MIN ( dstBufferSize - totalGenSize , randomDstSize ) ;
inBuff . size = inBuff . pos + readCSrcSize ;
2017-09-27 01:01:11 -07:00
outBuff . size = outBuff . pos + dstBuffSize ;
2017-09-28 02:14:48 -07:00
DISPLAYLEVEL ( 6 , " ZSTD_decompressStream input %u bytes (pos:%u/%u) \n " ,
2017-06-28 11:09:43 -07:00
( U32 ) readCSrcSize , ( U32 ) inBuff . pos , ( U32 ) cSize ) ;
2017-06-16 17:56:41 -07:00
decompressionResult = ZSTD_decompressStream ( zd , & outBuff , & inBuff ) ;
CHECK ( ZSTD_isError ( decompressionResult ) , " decompression error : %s " , ZSTD_getErrorName ( decompressionResult ) ) ;
2017-09-28 02:14:48 -07:00
DISPLAYLEVEL ( 6 , " inBuff.pos = %u \n " , ( U32 ) readCSrcSize ) ;
2017-06-16 17:56:41 -07:00
}
CHECK ( outBuff . pos ! = totalTestSize , " decompressed data : wrong size (%u != %u) " , ( U32 ) outBuff . pos , ( U32 ) totalTestSize ) ;
CHECK ( inBuff . pos ! = cSize , " compressed data should be fully read (%u != %u) " , ( U32 ) inBuff . pos , ( U32 ) cSize ) ;
{ U64 const crcDest = XXH64 ( dstBuffer , totalTestSize , 0 ) ;
if ( crcDest ! = crcOrig ) findDiff ( copyBuffer , dstBuffer , totalTestSize ) ;
CHECK ( crcDest ! = crcOrig , " decompressed data corrupted " ) ;
} }
/*===== noisy/erroneous src decompression test =====*/
/* add some noise */
{ U32 const nbNoiseChunks = ( FUZ_rand ( & lseed ) & 7 ) + 2 ;
U32 nn ; for ( nn = 0 ; nn < nbNoiseChunks ; nn + + ) {
size_t const randomNoiseSize = FUZ_randomLength ( & lseed , maxSampleLog ) ;
size_t const noiseSize = MIN ( ( cSize / 3 ) , randomNoiseSize ) ;
size_t const noiseStart = FUZ_rand ( & lseed ) % ( srcBufferSize - noiseSize ) ;
size_t const cStart = FUZ_rand ( & lseed ) % ( cSize - noiseSize ) ;
memcpy ( cBuffer + cStart , srcBuffer + noiseStart , noiseSize ) ;
} }
/* try decompression on noisy data */
2017-06-21 15:53:42 -07:00
CHECK_Z ( ZSTD_initDStream ( zd_noise ) ) ; /* note : no dictionary */
2017-06-16 17:56:41 -07:00
{ ZSTD_inBuffer inBuff = { cBuffer , cSize , 0 } ;
ZSTD_outBuffer outBuff = { dstBuffer , dstBufferSize , 0 } ;
while ( outBuff . pos < dstBufferSize ) {
size_t const randomCSrcSize = FUZ_randomLength ( & lseed , maxSampleLog ) ;
size_t const randomDstSize = FUZ_randomLength ( & lseed , maxSampleLog ) ;
size_t const adjustedDstSize = MIN ( dstBufferSize - outBuff . pos , randomDstSize ) ;
size_t const adjustedCSrcSize = MIN ( cSize - inBuff . pos , randomCSrcSize ) ;
outBuff . size = outBuff . pos + adjustedDstSize ;
inBuff . size = inBuff . pos + adjustedCSrcSize ;
{ size_t const decompressError = ZSTD_decompressStream ( zd , & outBuff , & inBuff ) ;
if ( ZSTD_isError ( decompressError ) ) break ; /* error correctly detected */
2017-06-19 11:07:33 -07:00
/* Good so far, but no more progress possible */
2017-06-16 17:56:41 -07:00
if ( outBuff . pos < outBuff . size & & inBuff . pos = = cSize ) break ;
} } } }
2017-06-18 23:25:15 -07:00
DISPLAY ( " \r %u fuzzer tests completed \n " , testNb - 1 ) ;
2017-06-16 17:56:41 -07:00
_cleanup :
ZSTD_freeCCtx ( zc ) ;
ZSTD_freeDStream ( zd ) ;
ZSTD_freeDStream ( zd_noise ) ;
2017-08-20 22:55:07 -07:00
ZSTD_freeCCtxParams ( cctxParams ) ;
2017-06-16 17:56:41 -07:00
free ( cNoiseBuffer [ 0 ] ) ;
free ( cNoiseBuffer [ 1 ] ) ;
free ( cNoiseBuffer [ 2 ] ) ;
free ( cNoiseBuffer [ 3 ] ) ;
free ( cNoiseBuffer [ 4 ] ) ;
free ( copyBuffer ) ;
free ( cBuffer ) ;
free ( dstBuffer ) ;
return result ;
_output_error :
result = 1 ;
goto _cleanup ;
}
2016-08-12 07:48:02 -07:00
/*-*******************************************************
* Command line
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
int FUZ_usage ( const char * programName )
{
DISPLAY ( " Usage : \n " ) ;
DISPLAY ( " %s [args] \n " , programName ) ;
DISPLAY ( " \n " ) ;
DISPLAY ( " Arguments : \n " ) ;
DISPLAY ( " -i# : Nb of tests (default:%u) \n " , nbTestsDefault ) ;
DISPLAY ( " -s# : Select seed (default:prompt user) \n " ) ;
DISPLAY ( " -t# : Select starting test number (default:0) \n " ) ;
DISPLAY ( " -P# : Select compressibility in %% (default:%i%%) \n " , FUZ_COMPRESSIBILITY_DEFAULT ) ;
DISPLAY ( " -v : verbose \n " ) ;
DISPLAY ( " -p : pause at the end \n " ) ;
DISPLAY ( " -h : display help and exit \n " ) ;
return 0 ;
}
2017-06-16 17:56:41 -07:00
typedef enum { simple_api , mt_api , advanced_api } e_api ;
2016-08-12 07:48:02 -07:00
int main ( int argc , const char * * argv )
{
2017-11-27 12:15:23 -08:00
U32 seed = 0 ;
int seedset = 0 ;
2016-08-12 07:48:02 -07:00
int nbTests = nbTestsDefault ;
int testNb = 0 ;
int proba = FUZ_COMPRESSIBILITY_DEFAULT ;
2017-11-27 12:15:23 -08:00
int result = 0 ;
2017-01-19 15:32:07 -08:00
int mainPause = 0 ;
2017-06-29 18:19:09 -07:00
int bigTests = ( sizeof ( size_t ) = = 8 ) ;
2017-06-16 17:56:41 -07:00
e_api selected_api = simple_api ;
2017-01-19 15:32:07 -08:00
const char * const programName = argv [ 0 ] ;
2017-08-21 12:41:19 -07:00
U32 useOpaqueAPI = 0 ;
2017-11-27 12:15:23 -08:00
int argNb ;
2016-08-12 07:48:02 -07:00
/* Check command line */
for ( argNb = 1 ; argNb < argc ; argNb + + ) {
const char * argument = argv [ argNb ] ;
2017-11-27 12:15:23 -08:00
assert ( argument ! = NULL ) ;
2016-08-12 07:48:02 -07:00
/* Parsing commands. Aggregated commands are allowed */
if ( argument [ 0 ] = = ' - ' ) {
2017-09-28 18:27:22 -07:00
if ( ! strcmp ( argument , " --mt " ) ) { selected_api = mt_api ; testNb + = ! testNb ; continue ; }
if ( ! strcmp ( argument , " --newapi " ) ) { selected_api = advanced_api ; testNb + = ! testNb ; continue ; }
if ( ! strcmp ( argument , " --opaqueapi " ) ) { selected_api = advanced_api ; testNb + = ! testNb ; useOpaqueAPI = 1 ; continue ; }
2017-03-20 11:25:00 -07:00
if ( ! strcmp ( argument , " --no-big-tests " ) ) { bigTests = 0 ; continue ; }
2017-01-19 15:32:07 -08:00
argument + + ;
2016-08-12 07:48:02 -07:00
while ( * argument ! = 0 ) {
switch ( * argument )
{
case ' h ' :
return FUZ_usage ( programName ) ;
2017-01-19 12:12:50 -08:00
2016-08-12 07:48:02 -07:00
case ' v ' :
argument + + ;
2017-01-19 12:12:50 -08:00
g_displayLevel + + ;
2016-08-12 07:48:02 -07:00
break ;
2017-01-19 12:12:50 -08:00
2016-08-12 07:48:02 -07:00
case ' q ' :
argument + + ;
g_displayLevel - - ;
break ;
2017-01-19 12:12:50 -08:00
2016-08-12 07:48:02 -07:00
case ' p ' : /* pause at the end */
argument + + ;
mainPause = 1 ;
break ;
2017-01-19 12:12:50 -08:00
case ' i ' : /* limit tests by nb of iterations (default) */
2016-08-12 07:48:02 -07:00
argument + + ;
2016-09-01 16:44:48 -07:00
nbTests = 0 ; g_clockTime = 0 ;
2016-08-12 07:48:02 -07:00
while ( ( * argument > = ' 0 ' ) & & ( * argument < = ' 9 ' ) ) {
nbTests * = 10 ;
nbTests + = * argument - ' 0 ' ;
argument + + ;
}
break ;
2017-01-19 12:12:50 -08:00
case ' T ' : /* limit tests by time */
2016-08-12 07:48:02 -07:00
argument + + ;
2016-09-01 16:44:48 -07:00
nbTests = 0 ; g_clockTime = 0 ;
2016-08-12 07:48:02 -07:00
while ( ( * argument > = ' 0 ' ) & & ( * argument < = ' 9 ' ) ) {
2016-09-01 16:44:48 -07:00
g_clockTime * = 10 ;
g_clockTime + = * argument - ' 0 ' ;
2016-08-12 07:48:02 -07:00
argument + + ;
}
2017-11-27 12:15:23 -08:00
if ( * argument = = ' m ' ) { /* -T1m == -T60 */
g_clockTime * = 60 , argument + + ;
if ( * argument = = ' n ' ) argument + + ; /* -T1mn == -T60 */
} else if ( * argument = = ' s ' ) argument + + ; /* -T10s == -T10 */
2017-11-29 19:11:12 -08:00
g_clockTime * = SEC_TO_MICRO ;
2016-08-12 07:48:02 -07:00
break ;
2017-01-19 12:12:50 -08:00
case ' s ' : /* manually select seed */
2016-08-12 07:48:02 -07:00
argument + + ;
seedset = 1 ;
2017-11-27 12:15:23 -08:00
seed = 0 ;
2016-08-12 07:48:02 -07:00
while ( ( * argument > = ' 0 ' ) & & ( * argument < = ' 9 ' ) ) {
seed * = 10 ;
seed + = * argument - ' 0 ' ;
argument + + ;
}
break ;
2017-01-19 12:12:50 -08:00
case ' t ' : /* select starting test number */
2016-08-12 07:48:02 -07:00
argument + + ;
testNb = 0 ;
while ( ( * argument > = ' 0 ' ) & & ( * argument < = ' 9 ' ) ) {
testNb * = 10 ;
testNb + = * argument - ' 0 ' ;
argument + + ;
}
break ;
case ' P ' : /* compressibility % */
argument + + ;
proba = 0 ;
while ( ( * argument > = ' 0 ' ) & & ( * argument < = ' 9 ' ) ) {
proba * = 10 ;
proba + = * argument - ' 0 ' ;
argument + + ;
}
if ( proba < 0 ) proba = 0 ;
if ( proba > 100 ) proba = 100 ;
break ;
default :
return FUZ_usage ( programName ) ;
}
} } } /* for(argNb=1; argNb<argc; argNb++) */
/* Get Seed */
2016-08-25 10:11:11 -07:00
DISPLAY ( " Starting zstream tester (%i-bits, %s) \n " , ( int ) ( sizeof ( size_t ) * 8 ) , ZSTD_VERSION_STRING ) ;
2016-08-12 07:48:02 -07:00
2016-09-01 16:44:48 -07:00
if ( ! seedset ) {
time_t const t = time ( NULL ) ;
U32 const h = XXH32 ( & t , sizeof ( t ) , 1 ) ;
seed = h % 10000 ;
}
2016-08-12 07:48:02 -07:00
DISPLAY ( " Seed = %u \n " , seed ) ;
if ( proba ! = FUZ_COMPRESSIBILITY_DEFAULT ) DISPLAY ( " Compressibility : %i%% \n " , proba ) ;
if ( nbTests < = 0 ) nbTests = 1 ;
if ( testNb = = 0 ) {
2017-11-27 12:15:23 -08:00
result = basicUnitTests ( 0 , ( ( double ) proba ) / 100 ) ; /* constant seed for predictability */
2017-07-10 17:16:41 -07:00
}
2016-08-12 07:48:02 -07:00
2017-06-16 17:56:41 -07:00
if ( ! result ) {
switch ( selected_api )
{
case simple_api :
result = fuzzerTests ( seed , nbTests , testNb , ( ( double ) proba ) / 100 , bigTests ) ;
break ;
case mt_api :
result = fuzzerTests_MT ( seed , nbTests , testNb , ( ( double ) proba ) / 100 , bigTests ) ;
break ;
case advanced_api :
2017-08-21 12:41:19 -07:00
result = fuzzerTests_newAPI ( seed , nbTests , testNb , ( ( double ) proba ) / 100 , bigTests , useOpaqueAPI ) ;
2017-06-16 17:56:41 -07:00
break ;
default :
assert ( 0 ) ; /* impossible */
}
}
2016-08-12 07:48:02 -07:00
if ( mainPause ) {
int unused ;
DISPLAY ( " Press Enter \n " ) ;
unused = getchar ( ) ;
( void ) unused ;
}
return result ;
}