2013-12-30 17:16:52 +00:00
/*
fuzzer . c - Fuzzer test tool for LZ4
2014-04-28 20:45:35 +00:00
Copyright ( C ) Yann Collet 2012 - 2014
2013-12-30 17:16:52 +00:00
GPL v2 License
This program is free software ; you can redistribute it and / or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation ; either version 2 of the License , or
( at your option ) any later version .
This program is distributed in the hope that it will be useful ,
but WITHOUT ANY WARRANTY ; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
GNU General Public License for more details .
You should have received a copy of the GNU General Public License along
with this program ; if not , write to the Free Software Foundation , Inc . ,
51 Franklin Street , Fifth Floor , Boston , MA 02110 - 1301 USA .
You can contact the author at :
- LZ4 homepage : http : //fastcompression.blogspot.com/p/lz4.html
- LZ4 source repository : http : //code.google.com/p/lz4/
*/
2014-04-28 20:45:35 +00:00
/**************************************
Remove Visual warning messages
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2014-02-04 14:11:10 +00:00
# define _CRT_SECURE_NO_WARNINGS // fgets
2014-07-02 21:03:58 +00:00
# ifdef _MSC_VER /* Visual Studio */
# pragma warning(disable : 4127) /* disable: C4127: conditional expression is constant */
2014-07-05 11:50:05 +00:00
# pragma warning(disable : 4146) /* disable: C4146: minus unsigned expression */
2014-07-02 21:03:58 +00:00
# endif
2013-12-30 17:16:52 +00:00
2014-04-28 20:45:35 +00:00
/**************************************
Includes
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2013-12-30 17:16:52 +00:00
# include <stdlib.h>
# include <stdio.h> // fgets, sscanf
# include <sys/timeb.h> // timeb
2014-04-16 14:25:56 +00:00
# include <string.h> // strcmp
2013-12-30 17:16:52 +00:00
# include "lz4.h"
# include "lz4hc.h"
2014-04-28 20:45:35 +00:00
# include "xxhash.h"
/**************************************
Basic Types
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
# if defined (__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) /* C99 */
# include <stdint.h>
typedef uint8_t BYTE ;
typedef uint16_t U16 ;
typedef uint32_t U32 ;
typedef int32_t S32 ;
typedef uint64_t U64 ;
# else
typedef unsigned char BYTE ;
typedef unsigned short U16 ;
typedef unsigned int U32 ;
typedef signed int S32 ;
typedef unsigned long long U64 ;
# endif
2013-12-30 17:16:52 +00:00
2014-04-28 20:45:35 +00:00
/**************************************
Constants
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2013-12-30 17:16:52 +00:00
# ifndef LZ4_VERSION
2014-07-14 22:04:10 +00:00
# define LZ4_VERSION ""
2013-12-30 17:16:52 +00:00
# endif
2014-04-22 23:54:32 +00:00
# define NB_ATTEMPTS (1<<16)
2014-04-28 20:45:35 +00:00
# define COMPRESSIBLE_NOISE_LENGTH (1 << 21)
# define FUZ_MAX_BLOCK_SIZE (1 << 17)
# define FUZ_MAX_DICT_SIZE (1 << 15)
2014-04-29 22:44:49 +00:00
# define FUZ_COMPRESSIBILITY_DEFAULT 50
2013-12-30 17:16:52 +00:00
# define PRIME1 2654435761U
# define PRIME2 2246822519U
# define PRIME3 3266489917U
2014-07-02 08:38:34 +00:00
# define KB *(1U<<10)
# define MB *(1U<<20)
# define GB *(1U<<30)
2013-12-30 17:16:52 +00:00
2014-08-30 11:32:09 +00:00
/*****************************************
Macros
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2014-04-29 20:39:08 +00:00
# define DISPLAY(...) fprintf(stderr, __VA_ARGS__)
# define DISPLAYLEVEL(l, ...) if (displayLevel>=l) { DISPLAY(__VA_ARGS__); }
2014-06-09 01:42:39 +00:00
/*****************************************
Local Parameters
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2014-04-29 20:39:08 +00:00
static int no_prompt = 0 ;
static char * programName ;
2014-06-09 01:42:39 +00:00
static int displayLevel = 2 ;
2014-04-29 20:39:08 +00:00
2014-04-28 20:45:35 +00:00
/*********************************************************
Fuzzer functions
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2014-07-14 22:29:40 +00:00
static int FUZ_GetMilliStart ( void )
2013-12-30 17:16:52 +00:00
{
struct timeb tb ;
int nCount ;
ftime ( & tb ) ;
nCount = ( int ) ( tb . millitm + ( tb . time & 0xfffff ) * 1000 ) ;
return nCount ;
}
static int FUZ_GetMilliSpan ( int nTimeStart )
{
int nSpan = FUZ_GetMilliStart ( ) - nTimeStart ;
if ( nSpan < 0 )
nSpan + = 0x100000 * 1000 ;
return nSpan ;
}
2014-04-28 22:49:31 +00:00
# define FUZ_rotl32(x,r) ((x << r) | (x >> (32 - r)))
2013-12-30 17:16:52 +00:00
unsigned int FUZ_rand ( unsigned int * src )
{
2014-04-28 22:49:31 +00:00
U32 rand32 = * src ;
rand32 * = PRIME1 ;
rand32 + = PRIME2 ;
rand32 = FUZ_rotl32 ( rand32 , 13 ) ;
* src = rand32 ;
2014-06-22 10:25:04 +00:00
return rand32 > > 3 ;
2013-12-30 17:16:52 +00:00
}
2014-04-28 20:45:35 +00:00
# define FUZ_RAND15BITS ((FUZ_rand(seed) >> 3) & 32767)
2014-08-30 11:32:09 +00:00
# define FUZ_RANDLENGTH ( ((FUZ_rand(seed) >> 7) & 3) ? (FUZ_rand(seed) % 15) : (FUZ_rand(seed) % 510) + 15)
2014-04-28 20:45:35 +00:00
void FUZ_fillCompressibleNoiseBuffer ( void * buffer , int bufferSize , double proba , U32 * seed )
2013-12-30 17:16:52 +00:00
{
2014-04-28 20:45:35 +00:00
BYTE * BBuffer = ( BYTE * ) buffer ;
int pos = 0 ;
U32 P32 = ( U32 ) ( 32768 * proba ) ;
// First Byte
BBuffer [ pos + + ] = ( BYTE ) ( FUZ_rand ( seed ) ) ;
while ( pos < bufferSize )
{
// Select : Literal (noise) or copy (within 64K)
if ( FUZ_RAND15BITS < P32 )
{
// Copy (within 64K)
int ref , d ;
int length = FUZ_RANDLENGTH + 4 ;
int offset = FUZ_RAND15BITS + 1 ;
if ( offset > pos ) offset = pos ;
if ( pos + length > bufferSize ) length = bufferSize - pos ;
ref = pos - offset ;
d = pos + length ;
while ( pos < d ) BBuffer [ pos + + ] = BBuffer [ ref + + ] ;
}
else
{
// Literal (noise)
int d ;
int length = FUZ_RANDLENGTH ;
if ( pos + length > bufferSize ) length = bufferSize - pos ;
d = pos + length ;
while ( pos < d ) BBuffer [ pos + + ] = ( BYTE ) ( FUZ_rand ( seed ) > > 5 ) ;
}
}
2013-12-30 17:16:52 +00:00
}
2014-07-02 17:02:29 +00:00
# define MAX_NB_BUFF_I134 150
2014-07-05 11:50:05 +00:00
# define BLOCKSIZE_I134 (32 MB)
2014-08-30 11:32:09 +00:00
int FUZ_AddressOverflow ( void )
2014-07-02 08:38:34 +00:00
{
char * buffers [ MAX_NB_BUFF_I134 + 1 ] = { 0 } ;
2014-07-05 11:50:05 +00:00
int i , nbBuff = 0 ;
int highAddress = 0 ;
2014-07-02 08:38:34 +00:00
2014-07-05 11:50:05 +00:00
printf ( " Overflow tests : " ) ;
2014-07-02 08:38:34 +00:00
// Only possible in 32-bits
if ( sizeof ( void * ) = = 8 )
{
2014-07-05 11:50:05 +00:00
printf ( " 64 bits mode : no overflow \n " ) ;
fflush ( stdout ) ;
2014-07-02 08:38:34 +00:00
return 0 ;
}
2014-07-05 11:50:05 +00:00
buffers [ 0 ] = ( char * ) malloc ( BLOCKSIZE_I134 ) ;
buffers [ 1 ] = ( char * ) malloc ( BLOCKSIZE_I134 ) ;
if ( ( ! buffers [ 0 ] ) | | ( ! buffers [ 1 ] ) )
2014-07-02 08:38:34 +00:00
{
2014-07-05 11:50:05 +00:00
printf ( " not enough memory for tests \n " ) ;
return 0 ;
}
for ( nbBuff = 2 ; nbBuff < MAX_NB_BUFF_I134 ; nbBuff + + )
{
printf ( " %3i \b \b \b \b " , nbBuff ) ;
2014-07-02 17:02:29 +00:00
buffers [ nbBuff ] = ( char * ) malloc ( BLOCKSIZE_I134 ) ;
2014-07-05 11:50:05 +00:00
//printf("%08X ", (U32)(size_t)(buffers[nbBuff]));
fflush ( stdout ) ;
if ( ( ( size_t ) buffers [ nbBuff ] > ( size_t ) 0x80000000 ) & & ( ! highAddress ) )
2014-07-02 08:38:34 +00:00
{
2014-07-05 11:50:05 +00:00
printf ( " high address detected : " ) ;
fflush ( stdout ) ;
highAddress = 1 ;
2014-07-02 08:38:34 +00:00
}
2014-07-05 11:50:05 +00:00
if ( buffers [ nbBuff ] = = NULL ) goto _endOfTests ;
2014-07-02 08:38:34 +00:00
{
2014-07-02 21:03:58 +00:00
size_t sizeToGenerateOverflow = ( size_t ) ( - ( ( size_t ) buffers [ nbBuff - 1 ] ) + 512 ) ;
2014-07-05 11:50:05 +00:00
int nbOf255 = ( int ) ( ( sizeToGenerateOverflow / 255 ) + 1 ) ;
2014-07-02 08:38:34 +00:00
char * input = buffers [ nbBuff - 1 ] ;
char * output = buffers [ nbBuff ] ;
int r ;
2014-07-02 13:38:16 +00:00
input [ 0 ] = 0xF0 ; // Literal length overflow
input [ 1 ] = 0xFF ;
input [ 2 ] = 0xFF ;
2014-07-02 17:02:29 +00:00
input [ 3 ] = 0xFF ;
2014-07-05 11:50:05 +00:00
for ( i = 4 ; i < = nbOf255 + 4 ; i + + ) input [ i ] = 0xff ;
2014-07-02 17:02:29 +00:00
r = LZ4_decompress_safe ( input , output , nbOf255 + 64 , BLOCKSIZE_I134 ) ;
2014-07-05 11:50:05 +00:00
if ( r > 0 ) goto _overflowError ;
2014-07-02 17:02:29 +00:00
input [ 0 ] = 0x1F ; // Match length overflow
input [ 1 ] = 0x01 ;
input [ 2 ] = 0x01 ;
input [ 3 ] = 0x00 ;
r = LZ4_decompress_safe ( input , output , nbOf255 + 64 , BLOCKSIZE_I134 ) ;
2014-07-05 11:50:05 +00:00
if ( r > 0 ) goto _overflowError ;
output = buffers [ nbBuff - 2 ] ; // Reverse in/out pointer order
input [ 0 ] = 0xF0 ; // Literal length overflow
input [ 1 ] = 0xFF ;
input [ 2 ] = 0xFF ;
input [ 3 ] = 0xFF ;
r = LZ4_decompress_safe ( input , output , nbOf255 + 64 , BLOCKSIZE_I134 ) ;
if ( r > 0 ) goto _overflowError ;
input [ 0 ] = 0x1F ; // Match length overflow
input [ 1 ] = 0x01 ;
input [ 2 ] = 0x01 ;
input [ 3 ] = 0x00 ;
r = LZ4_decompress_safe ( input , output , nbOf255 + 64 , BLOCKSIZE_I134 ) ;
if ( r > 0 ) goto _overflowError ;
2014-07-02 08:38:34 +00:00
}
}
2014-07-05 11:50:05 +00:00
nbBuff + + ;
_endOfTests :
2014-07-02 17:02:29 +00:00
for ( i = 0 ; i < nbBuff ; i + + ) free ( buffers [ i ] ) ;
2014-07-05 11:50:05 +00:00
if ( ! highAddress ) printf ( " high address not possible \n " ) ;
else printf ( " all overflows correctly detected \n " ) ;
2014-07-02 08:38:34 +00:00
return 0 ;
2014-07-05 11:50:05 +00:00
_overflowError :
printf ( " Address space overflow error !! \n " ) ;
exit ( 1 ) ;
2014-07-02 08:38:34 +00:00
}
2014-04-29 20:39:08 +00:00
# define FUZ_MAX(a,b) (a>b?a:b)
2013-12-30 17:16:52 +00:00
2014-05-19 23:40:29 +00:00
int FUZ_test ( U32 seed , int nbCycles , int startCycle , double compressibility ) {
2013-12-30 17:16:52 +00:00
unsigned long long bytes = 0 ;
unsigned long long cbytes = 0 ;
unsigned long long hcbytes = 0 ;
2014-04-28 20:45:35 +00:00
unsigned long long ccbytes = 0 ;
void * CNBuffer ;
char * compressedBuffer ;
char * decodedBuffer ;
2013-12-30 17:16:52 +00:00
# define FUZ_max LZ4_COMPRESSBOUND(LEN)
2014-04-29 22:44:49 +00:00
unsigned int randState = seed ;
2014-05-19 23:40:29 +00:00
int ret , cycleNb ;
2014-04-28 20:45:35 +00:00
# define FUZ_CHECKTEST(cond, ...) if (cond) { printf("Test %i : ", testNb); printf(__VA_ARGS__); \
2014-05-19 23:40:29 +00:00
printf ( " (seed %u, cycle %i) \n " , seed , cycleNb ) ; goto _output_error ; }
2014-06-09 01:42:39 +00:00
# define FUZ_DISPLAYTEST { testNb++; ((displayLevel<3) || no_prompt) ? 0 : printf("%2i\b\b", testNb); if (displayLevel==4) fflush(stdout); }
2013-12-30 17:16:52 +00:00
void * stateLZ4 = malloc ( LZ4_sizeofState ( ) ) ;
void * stateLZ4HC = malloc ( LZ4_sizeofStateHC ( ) ) ;
2014-04-28 20:45:35 +00:00
void * LZ4continue ;
2014-06-09 15:46:03 +00:00
LZ4_stream_t LZ4dict ;
2014-04-28 20:45:35 +00:00
U32 crcOrig , crcCheck ;
2014-06-09 01:42:39 +00:00
int displayRefresh ;
2013-12-30 17:16:52 +00:00
2014-06-21 16:01:15 +00:00
// init
memset ( & LZ4dict , 0 , sizeof ( LZ4dict ) ) ;
2014-04-28 20:45:35 +00:00
// Create compressible test buffer
CNBuffer = malloc ( COMPRESSIBLE_NOISE_LENGTH ) ;
2014-04-29 22:44:49 +00:00
FUZ_fillCompressibleNoiseBuffer ( CNBuffer , COMPRESSIBLE_NOISE_LENGTH , compressibility , & randState ) ;
2014-04-28 20:45:35 +00:00
compressedBuffer = malloc ( LZ4_compressBound ( FUZ_MAX_BLOCK_SIZE ) ) ;
2014-04-29 20:39:08 +00:00
decodedBuffer = malloc ( FUZ_MAX_DICT_SIZE + FUZ_MAX_BLOCK_SIZE ) ;
2013-12-30 17:16:52 +00:00
2014-06-09 01:42:39 +00:00
// display refresh rate
switch ( displayLevel )
{
case 0 : displayRefresh = nbCycles + 1 ; break ;
2014-07-05 11:50:05 +00:00
case 1 : displayRefresh = FUZ_MAX ( 1 , nbCycles / 100 ) ; break ;
case 2 : displayRefresh = 89 ; break ;
2014-06-09 01:42:39 +00:00
default : displayRefresh = 1 ;
}
2014-05-19 23:40:29 +00:00
// move to startCycle
for ( cycleNb = 0 ; cycleNb < startCycle ; cycleNb + + )
{
2014-06-21 16:01:15 +00:00
// synd rand & dict
int dictSize , blockSize , blockStart ;
char * dict ;
char * block ;
blockSize = FUZ_rand ( & randState ) % FUZ_MAX_BLOCK_SIZE ;
blockStart = FUZ_rand ( & randState ) % ( COMPRESSIBLE_NOISE_LENGTH - blockSize ) ;
dictSize = FUZ_rand ( & randState ) % FUZ_MAX_DICT_SIZE ;
if ( dictSize > blockStart ) dictSize = blockStart ;
block = ( ( char * ) CNBuffer ) + blockStart ;
dict = block - dictSize ;
LZ4_loadDict ( & LZ4dict , dict , dictSize ) ;
LZ4_compress_continue ( & LZ4dict , block , compressedBuffer , blockSize ) ;
LZ4_loadDict ( & LZ4dict , dict , dictSize ) ;
LZ4_compress_continue ( & LZ4dict , block , compressedBuffer , blockSize ) ;
LZ4_loadDict ( & LZ4dict , dict , dictSize ) ;
LZ4_compress_continue ( & LZ4dict , block , compressedBuffer , blockSize ) ;
2014-05-19 23:40:29 +00:00
}
2014-04-28 20:45:35 +00:00
// Test loop
2014-05-19 23:40:29 +00:00
for ( cycleNb = startCycle ; cycleNb < nbCycles ; cycleNb + + )
2013-12-30 17:16:52 +00:00
{
int testNb = 0 ;
2014-04-28 20:45:35 +00:00
char * dict ;
char * block ;
int dictSize , blockSize , blockStart , compressedSize , HCcompressedSize ;
int blockContinueCompressedSize ;
2013-12-30 17:16:52 +00:00
2014-06-09 01:42:39 +00:00
if ( ( cycleNb % displayRefresh ) = = 0 )
2014-04-16 14:25:56 +00:00
{
2014-05-19 23:40:29 +00:00
printf ( " \r %7i /%7i - " , cycleNb , nbCycles ) ;
2014-06-09 01:42:39 +00:00
fflush ( stdout ) ;
2014-04-16 14:25:56 +00:00
}
2013-12-30 17:16:52 +00:00
2014-04-28 20:45:35 +00:00
// Select block to test
blockSize = FUZ_rand ( & randState ) % FUZ_MAX_BLOCK_SIZE ;
blockStart = FUZ_rand ( & randState ) % ( COMPRESSIBLE_NOISE_LENGTH - blockSize ) ;
dictSize = FUZ_rand ( & randState ) % FUZ_MAX_DICT_SIZE ;
if ( dictSize > blockStart ) dictSize = blockStart ;
block = ( ( char * ) CNBuffer ) + blockStart ;
dict = block - dictSize ;
/* Compression tests */
2013-12-30 17:16:52 +00:00
// Test compression HC
2014-04-28 20:45:35 +00:00
FUZ_DISPLAYTEST ;
ret = LZ4_compressHC ( block , compressedBuffer , blockSize ) ;
FUZ_CHECKTEST ( ret = = 0 , " LZ4_compressHC() failed " ) ;
HCcompressedSize = ret ;
2013-12-30 17:16:52 +00:00
// Test compression HC using external state
2014-04-28 20:45:35 +00:00
FUZ_DISPLAYTEST ;
ret = LZ4_compressHC_withStateHC ( stateLZ4HC , block , compressedBuffer , blockSize ) ;
2013-12-30 17:16:52 +00:00
FUZ_CHECKTEST ( ret = = 0 , " LZ4_compressHC_withStateHC() failed " ) ;
// Test compression using external state
2014-04-28 20:45:35 +00:00
FUZ_DISPLAYTEST ;
ret = LZ4_compress_withState ( stateLZ4 , block , compressedBuffer , blockSize ) ;
2013-12-30 17:16:52 +00:00
FUZ_CHECKTEST ( ret = = 0 , " LZ4_compress_withState() failed " ) ;
// Test compression
2014-04-28 20:45:35 +00:00
FUZ_DISPLAYTEST ;
ret = LZ4_compress ( block , compressedBuffer , blockSize ) ;
FUZ_CHECKTEST ( ret = = 0 , " LZ4_compress() failed " ) ;
compressedSize = ret ;
/* Decompression tests */
crcOrig = XXH32 ( block , blockSize , 0 ) ;
2013-12-30 17:16:52 +00:00
// Test decoding with output size being exactly what's necessary => must work
2014-04-28 20:45:35 +00:00
FUZ_DISPLAYTEST ;
ret = LZ4_decompress_fast ( compressedBuffer , decodedBuffer , blockSize ) ;
2013-12-30 17:16:52 +00:00
FUZ_CHECKTEST ( ret < 0 , " LZ4_decompress_fast failed despite correct space " ) ;
2014-04-28 20:45:35 +00:00
FUZ_CHECKTEST ( ret ! = compressedSize , " LZ4_decompress_fast failed : did not fully read compressed data " ) ;
crcCheck = XXH32 ( decodedBuffer , blockSize , 0 ) ;
FUZ_CHECKTEST ( crcCheck ! = crcOrig , " LZ4_decompress_fast corrupted decoded data " ) ;
2013-12-30 17:16:52 +00:00
// Test decoding with one byte missing => must fail
2014-04-28 20:45:35 +00:00
FUZ_DISPLAYTEST ;
decodedBuffer [ blockSize - 1 ] = 0 ;
ret = LZ4_decompress_fast ( compressedBuffer , decodedBuffer , blockSize - 1 ) ;
2013-12-30 17:16:52 +00:00
FUZ_CHECKTEST ( ret > = 0 , " LZ4_decompress_fast should have failed, due to Output Size being too small " ) ;
2014-04-28 20:45:35 +00:00
FUZ_CHECKTEST ( decodedBuffer [ blockSize - 1 ] , " LZ4_decompress_fast overrun specified output buffer " ) ;
2013-12-30 17:16:52 +00:00
// Test decoding with one byte too much => must fail
FUZ_DISPLAYTEST ;
2014-04-28 20:45:35 +00:00
ret = LZ4_decompress_fast ( compressedBuffer , decodedBuffer , blockSize + 1 ) ;
2013-12-30 17:16:52 +00:00
FUZ_CHECKTEST ( ret > = 0 , " LZ4_decompress_fast should have failed, due to Output Size being too large " ) ;
2014-04-28 20:45:35 +00:00
// Test decoding with output size exactly what's necessary => must work
2013-12-30 17:16:52 +00:00
FUZ_DISPLAYTEST ;
2014-04-28 20:45:35 +00:00
decodedBuffer [ blockSize ] = 0 ;
ret = LZ4_decompress_safe ( compressedBuffer , decodedBuffer , compressedSize , blockSize ) ;
2013-12-30 17:16:52 +00:00
FUZ_CHECKTEST ( ret < 0 , " LZ4_decompress_safe failed despite sufficient space " ) ;
2014-04-28 20:45:35 +00:00
FUZ_CHECKTEST ( ret ! = blockSize , " LZ4_decompress_safe did not regenerate original data " ) ;
FUZ_CHECKTEST ( decodedBuffer [ blockSize ] , " LZ4_decompress_safe overrun specified output buffer size " ) ;
crcCheck = XXH32 ( decodedBuffer , blockSize , 0 ) ;
FUZ_CHECKTEST ( crcCheck ! = crcOrig , " LZ4_decompress_safe corrupted decoded data " ) ;
2013-12-30 17:16:52 +00:00
2014-04-28 20:45:35 +00:00
// Test decoding with more than enough output size => must work
2013-12-30 17:16:52 +00:00
FUZ_DISPLAYTEST ;
2014-04-28 20:45:35 +00:00
decodedBuffer [ blockSize ] = 0 ;
decodedBuffer [ blockSize + 1 ] = 0 ;
ret = LZ4_decompress_safe ( compressedBuffer , decodedBuffer , compressedSize , blockSize + 1 ) ;
FUZ_CHECKTEST ( ret < 0 , " LZ4_decompress_safe failed despite amply sufficient space " ) ;
FUZ_CHECKTEST ( ret ! = blockSize , " LZ4_decompress_safe did not regenerate original data " ) ;
2014-05-19 23:40:29 +00:00
//FUZ_CHECKTEST(decodedBuffer[blockSize], "LZ4_decompress_safe wrote more than (unknown) target size"); // well, is that an issue ?
2014-04-28 20:45:35 +00:00
FUZ_CHECKTEST ( decodedBuffer [ blockSize + 1 ] , " LZ4_decompress_safe overrun specified output buffer size " ) ;
crcCheck = XXH32 ( decodedBuffer , blockSize , 0 ) ;
FUZ_CHECKTEST ( crcCheck ! = crcOrig , " LZ4_decompress_safe corrupted decoded data " ) ;
2013-12-30 17:16:52 +00:00
// Test decoding with output size being one byte too short => must fail
FUZ_DISPLAYTEST ;
2014-04-28 20:45:35 +00:00
decodedBuffer [ blockSize - 1 ] = 0 ;
ret = LZ4_decompress_safe ( compressedBuffer , decodedBuffer , compressedSize , blockSize - 1 ) ;
2013-12-30 17:16:52 +00:00
FUZ_CHECKTEST ( ret > = 0 , " LZ4_decompress_safe should have failed, due to Output Size being one byte too short " ) ;
2014-04-28 20:45:35 +00:00
FUZ_CHECKTEST ( decodedBuffer [ blockSize - 1 ] , " LZ4_decompress_safe overrun specified output buffer size " ) ;
// Test decoding with output size being 10 bytes too short => must fail
FUZ_DISPLAYTEST ;
if ( blockSize > 10 )
{
decodedBuffer [ blockSize - 10 ] = 0 ;
ret = LZ4_decompress_safe ( compressedBuffer , decodedBuffer , compressedSize , blockSize - 10 ) ;
FUZ_CHECKTEST ( ret > = 0 , " LZ4_decompress_safe should have failed, due to Output Size being 10 bytes too short " ) ;
FUZ_CHECKTEST ( decodedBuffer [ blockSize - 10 ] , " LZ4_decompress_safe overrun specified output buffer size " ) ;
}
2013-12-30 17:16:52 +00:00
// Test decoding with input size being one byte too short => must fail
FUZ_DISPLAYTEST ;
2014-04-28 20:45:35 +00:00
ret = LZ4_decompress_safe ( compressedBuffer , decodedBuffer , compressedSize - 1 , blockSize ) ;
FUZ_CHECKTEST ( ret > = 0 , " LZ4_decompress_safe should have failed, due to input size being one byte too short (blockSize=%i, ret=%i, compressedSize=%i) " , blockSize , ret , compressedSize ) ;
2013-12-30 17:16:52 +00:00
// Test decoding with input size being one byte too large => must fail
FUZ_DISPLAYTEST ;
2014-04-28 20:45:35 +00:00
decodedBuffer [ blockSize ] = 0 ;
ret = LZ4_decompress_safe ( compressedBuffer , decodedBuffer , compressedSize + 1 , blockSize ) ;
2013-12-30 17:16:52 +00:00
FUZ_CHECKTEST ( ret > = 0 , " LZ4_decompress_safe should have failed, due to input size being too large " ) ;
2014-04-28 20:45:35 +00:00
FUZ_CHECKTEST ( decodedBuffer [ blockSize ] , " LZ4_decompress_safe overrun specified output buffer size " ) ;
2013-12-30 17:16:52 +00:00
// Test partial decoding with target output size being max/2 => must work
FUZ_DISPLAYTEST ;
2014-04-28 20:45:35 +00:00
ret = LZ4_decompress_safe_partial ( compressedBuffer , decodedBuffer , compressedSize , blockSize / 2 , blockSize ) ;
2013-12-30 17:16:52 +00:00
FUZ_CHECKTEST ( ret < 0 , " LZ4_decompress_safe_partial failed despite sufficient space " ) ;
// Test partial decoding with target output size being just below max => must work
FUZ_DISPLAYTEST ;
2014-04-28 20:45:35 +00:00
ret = LZ4_decompress_safe_partial ( compressedBuffer , decodedBuffer , compressedSize , blockSize - 3 , blockSize ) ;
2013-12-30 17:16:52 +00:00
FUZ_CHECKTEST ( ret < 0 , " LZ4_decompress_safe_partial failed despite sufficient space " ) ;
2014-04-28 20:45:35 +00:00
/* Test Compression with limited output size */
2013-12-30 17:16:52 +00:00
// Test compression with output size being exactly what's necessary (should work)
FUZ_DISPLAYTEST ;
2014-04-28 20:45:35 +00:00
ret = LZ4_compress_limitedOutput ( block , compressedBuffer , blockSize , compressedSize ) ;
2013-12-30 17:16:52 +00:00
FUZ_CHECKTEST ( ret = = 0 , " LZ4_compress_limitedOutput() failed despite sufficient space " ) ;
// Test compression with output size being exactly what's necessary and external state (should work)
2014-04-28 20:45:35 +00:00
FUZ_DISPLAYTEST ;
ret = LZ4_compress_limitedOutput_withState ( stateLZ4 , block , compressedBuffer , blockSize , compressedSize ) ;
2013-12-30 17:16:52 +00:00
FUZ_CHECKTEST ( ret = = 0 , " LZ4_compress_limitedOutput_withState() failed despite sufficient space " ) ;
// Test HC compression with output size being exactly what's necessary (should work)
FUZ_DISPLAYTEST ;
2014-04-28 20:45:35 +00:00
ret = LZ4_compressHC_limitedOutput ( block , compressedBuffer , blockSize , HCcompressedSize ) ;
2013-12-30 17:16:52 +00:00
FUZ_CHECKTEST ( ret = = 0 , " LZ4_compressHC_limitedOutput() failed despite sufficient space " ) ;
// Test HC compression with output size being exactly what's necessary (should work)
FUZ_DISPLAYTEST ;
2014-04-28 20:45:35 +00:00
ret = LZ4_compressHC_limitedOutput_withStateHC ( stateLZ4HC , block , compressedBuffer , blockSize , HCcompressedSize ) ;
2013-12-30 17:16:52 +00:00
FUZ_CHECKTEST ( ret = = 0 , " LZ4_compressHC_limitedOutput_withStateHC() failed despite sufficient space " ) ;
// Test compression with just one missing byte into output buffer => must fail
FUZ_DISPLAYTEST ;
2014-04-28 20:45:35 +00:00
compressedBuffer [ compressedSize - 1 ] = 0 ;
ret = LZ4_compress_limitedOutput ( block , compressedBuffer , blockSize , compressedSize - 1 ) ;
FUZ_CHECKTEST ( ret , " LZ4_compress_limitedOutput should have failed (output buffer too small by 1 byte) " ) ;
FUZ_CHECKTEST ( compressedBuffer [ compressedSize - 1 ] , " LZ4_compress_limitedOutput overran output buffer " )
2013-12-30 17:16:52 +00:00
// Test HC compression with just one missing byte into output buffer => must fail
FUZ_DISPLAYTEST ;
2014-04-28 20:45:35 +00:00
compressedBuffer [ compressedSize - 1 ] = 0 ;
ret = LZ4_compressHC_limitedOutput ( block , compressedBuffer , blockSize , HCcompressedSize - 1 ) ;
FUZ_CHECKTEST ( ret , " LZ4_compressHC_limitedOutput should have failed (output buffer too small by 1 byte) " ) ;
FUZ_CHECKTEST ( compressedBuffer [ compressedSize - 1 ] , " LZ4_compressHC_limitedOutput overran output buffer " )
/* Dictionary tests */
// Compress using dictionary
FUZ_DISPLAYTEST ;
LZ4continue = LZ4_create ( dict ) ;
LZ4_compress_continue ( LZ4continue , dict , compressedBuffer , dictSize ) ; // Just to fill hash tables
blockContinueCompressedSize = LZ4_compress_continue ( LZ4continue , block , compressedBuffer , blockSize ) ;
FUZ_CHECKTEST ( blockContinueCompressedSize = = 0 , " LZ4_compress_continue failed " ) ;
2014-07-14 22:04:10 +00:00
free ( LZ4continue ) ;
2014-04-28 20:45:35 +00:00
// Decompress with dictionary as prefix
FUZ_DISPLAYTEST ;
memcpy ( decodedBuffer , dict , dictSize ) ;
ret = LZ4_decompress_fast_withPrefix64k ( compressedBuffer , decodedBuffer + dictSize , blockSize ) ;
FUZ_CHECKTEST ( ret ! = blockContinueCompressedSize , " LZ4_decompress_fast_withPrefix64k did not read all compressed block input " ) ;
crcCheck = XXH32 ( decodedBuffer + dictSize , blockSize , 0 ) ;
2014-06-02 06:07:19 +00:00
if ( crcCheck ! = crcOrig )
{
int i = 0 ;
while ( block [ i ] = = decodedBuffer [ i ] ) i + + ;
printf ( " Wrong Byte at position %i/%i \n " , i , blockSize ) ;
}
FUZ_CHECKTEST ( crcCheck ! = crcOrig , " LZ4_decompress_fast_withPrefix64k corrupted decoded data (dict %i) " , dictSize ) ;
2014-04-28 20:45:35 +00:00
FUZ_DISPLAYTEST ;
ret = LZ4_decompress_safe_withPrefix64k ( compressedBuffer , decodedBuffer + dictSize , blockContinueCompressedSize , blockSize ) ;
FUZ_CHECKTEST ( ret ! = blockSize , " LZ4_decompress_safe_withPrefix64k did not regenerate original data " ) ;
crcCheck = XXH32 ( decodedBuffer + dictSize , blockSize , 0 ) ;
FUZ_CHECKTEST ( crcCheck ! = crcOrig , " LZ4_decompress_safe_withPrefix64k corrupted decoded data " ) ;
2014-06-21 16:01:15 +00:00
// Compress using External dictionary
2014-05-19 23:40:29 +00:00
FUZ_DISPLAYTEST ;
2014-06-21 16:01:15 +00:00
dict - = 9 ; // Separation, so it is an ExtDict
2014-05-19 23:40:29 +00:00
if ( dict < ( char * ) CNBuffer ) dict = ( char * ) CNBuffer ;
2014-05-20 22:36:27 +00:00
LZ4_loadDict ( & LZ4dict , dict , dictSize ) ;
2014-06-09 01:42:39 +00:00
blockContinueCompressedSize = LZ4_compress_continue ( & LZ4dict , block , compressedBuffer , blockSize ) ;
2014-06-19 21:54:16 +00:00
FUZ_CHECKTEST ( blockContinueCompressedSize = = 0 , " LZ4_compress_continue failed " ) ;
2014-05-20 22:36:27 +00:00
FUZ_DISPLAYTEST ;
LZ4_loadDict ( & LZ4dict , dict , dictSize ) ;
2014-06-09 01:42:39 +00:00
ret = LZ4_compress_limitedOutput_continue ( & LZ4dict , block , compressedBuffer , blockSize , blockContinueCompressedSize - 1 ) ;
2014-06-21 16:01:15 +00:00
FUZ_CHECKTEST ( ret > 0 , " LZ4_compress_limitedOutput_continue using ExtDict should fail : one missing byte for output buffer " ) ;
2014-05-20 22:36:27 +00:00
FUZ_DISPLAYTEST ;
LZ4_loadDict ( & LZ4dict , dict , dictSize ) ;
2014-06-09 01:42:39 +00:00
ret = LZ4_compress_limitedOutput_continue ( & LZ4dict , block , compressedBuffer , blockSize , blockContinueCompressedSize ) ;
2014-06-21 16:01:15 +00:00
FUZ_CHECKTEST ( ret ! = blockContinueCompressedSize , " LZ4_compress_limitedOutput_compressed size is different (%i != %i) " , ret , blockContinueCompressedSize ) ;
2014-06-19 21:54:16 +00:00
FUZ_CHECKTEST ( ret < = 0 , " LZ4_compress_limitedOutput_continue should work : enough size available within output buffer " ) ;
2014-05-19 23:40:29 +00:00
2014-04-28 20:45:35 +00:00
// Decompress with dictionary as external
FUZ_DISPLAYTEST ;
decodedBuffer [ blockSize ] = 0 ;
2014-05-04 12:26:05 +00:00
ret = LZ4_decompress_fast_usingDict ( compressedBuffer , decodedBuffer , blockSize , dict , dictSize ) ;
FUZ_CHECKTEST ( ret ! = blockContinueCompressedSize , " LZ4_decompress_fast_usingDict did not read all compressed block input " ) ;
FUZ_CHECKTEST ( decodedBuffer [ blockSize ] , " LZ4_decompress_fast_usingDict overrun specified output buffer size " )
2014-04-28 20:45:35 +00:00
crcCheck = XXH32 ( decodedBuffer , blockSize , 0 ) ;
2014-05-19 23:40:29 +00:00
if ( crcCheck ! = crcOrig )
{
int i = 0 ;
while ( block [ i ] = = decodedBuffer [ i ] ) i + + ;
printf ( " Wrong Byte at position %i/%i \n " , i , blockSize ) ;
}
2014-06-02 06:07:19 +00:00
FUZ_CHECKTEST ( crcCheck ! = crcOrig , " LZ4_decompress_fast_usingDict corrupted decoded data (dict %i) " , dictSize ) ;
2014-04-28 20:45:35 +00:00
FUZ_DISPLAYTEST ;
decodedBuffer [ blockSize ] = 0 ;
2014-05-04 12:26:05 +00:00
ret = LZ4_decompress_safe_usingDict ( compressedBuffer , decodedBuffer , blockContinueCompressedSize , blockSize , dict , dictSize ) ;
FUZ_CHECKTEST ( ret ! = blockSize , " LZ4_decompress_safe_usingDict did not regenerate original data " ) ;
FUZ_CHECKTEST ( decodedBuffer [ blockSize ] , " LZ4_decompress_safe_usingDict overrun specified output buffer size " )
2014-04-28 20:45:35 +00:00
crcCheck = XXH32 ( decodedBuffer , blockSize , 0 ) ;
2014-05-04 12:26:05 +00:00
FUZ_CHECKTEST ( crcCheck ! = crcOrig , " LZ4_decompress_safe_usingDict corrupted decoded data " ) ;
2014-04-28 20:45:35 +00:00
FUZ_DISPLAYTEST ;
decodedBuffer [ blockSize - 1 ] = 0 ;
2014-05-04 12:26:05 +00:00
ret = LZ4_decompress_fast_usingDict ( compressedBuffer , decodedBuffer , blockSize - 1 , dict , dictSize ) ;
2014-04-28 20:45:35 +00:00
FUZ_CHECKTEST ( ret > = 0 , " LZ4_decompress_fast_withDict should have failed : wrong original size (-1 byte) " ) ;
2014-05-04 12:26:05 +00:00
FUZ_CHECKTEST ( decodedBuffer [ blockSize - 1 ] , " LZ4_decompress_fast_usingDict overrun specified output buffer size " ) ;
2014-04-28 20:45:35 +00:00
FUZ_DISPLAYTEST ;
decodedBuffer [ blockSize - 1 ] = 0 ;
2014-05-04 12:26:05 +00:00
ret = LZ4_decompress_safe_usingDict ( compressedBuffer , decodedBuffer , blockContinueCompressedSize , blockSize - 1 , dict , dictSize ) ;
FUZ_CHECKTEST ( ret > = 0 , " LZ4_decompress_safe_usingDict should have failed : not enough output size (-1 byte) " ) ;
FUZ_CHECKTEST ( decodedBuffer [ blockSize - 1 ] , " LZ4_decompress_safe_usingDict overrun specified output buffer size " ) ;
2014-04-28 20:45:35 +00:00
FUZ_DISPLAYTEST ;
if ( blockSize > 10 )
{
decodedBuffer [ blockSize - 10 ] = 0 ;
2014-05-04 12:26:05 +00:00
ret = LZ4_decompress_safe_usingDict ( compressedBuffer , decodedBuffer , blockContinueCompressedSize , blockSize - 10 , dict , dictSize ) ;
2014-06-21 16:01:15 +00:00
FUZ_CHECKTEST ( ret > = 0 , " LZ4_decompress_safe_usingDict should have failed : output buffer too small (-10 byte) " ) ;
2014-05-04 12:26:05 +00:00
FUZ_CHECKTEST ( decodedBuffer [ blockSize - 10 ] , " LZ4_decompress_safe_usingDict overrun specified output buffer size (-10 byte) (blockSize=%i) " , blockSize ) ;
2014-04-28 20:45:35 +00:00
}
2013-12-30 17:16:52 +00:00
2014-04-28 20:45:35 +00:00
// Fill stats
bytes + = blockSize ;
cbytes + = compressedSize ;
hcbytes + = HCcompressedSize ;
ccbytes + = blockContinueCompressedSize ;
2013-12-30 17:16:52 +00:00
}
2014-05-19 23:40:29 +00:00
printf ( " \r %7i /%7i - " , cycleNb , nbCycles ) ;
2013-12-30 17:16:52 +00:00
printf ( " all tests completed successfully \n " ) ;
printf ( " compression ratio: %0.3f%% \n " , ( double ) cbytes / bytes * 100 ) ;
printf ( " HC compression ratio: %0.3f%% \n " , ( double ) hcbytes / bytes * 100 ) ;
2014-04-28 20:45:35 +00:00
printf ( " ratio with dict: %0.3f%% \n " , ( double ) ccbytes / bytes * 100 ) ;
2014-04-28 22:17:49 +00:00
// unalloc
2014-04-16 14:25:56 +00:00
if ( ! no_prompt ) getchar ( ) ;
2014-04-28 22:17:49 +00:00
free ( CNBuffer ) ;
free ( compressedBuffer ) ;
free ( decodedBuffer ) ;
2014-04-29 20:39:08 +00:00
free ( stateLZ4 ) ;
free ( stateLZ4HC ) ;
2013-12-30 17:16:52 +00:00
return 0 ;
_output_error :
2014-04-16 14:25:56 +00:00
if ( ! no_prompt ) getchar ( ) ;
2014-04-28 22:17:49 +00:00
free ( CNBuffer ) ;
free ( compressedBuffer ) ;
free ( decodedBuffer ) ;
2014-04-29 20:39:08 +00:00
free ( stateLZ4 ) ;
free ( stateLZ4HC ) ;
2013-12-30 17:16:52 +00:00
return 1 ;
}
2014-04-29 20:39:08 +00:00
2014-07-14 22:29:40 +00:00
int FUZ_usage ( void )
2014-04-29 20:39:08 +00:00
{
DISPLAY ( " Usage : \n " ) ;
DISPLAY ( " %s [args] \n " , programName ) ;
DISPLAY ( " \n " ) ;
DISPLAY ( " Arguments : \n " ) ;
DISPLAY ( " -i# : Nb of tests (default:%i) \n " , NB_ATTEMPTS ) ;
DISPLAY ( " -s# : Select seed (default:prompt user) \n " ) ;
2014-05-19 23:40:29 +00:00
DISPLAY ( " -t# : Select starting test number (default:0) \n " ) ;
2014-04-29 22:44:49 +00:00
DISPLAY ( " -p# : Select compressibility in %% (default:%i%%) \n " , FUZ_COMPRESSIBILITY_DEFAULT ) ;
2014-06-09 01:42:39 +00:00
DISPLAY ( " -v : verbose \n " ) ;
2014-04-29 20:39:08 +00:00
DISPLAY ( " -h : display help and exit \n " ) ;
return 0 ;
}
int main ( int argc , char * * argv ) {
U32 timestamp = FUZ_GetMilliStart ( ) ;
U32 seed = 0 ;
int seedset = 0 ;
int argNb ;
int nbTests = NB_ATTEMPTS ;
2014-05-19 23:40:29 +00:00
int testNb = 0 ;
2014-04-29 22:44:49 +00:00
int proba = FUZ_COMPRESSIBILITY_DEFAULT ;
2014-04-29 20:39:08 +00:00
// Check command line
programName = argv [ 0 ] ;
for ( argNb = 1 ; argNb < argc ; argNb + + )
{
char * argument = argv [ argNb ] ;
if ( ! argument ) continue ; // Protection if argument empty
// Decode command (note : aggregated commands are allowed)
if ( argument [ 0 ] = = ' - ' )
{
2014-06-09 01:42:39 +00:00
if ( ! strcmp ( argument , " --no-prompt " ) ) { no_prompt = 1 ; seedset = 1 ; displayLevel = 1 ; continue ; }
2014-04-29 20:39:08 +00:00
while ( argument [ 1 ] ! = 0 )
{
argument + + ;
switch ( * argument )
{
case ' h ' :
return FUZ_usage ( ) ;
2014-06-09 01:42:39 +00:00
case ' v ' :
argument + + ;
displayLevel = 4 ;
break ;
2014-04-29 20:39:08 +00:00
case ' i ' :
argument + + ;
nbTests = 0 ;
while ( ( * argument > = ' 0 ' ) & & ( * argument < = ' 9 ' ) )
{
nbTests * = 10 ;
nbTests + = * argument - ' 0 ' ;
argument + + ;
}
break ;
case ' s ' :
argument + + ;
seed = 0 ; seedset = 1 ;
while ( ( * argument > = ' 0 ' ) & & ( * argument < = ' 9 ' ) )
{
seed * = 10 ;
seed + = * argument - ' 0 ' ;
argument + + ;
}
break ;
2014-05-19 23:40:29 +00:00
case ' t ' :
argument + + ;
testNb = 0 ;
while ( ( * argument > = ' 0 ' ) & & ( * argument < = ' 9 ' ) )
{
testNb * = 10 ;
testNb + = * argument - ' 0 ' ;
argument + + ;
}
break ;
2014-04-29 22:44:49 +00:00
case ' p ' :
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 ;
2014-04-29 20:39:08 +00:00
default : ;
}
}
}
}
// Get Seed
printf ( " Starting LZ4 fuzzer (%i-bits, %s) \n " , ( int ) ( sizeof ( size_t ) * 8 ) , LZ4_VERSION ) ;
if ( ! seedset )
{
2014-06-22 10:25:04 +00:00
char userInput [ 50 ] = { 0 } ;
2014-04-29 20:39:08 +00:00
printf ( " Select an Initialisation number (default : random) : " ) ;
fflush ( stdout ) ;
if ( no_prompt | | fgets ( userInput , sizeof userInput , stdin ) )
{
if ( sscanf ( userInput , " %u " , & seed ) = = 1 ) { }
else seed = FUZ_GetMilliSpan ( timestamp ) ;
}
}
printf ( " Seed = %u \n " , seed ) ;
2014-04-29 22:44:49 +00:00
if ( proba ! = FUZ_COMPRESSIBILITY_DEFAULT ) printf ( " Compressibility : %i%% \n " , proba ) ;
2014-04-29 20:39:08 +00:00
2014-08-30 11:32:09 +00:00
FUZ_AddressOverflow ( ) ;
2014-04-29 20:39:08 +00:00
if ( nbTests < = 0 ) nbTests = 1 ;
2014-05-19 23:40:29 +00:00
return FUZ_test ( seed , nbTests , testNb , ( ( double ) proba ) / 100 ) ;
2014-04-29 20:39:08 +00:00
}