You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
227 lines
8.8 KiB
227 lines
8.8 KiB
/* |
|
fuzzer.c - Fuzzer test tool for LZ4 |
|
Copyright (C) Andrew Mahone - Yann Collet 2012 |
|
Original code by Andrew Mahone / Modified by Yann Collet |
|
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/ |
|
*/ |
|
|
|
//************************************** |
|
// Remove Visual warning messages |
|
//************************************** |
|
#define _CRT_SECURE_NO_WARNINGS // fgets |
|
|
|
|
|
//************************************** |
|
// Includes |
|
//************************************** |
|
#include <stdlib.h> |
|
#include <stdio.h> // fgets, sscanf |
|
#include <sys/timeb.h> // timeb |
|
#include "lz4.h" |
|
|
|
|
|
//************************************** |
|
// Constants |
|
//************************************** |
|
#define NB_ATTEMPTS (1<<18) |
|
#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() |
|
{ |
|
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; |
|
} |
|
|
|
|
|
unsigned int FUZ_rand(unsigned int* src) |
|
{ |
|
*src = ((*src) * PRIME1) + PRIME2; |
|
return *src; |
|
} |
|
|
|
|
|
int test_canary(unsigned char *buf) { |
|
int i; |
|
for (i = 0; i < 2048; i++) |
|
if (buf[i] != buf[i + 2048]) |
|
return 0; |
|
return 1; |
|
} |
|
|
|
int FUZ_SecurityTest() |
|
{ |
|
char* output; |
|
char* input; |
|
int i, r; |
|
|
|
printf("Starting security tests..."); |
|
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; |
|
r = LZ4_uncompress(input, output, 20<<20); |
|
|
|
free(input); |
|
free(output); |
|
printf(" Completed (r=%i)\n",r); |
|
return 0; |
|
} |
|
|
|
|
|
//int main(int argc, char *argv[]) { |
|
int main() { |
|
unsigned long long bytes = 0; |
|
unsigned long long cbytes = 0; |
|
unsigned char buf[LEN]; |
|
unsigned char testOut[LEN+1]; |
|
# define FUZ_max LZ4_COMPRESSBOUND(LEN) |
|
# define FUZ_avail ROUND_PAGE(FUZ_max) |
|
const int off_full = FUZ_avail - FUZ_max; |
|
unsigned char cbuf[FUZ_avail + PAGE_SIZE]; |
|
unsigned int seed, cur_seq=PRIME3, seeds[NUM_SEQ], timestamp=FUZ_GetMilliStart(); |
|
int i, j, k, ret, len; |
|
char userInput[30] = {0}; |
|
|
|
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); |
|
|
|
FUZ_SecurityTest(); |
|
|
|
for (i = 0; i < 2048; i++) |
|
cbuf[FUZ_avail + i] = cbuf[FUZ_avail + 2048 + i] = FUZ_rand(&seed) >> 16; |
|
|
|
for (i = 0; i < NB_ATTEMPTS; i++) |
|
{ |
|
printf("\r%7i /%7i\r", i, NB_ATTEMPTS); |
|
|
|
FUZ_rand(&seed); |
|
for (j = 0; j < NUM_SEQ; j++) { |
|
seeds[j] = FUZ_rand(&seed) << 8; |
|
seeds[j] ^= (FUZ_rand(&seed) >> 8) & 65535; |
|
} |
|
for (j = 0; j < LEN; j++) { |
|
k = FUZ_rand(&seed); |
|
if (j == 0 || NEW_SEQ(k)) |
|
cur_seq = seeds[(FUZ_rand(&seed) >> 16) & SEQ_MSK]; |
|
if (MOD_SEQ(k)) { |
|
k = (FUZ_rand(&seed) >> 16) & SEQ_MSK; |
|
seeds[k] = FUZ_rand(&seed) << 8; |
|
seeds[k] ^= (FUZ_rand(&seed) >> 8) & 65535; |
|
} |
|
buf[j] = FUZ_rand(&cur_seq) >> 16; |
|
} |
|
|
|
// Test compression |
|
ret = LZ4_compress_limitedOutput((const char*)buf, (char*)&cbuf[off_full], LEN, FUZ_max); |
|
if (ret == 0) { printf("compression failed despite sufficient space: seed %u, len %d\n", seed, LEN); goto _output_error; } |
|
len = ret; |
|
|
|
// Test decoding with output size being exactly what's necessary => must work |
|
ret = LZ4_uncompress((char*)&cbuf[off_full], (char*)testOut, LEN); |
|
if (ret<0) { printf("decompression failed despite correct space: seed %u, len %d\n", seed, LEN); goto _output_error; } |
|
|
|
// Test decoding with one byte missing => must fail |
|
ret = LZ4_uncompress((char*)&cbuf[off_full], (char*)testOut, LEN-1); |
|
if (ret>=0) { printf("decompression should have failed, due to Output Size being too small : seed %u, len %d\n", seed, LEN); goto _output_error; } |
|
|
|
// Test decoding with one byte too much => must fail |
|
ret = LZ4_uncompress((char*)&cbuf[off_full], (char*)testOut, LEN+1); |
|
if (ret>=0) { printf("decompression should have failed, due to Output Size being too large : seed %u, len %d\n", seed, LEN); goto _output_error; } |
|
|
|
// Test decoding with enough output size => must work |
|
ret = LZ4_uncompress_unknownOutputSize((char*)&cbuf[off_full], (char*)testOut, len, LEN+1); |
|
if (ret<0) { printf("decompression failed despite sufficient space: seed %u, len %d\n", seed, LEN); goto _output_error; } |
|
|
|
// Test decoding with output size being exactly what's necessary => must work |
|
ret = LZ4_uncompress_unknownOutputSize((char*)&cbuf[off_full], (char*)testOut, len, LEN); |
|
if (ret<0) { printf("decompression failed despite sufficient space: seed %u, len %d\n", seed, LEN); goto _output_error; } |
|
|
|
// Test decoding with output size being one byte too short => must fail |
|
ret = LZ4_uncompress_unknownOutputSize((char*)&cbuf[off_full], (char*)testOut, len, LEN-1); |
|
if (ret>=0) { printf("decompression should have failed, due to Output Size being too small : seed %u, len %d\n", seed, LEN); goto _output_error; } |
|
|
|
// Test decoding with input size being one byte too short => must fail |
|
ret = LZ4_uncompress_unknownOutputSize((char*)&cbuf[off_full], (char*)testOut, len-1, LEN); |
|
if (ret>=0) { printf("decompression should have failed, due to input size being too small : seed %u, len %d\n", seed, LEN); goto _output_error; } |
|
|
|
// Test decoding with input size being one byte too large => must fail |
|
ret = LZ4_uncompress_unknownOutputSize((char*)&cbuf[off_full], (char*)testOut, len+1, LEN); |
|
if (ret>=0) { printf("decompression should have failed, due to input size being too large : seed %u, len %d\n", seed, LEN); goto _output_error; } |
|
|
|
// Test compression with output size being exactly what's necessary (should work) |
|
ret = LZ4_compress_limitedOutput((const char*)buf, (char*)&cbuf[FUZ_avail-len], LEN, len); |
|
if (!test_canary(&cbuf[FUZ_avail])) { printf("compression overran output buffer: seed %u, len %d, olen %d\n", seed, LEN, len); goto _output_error; } |
|
if (ret == 0) { printf("compression failed despite sufficient space: seed %u, len %d\n", seed, LEN); goto _output_error; } |
|
|
|
// Test compression with just one missing byte into output buffer => must fail |
|
ret = LZ4_compress_limitedOutput((const char*)buf, (char*)&cbuf[FUZ_avail-(len-1)], LEN, len-1); |
|
if (ret) { printf("compression overran output buffer: seed %u, len %d, olen %d => ret %d", seed, LEN, len-1, ret); goto _output_error; } |
|
if (!test_canary(&cbuf[FUZ_avail])) { printf("compression overran output buffer: seed %u, len %d, olen %d", seed, LEN, len-1); goto _output_error; } |
|
|
|
bytes += LEN; |
|
cbytes += len; |
|
} |
|
|
|
printf("all tests completed successfully \n"); |
|
printf("compression ratio: %0.3f%%\n", (double)cbytes/bytes*100); |
|
getchar(); |
|
return 0; |
|
|
|
_output_error: |
|
getchar(); |
|
return 1; |
|
}
|
|
|