2012-10-24 12:59:19 +00:00
/*
fuzzer . c - Fuzzer test tool for LZ4
2013-06-10 17:29:13 +00:00
Copyright ( C ) Yann Collet - Andrew Mahone 2012 - 2013
Code started by Andrew Mahone , modified by Yann Collet
2013-03-30 21:11:40 +00:00
GPL v2 License
2012-10-24 12:59:19 +00:00
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 .
2013-03-30 21:11:40 +00:00
You can contact the author at :
- LZ4 homepage : http : //fastcompression.blogspot.com/p/lz4.html
- LZ4 source repository : http : //code.google.com/p/lz4/
2012-10-24 12:59:19 +00:00
*/
//**************************************
// Remove Visual warning messages
//**************************************
# define _CRT_SECURE_NO_WARNINGS // fgets
//**************************************
// Includes
//**************************************
# include <stdlib.h>
2012-11-30 13:23:36 +00:00
# include <stdio.h> // fgets, sscanf
2012-10-24 12:59:19 +00:00
# include <sys/timeb.h> // timeb
# include "lz4.h"
2013-03-30 21:11:40 +00:00
# include "lz4hc.h"
2012-10-24 12:59:19 +00:00
//**************************************
// Constants
//**************************************
2013-04-18 08:53:13 +00:00
# define NB_ATTEMPTS (1<<17)
2012-10-24 12:59:19 +00:00
# define LEN ((1<<15))
# define SEQ_POW 2
# define NUM_SEQ (1 << SEQ_POW)
# define SEQ_MSK ((NUM_SEQ) - 1)
# define MOD_SEQ(x) ((((x) >> 8) & 255) == 0)
# define NEW_SEQ(x) ((((x) >> 10) %10) == 0)
# define PAGE_SIZE 4096
# define ROUND_PAGE(x) (((x) + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1))
# define PRIME1 2654435761U
# define PRIME2 2246822519U
# define PRIME3 3266489917U
//*********************************************************
// Functions
//*********************************************************
static int FUZ_GetMilliStart ( )
{
2013-06-10 17:29:13 +00:00
struct timeb tb ;
int nCount ;
ftime ( & tb ) ;
nCount = ( int ) ( tb . millitm + ( tb . time & 0xfffff ) * 1000 ) ;
return nCount ;
2012-10-24 12:59:19 +00:00
}
2013-06-10 17:29:13 +00:00
2012-10-24 12:59:19 +00:00
static int FUZ_GetMilliSpan ( int nTimeStart )
{
2013-06-10 17:29:13 +00:00
int nSpan = FUZ_GetMilliStart ( ) - nTimeStart ;
if ( nSpan < 0 )
nSpan + = 0x100000 * 1000 ;
return nSpan ;
2012-10-24 12:59:19 +00:00
}
unsigned int FUZ_rand ( unsigned int * src )
{
2013-03-30 21:11:40 +00:00
* src = ( ( * src ) * PRIME1 ) + PRIME2 ;
return * src ;
2012-10-24 12:59:19 +00:00
}
2013-06-10 17:29:13 +00:00
int test_canary ( unsigned char * buf )
{
int i ;
for ( i = 0 ; i < 2048 ; i + + )
if ( buf [ i ] ! = buf [ i + 2048 ] )
return 0 ;
return 1 ;
2012-10-24 12:59:19 +00:00
}
2013-06-10 17:29:13 +00:00
2012-12-21 16:49:17 +00:00
int FUZ_SecurityTest ( )
{
char * output ;
char * input ;
int i , r ;
2013-05-27 13:37:48 +00:00
printf ( " Overflow test (issue 52)... " ) ;
2012-12-21 16:49:17 +00:00
input = ( char * ) malloc ( 20 < < 20 ) ;
output = ( char * ) malloc ( 20 < < 20 ) ;
input [ 0 ] = 0x0F ;
input [ 1 ] = 0x00 ;
input [ 2 ] = 0x00 ;
for ( i = 3 ; i < 16840000 ; i + + )
input [ i ] = 0xff ;
2013-04-26 14:37:46 +00:00
r = LZ4_decompress_fast ( input , output , 20 < < 20 ) ;
2012-12-21 16:49:17 +00:00
free ( input ) ;
free ( output ) ;
2013-04-18 08:53:13 +00:00
printf ( " Passed (return = %i < 0) \n " , r ) ;
2012-12-21 16:49:17 +00:00
return 0 ;
}
2012-10-24 12:59:19 +00:00
//int main(int argc, char *argv[]) {
int main ( ) {
unsigned long long bytes = 0 ;
unsigned long long cbytes = 0 ;
2013-04-18 08:53:13 +00:00
unsigned long long hcbytes = 0 ;
2012-10-24 12:59:19 +00:00
unsigned char buf [ LEN ] ;
2012-11-30 13:23:36 +00:00
unsigned char testOut [ LEN + 1 ] ;
# define FUZ_max LZ4_COMPRESSBOUND(LEN)
2012-10-26 12:35:31 +00:00
# define FUZ_avail ROUND_PAGE(FUZ_max)
const int off_full = FUZ_avail - FUZ_max ;
unsigned char cbuf [ FUZ_avail + PAGE_SIZE ] ;
2013-06-10 17:29:13 +00:00
unsigned int seed , randState , cur_seq = PRIME3 , seeds [ NUM_SEQ ] , timestamp = FUZ_GetMilliStart ( ) ;
int i , j , k , ret , len , lenHC , attemptNb ;
2013-03-30 21:11:40 +00:00
char userInput [ 30 ] = { 0 } ;
2013-06-10 17:29:13 +00:00
# define FUZ_CHECKTEST(cond, message) testNb++; if (cond) { printf("Test %i : %s : seed %u, cycle %u \n", testNb, message, seed, attemptNb); goto _output_error; }
2012-10-24 12:59:19 +00:00
2013-03-30 21:11:40 +00:00
printf ( " starting LZ4 fuzzer \n " ) ;
printf ( " Select an Initialisation number (default : random) : " ) ;
fflush ( stdout ) ;
if ( fgets ( userInput , sizeof userInput , stdin ) )
{
if ( sscanf ( userInput , " %d " , & seed ) = = 1 ) { }
else seed = FUZ_GetMilliSpan ( timestamp ) ;
}
printf ( " Seed = %u \n " , seed ) ;
2013-06-10 17:29:13 +00:00
randState = seed ;
2012-10-24 12:59:19 +00:00
2013-03-30 21:11:40 +00:00
FUZ_SecurityTest ( ) ;
2012-12-21 16:49:17 +00:00
2013-03-30 21:11:40 +00:00
for ( i = 0 ; i < 2048 ; i + + )
2013-06-10 17:29:13 +00:00
cbuf [ FUZ_avail + i ] = cbuf [ FUZ_avail + 2048 + i ] = FUZ_rand ( & randState ) > > 16 ;
2012-10-24 12:59:19 +00:00
2013-06-10 17:29:13 +00:00
for ( attemptNb = 0 ; attemptNb < NB_ATTEMPTS ; attemptNb + + )
2013-03-02 23:34:21 +00:00
{
2013-06-10 17:29:13 +00:00
int testNb = 0 ;
printf ( " \r %7i /%7i \r " , attemptNb , NB_ATTEMPTS ) ;
2013-03-30 21:11:40 +00:00
2012-10-24 12:59:19 +00:00
for ( j = 0 ; j < NUM_SEQ ; j + + ) {
2013-06-10 17:29:13 +00:00
seeds [ j ] = FUZ_rand ( & randState ) < < 8 ;
seeds [ j ] ^ = ( FUZ_rand ( & randState ) > > 8 ) & 65535 ;
2012-10-24 12:59:19 +00:00
}
for ( j = 0 ; j < LEN ; j + + ) {
2013-06-10 17:29:13 +00:00
k = FUZ_rand ( & randState ) ;
2012-10-24 12:59:19 +00:00
if ( j = = 0 | | NEW_SEQ ( k ) )
2013-06-10 17:29:13 +00:00
cur_seq = seeds [ ( FUZ_rand ( & randState ) > > 16 ) & SEQ_MSK ] ;
2012-10-24 12:59:19 +00:00
if ( MOD_SEQ ( k ) ) {
2013-06-10 17:29:13 +00:00
k = ( FUZ_rand ( & randState ) > > 16 ) & SEQ_MSK ;
seeds [ k ] = FUZ_rand ( & randState ) < < 8 ;
seeds [ k ] ^ = ( FUZ_rand ( & randState ) > > 8 ) & 65535 ;
2012-10-24 12:59:19 +00:00
}
buf [ j ] = FUZ_rand ( & cur_seq ) > > 16 ;
}
2012-11-30 13:23:36 +00:00
2013-04-18 08:53:13 +00:00
// Test compression HC
ret = LZ4_compressHC_limitedOutput ( ( const char * ) buf , ( char * ) & cbuf [ off_full ] , LEN , FUZ_max ) ;
2013-06-10 17:29:13 +00:00
FUZ_CHECKTEST ( ret = = 0 , " HC compression failed despite sufficient space " ) ;
2013-04-18 08:53:13 +00:00
lenHC = ret ;
2013-03-30 21:11:40 +00:00
// Test compression
2012-10-26 12:35:31 +00:00
ret = LZ4_compress_limitedOutput ( ( const char * ) buf , ( char * ) & cbuf [ off_full ] , LEN , FUZ_max ) ;
2013-06-10 17:29:13 +00:00
FUZ_CHECKTEST ( ret = = 0 , " compression failed despite sufficient space " ) ;
2012-10-24 12:59:19 +00:00
len = ret ;
2013-03-30 21:11:40 +00:00
// Test decoding with output size being exactly what's necessary => must work
2013-04-26 14:37:46 +00:00
ret = LZ4_decompress_fast ( ( char * ) & cbuf [ off_full ] , ( char * ) testOut , LEN ) ;
2013-06-10 17:29:13 +00:00
FUZ_CHECKTEST ( ret < 0 , " decompression failed despite correct space " ) ;
2012-11-30 13:23:36 +00:00
2013-03-30 21:11:40 +00:00
// Test decoding with one byte missing => must fail
2013-04-26 14:37:46 +00:00
ret = LZ4_decompress_fast ( ( char * ) & cbuf [ off_full ] , ( char * ) testOut , LEN - 1 ) ;
2013-06-10 17:29:13 +00:00
FUZ_CHECKTEST ( ret > = 0 , " decompression should have failed, due to Output Size being too small " ) ;
2012-11-30 13:23:36 +00:00
2013-03-30 21:11:40 +00:00
// Test decoding with one byte too much => must fail
2013-04-26 14:37:46 +00:00
ret = LZ4_decompress_fast ( ( char * ) & cbuf [ off_full ] , ( char * ) testOut , LEN + 1 ) ;
2013-06-10 17:29:13 +00:00
FUZ_CHECKTEST ( ret > = 0 , " decompression should have failed, due to Output Size being too large " ) ;
2012-11-30 13:23:36 +00:00
2013-03-30 21:11:40 +00:00
// Test decoding with enough output size => must work
2013-04-26 14:37:46 +00:00
ret = LZ4_decompress_safe ( ( char * ) & cbuf [ off_full ] , ( char * ) testOut , len , LEN + 1 ) ;
2013-06-10 17:29:13 +00:00
FUZ_CHECKTEST ( ret < 0 , " decompression failed despite sufficient space " ) ;
2012-11-30 13:23:36 +00:00
2013-03-30 21:11:40 +00:00
// Test decoding with output size being exactly what's necessary => must work
2013-04-26 14:37:46 +00:00
ret = LZ4_decompress_safe ( ( char * ) & cbuf [ off_full ] , ( char * ) testOut , len , LEN ) ;
2013-06-10 17:29:13 +00:00
FUZ_CHECKTEST ( ret < 0 , " decompression failed despite sufficient space " ) ;
2012-11-30 13:23:36 +00:00
2013-03-30 21:11:40 +00:00
// Test decoding with output size being one byte too short => must fail
2013-04-26 14:37:46 +00:00
ret = LZ4_decompress_safe ( ( char * ) & cbuf [ off_full ] , ( char * ) testOut , len , LEN - 1 ) ;
2013-06-10 17:29:13 +00:00
FUZ_CHECKTEST ( ret > = 0 , " LZ4_decompress_safe should have failed, due to Output Size being one byte too short " ) ;
2012-11-30 13:23:36 +00:00
2013-03-30 21:11:40 +00:00
// Test decoding with input size being one byte too short => must fail
2013-04-26 14:37:46 +00:00
ret = LZ4_decompress_safe ( ( char * ) & cbuf [ off_full ] , ( char * ) testOut , len - 1 , LEN ) ;
2013-06-10 17:29:13 +00:00
FUZ_CHECKTEST ( ret > = 0 , " LZ4_decompress_safe should have failed, due to input size being one byte too short " ) ;
2012-11-30 13:23:36 +00:00
2013-03-30 21:11:40 +00:00
// Test decoding with input size being one byte too large => must fail
2013-04-26 14:37:46 +00:00
ret = LZ4_decompress_safe ( ( char * ) & cbuf [ off_full ] , ( char * ) testOut , len + 1 , LEN ) ;
2013-06-10 17:29:13 +00:00
FUZ_CHECKTEST ( ret > = 0 , " decompression should have failed, due to input size being too large " ) ;
//if (ret>=0) { printf("Test 10 : decompression should have failed, due to input size being too large : seed %u, len %d\n", seed, LEN); goto _output_error; }
// Test partial decoding with target output size being max/2 => must work
ret = LZ4_decompress_safe_partial ( ( char * ) & cbuf [ off_full ] , ( char * ) testOut , len , LEN / 2 , LEN ) ;
FUZ_CHECKTEST ( ret < 0 , " partial decompression failed despite sufficient space " ) ;
// Test partial decoding with target output size being just below max => must work
ret = LZ4_decompress_safe_partial ( ( char * ) & cbuf [ off_full ] , ( char * ) testOut , len , LEN - 3 , LEN ) ;
FUZ_CHECKTEST ( ret < 0 , " partial decompression failed despite sufficient space " ) ;
2012-11-30 13:23:36 +00:00
2013-03-30 21:11:40 +00:00
// Test compression with output size being exactly what's necessary (should work)
2012-10-26 12:35:31 +00:00
ret = LZ4_compress_limitedOutput ( ( const char * ) buf , ( char * ) & cbuf [ FUZ_avail - len ] , LEN , len ) ;
2013-06-10 17:29:13 +00:00
FUZ_CHECKTEST ( ! test_canary ( & cbuf [ FUZ_avail ] ) , " compression overran output buffer " ) ;
FUZ_CHECKTEST ( ret = = 0 , " compression failed despite sufficient space " ) ;
2012-10-24 12:59:19 +00:00
2013-04-18 08:53:13 +00:00
// Test HC compression with output size being exactly what's necessary (should work)
ret = LZ4_compressHC_limitedOutput ( ( const char * ) buf , ( char * ) & cbuf [ FUZ_avail - len ] , LEN , lenHC ) ;
2013-06-10 17:29:13 +00:00
FUZ_CHECKTEST ( ret = = 0 , " HC compression failed despite sufficient space " ) ;
2013-04-18 08:53:13 +00:00
2013-03-30 21:11:40 +00:00
// Test compression with just one missing byte into output buffer => must fail
2012-10-26 12:35:31 +00:00
ret = LZ4_compress_limitedOutput ( ( const char * ) buf , ( char * ) & cbuf [ FUZ_avail - ( len - 1 ) ] , LEN , len - 1 ) ;
2013-06-10 17:29:13 +00:00
FUZ_CHECKTEST ( ret , " compression overran output buffer " ) ;
FUZ_CHECKTEST ( ! test_canary ( & cbuf [ FUZ_avail ] ) , " compression overran output buffer " ) ;
2012-10-24 12:59:19 +00:00
2013-04-18 08:53:13 +00:00
// Test HC compression with just one missing byte into output buffer => must fail
ret = LZ4_compressHC_limitedOutput ( ( const char * ) buf , ( char * ) & cbuf [ FUZ_avail - ( len - 1 ) ] , LEN , lenHC - 1 ) ;
2013-06-10 17:29:13 +00:00
FUZ_CHECKTEST ( ret , " HC compression overran output buffer " ) ;
2013-04-18 08:53:13 +00:00
2013-03-30 21:11:40 +00:00
bytes + = LEN ;
2012-10-24 12:59:19 +00:00
cbytes + = len ;
2013-04-18 08:53:13 +00:00
hcbytes + = lenHC ;
2013-06-10 17:29:13 +00:00
FUZ_rand ( & randState ) ;
2012-10-24 12:59:19 +00:00
}
2012-11-30 13:23:36 +00:00
2013-03-30 21:11:40 +00:00
printf ( " all tests completed successfully \n " ) ;
2012-10-24 12:59:19 +00:00
printf ( " compression ratio: %0.3f%% \n " , ( double ) cbytes / bytes * 100 ) ;
2013-04-18 08:53:13 +00:00
printf ( " HC compression ratio: %0.3f%% \n " , ( double ) hcbytes / bytes * 100 ) ;
2013-03-30 21:11:40 +00:00
getchar ( ) ;
2012-10-24 12:59:19 +00:00
return 0 ;
2012-11-30 13:23:36 +00:00
_output_error :
2013-03-30 21:11:40 +00:00
getchar ( ) ;
return 1 ;
2012-10-24 12:59:19 +00:00
}