2 fuzzer.c - Fuzzer test tool for LZ4
\r
3 Copyright (C) Yann Collet - Andrew Mahone 2012-2013
\r
4 Code started by Andrew Mahone, modified by Yann Collet
\r
7 This program is free software; you can redistribute it and/or modify
\r
8 it under the terms of the GNU General Public License as published by
\r
9 the Free Software Foundation; either version 2 of the License, or
\r
10 (at your option) any later version.
\r
12 This program is distributed in the hope that it will be useful,
\r
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
\r
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
\r
15 GNU General Public License for more details.
\r
17 You should have received a copy of the GNU General Public License along
\r
18 with this program; if not, write to the Free Software Foundation, Inc.,
\r
19 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
\r
21 You can contact the author at :
\r
22 - LZ4 homepage : http://fastcompression.blogspot.com/p/lz4.html
\r
23 - LZ4 source repository : http://code.google.com/p/lz4/
\r
26 //**************************************
\r
27 // Remove Visual warning messages
\r
28 //**************************************
\r
29 #define _CRT_SECURE_NO_WARNINGS // fgets
\r
32 //**************************************
\r
34 //**************************************
\r
36 #include <stdio.h> // fgets, sscanf
\r
37 #include <sys/timeb.h> // timeb
\r
42 //**************************************
\r
44 //**************************************
\r
45 #define NB_ATTEMPTS (1<<17)
\r
46 #define LEN ((1<<15))
\r
48 #define NUM_SEQ (1 << SEQ_POW)
\r
49 #define SEQ_MSK ((NUM_SEQ) - 1)
\r
50 #define MOD_SEQ(x) ((((x) >> 8) & 255) == 0)
\r
51 #define NEW_SEQ(x) ((((x) >> 10) %10) == 0)
\r
52 #define PAGE_SIZE 4096
\r
53 #define ROUND_PAGE(x) (((x) + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1))
\r
54 #define PRIME1 2654435761U
\r
55 #define PRIME2 2246822519U
\r
56 #define PRIME3 3266489917U
\r
59 //*********************************************************
\r
61 //*********************************************************
\r
62 static int FUZ_GetMilliStart()
\r
67 nCount = (int) (tb.millitm + (tb.time & 0xfffff) * 1000);
\r
72 static int FUZ_GetMilliSpan( int nTimeStart )
\r
74 int nSpan = FUZ_GetMilliStart() - nTimeStart;
\r
76 nSpan += 0x100000 * 1000;
\r
81 unsigned int FUZ_rand(unsigned int* src)
\r
83 *src = ((*src) * PRIME1) + PRIME2;
\r
88 int test_canary(unsigned char *buf)
\r
91 for (i = 0; i < 2048; i++)
\r
92 if (buf[i] != buf[i + 2048])
\r
98 int FUZ_SecurityTest()
\r
104 printf("Overflow test (issue 52)...");
\r
105 input = (char*) malloc (20<<20);
\r
106 output = (char*) malloc (20<<20);
\r
110 for(i = 3; i < 16840000; i++)
\r
112 r = LZ4_decompress_fast(input, output, 20<<20);
\r
116 printf(" Passed (return = %i < 0)\n",r);
\r
121 //int main(int argc, char *argv[]) {
\r
123 unsigned long long bytes = 0;
\r
124 unsigned long long cbytes = 0;
\r
125 unsigned long long hcbytes = 0;
\r
126 unsigned char buf[LEN];
\r
127 unsigned char testOut[LEN+1];
\r
128 # define FUZ_max LZ4_COMPRESSBOUND(LEN)
\r
129 # define FUZ_avail ROUND_PAGE(FUZ_max)
\r
130 const int off_full = FUZ_avail - FUZ_max;
\r
131 unsigned char cbuf[FUZ_avail + PAGE_SIZE];
\r
132 unsigned int seed, randState, cur_seq=PRIME3, seeds[NUM_SEQ], timestamp=FUZ_GetMilliStart();
\r
133 int i, j, k, ret, len, lenHC, attemptNb;
\r
134 char userInput[30] = {0};
\r
135 # define FUZ_CHECKTEST(cond, message) testNb++; if (cond) { printf("Test %i : %s : seed %u, cycle %u \n", testNb, message, seed, attemptNb); goto _output_error; }
\r
137 printf("starting LZ4 fuzzer\n");
\r
138 printf("Select an Initialisation number (default : random) : ");
\r
140 if ( fgets(userInput, sizeof userInput, stdin) )
\r
142 if ( sscanf(userInput, "%d", &seed) == 1 ) {}
\r
143 else seed = FUZ_GetMilliSpan(timestamp);
\r
145 printf("Seed = %u\n", seed);
\r
148 FUZ_SecurityTest();
\r
150 for (i = 0; i < 2048; i++)
\r
151 cbuf[FUZ_avail + i] = cbuf[FUZ_avail + 2048 + i] = FUZ_rand(&randState) >> 16;
\r
153 for (attemptNb = 0; attemptNb < NB_ATTEMPTS; attemptNb++)
\r
157 printf("\r%7i /%7i\r", attemptNb, NB_ATTEMPTS);
\r
159 for (j = 0; j < NUM_SEQ; j++) {
\r
160 seeds[j] = FUZ_rand(&randState) << 8;
\r
161 seeds[j] ^= (FUZ_rand(&randState) >> 8) & 65535;
\r
163 for (j = 0; j < LEN; j++) {
\r
164 k = FUZ_rand(&randState);
\r
165 if (j == 0 || NEW_SEQ(k))
\r
166 cur_seq = seeds[(FUZ_rand(&randState) >> 16) & SEQ_MSK];
\r
168 k = (FUZ_rand(&randState) >> 16) & SEQ_MSK;
\r
169 seeds[k] = FUZ_rand(&randState) << 8;
\r
170 seeds[k] ^= (FUZ_rand(&randState) >> 8) & 65535;
\r
172 buf[j] = FUZ_rand(&cur_seq) >> 16;
\r
175 // Test compression HC
\r
176 ret = LZ4_compressHC_limitedOutput((const char*)buf, (char*)&cbuf[off_full], LEN, FUZ_max);
\r
177 FUZ_CHECKTEST(ret==0, "HC compression failed despite sufficient space");
\r
180 // Test compression
\r
181 ret = LZ4_compress_limitedOutput((const char*)buf, (char*)&cbuf[off_full], LEN, FUZ_max);
\r
182 FUZ_CHECKTEST(ret==0, "compression failed despite sufficient space");
\r
185 // Test decoding with output size being exactly what's necessary => must work
\r
186 ret = LZ4_decompress_fast((char*)&cbuf[off_full], (char*)testOut, LEN);
\r
187 FUZ_CHECKTEST(ret<0, "decompression failed despite correct space");
\r
189 // Test decoding with one byte missing => must fail
\r
190 ret = LZ4_decompress_fast((char*)&cbuf[off_full], (char*)testOut, LEN-1);
\r
191 FUZ_CHECKTEST(ret>=0, "decompression should have failed, due to Output Size being too small");
\r
193 // Test decoding with one byte too much => must fail
\r
194 ret = LZ4_decompress_fast((char*)&cbuf[off_full], (char*)testOut, LEN+1);
\r
195 FUZ_CHECKTEST(ret>=0, "decompression should have failed, due to Output Size being too large");
\r
197 // Test decoding with enough output size => must work
\r
198 ret = LZ4_decompress_safe((char*)&cbuf[off_full], (char*)testOut, len, LEN+1);
\r
199 FUZ_CHECKTEST(ret<0, "decompression failed despite sufficient space");
\r
201 // Test decoding with output size being exactly what's necessary => must work
\r
202 ret = LZ4_decompress_safe((char*)&cbuf[off_full], (char*)testOut, len, LEN);
\r
203 FUZ_CHECKTEST(ret<0, "decompression failed despite sufficient space");
\r
205 // Test decoding with output size being one byte too short => must fail
\r
206 ret = LZ4_decompress_safe((char*)&cbuf[off_full], (char*)testOut, len, LEN-1);
\r
207 FUZ_CHECKTEST(ret>=0, "LZ4_decompress_safe should have failed, due to Output Size being one byte too short");
\r
209 // Test decoding with input size being one byte too short => must fail
\r
210 ret = LZ4_decompress_safe((char*)&cbuf[off_full], (char*)testOut, len-1, LEN);
\r
211 FUZ_CHECKTEST(ret>=0, "LZ4_decompress_safe should have failed, due to input size being one byte too short");
\r
213 // Test decoding with input size being one byte too large => must fail
\r
214 ret = LZ4_decompress_safe((char*)&cbuf[off_full], (char*)testOut, len+1, LEN);
\r
215 FUZ_CHECKTEST(ret>=0, "decompression should have failed, due to input size being too large");
\r
216 //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; }
\r
218 // Test partial decoding with target output size being max/2 => must work
\r
219 ret = LZ4_decompress_safe_partial((char*)&cbuf[off_full], (char*)testOut, len, LEN/2, LEN);
\r
220 FUZ_CHECKTEST(ret<0, "partial decompression failed despite sufficient space");
\r
222 // Test partial decoding with target output size being just below max => must work
\r
223 ret = LZ4_decompress_safe_partial((char*)&cbuf[off_full], (char*)testOut, len, LEN-3, LEN);
\r
224 FUZ_CHECKTEST(ret<0, "partial decompression failed despite sufficient space");
\r
226 // Test compression with output size being exactly what's necessary (should work)
\r
227 ret = LZ4_compress_limitedOutput((const char*)buf, (char*)&cbuf[FUZ_avail-len], LEN, len);
\r
228 FUZ_CHECKTEST(!test_canary(&cbuf[FUZ_avail]), "compression overran output buffer");
\r
229 FUZ_CHECKTEST(ret==0, "compression failed despite sufficient space");
\r
231 // Test HC compression with output size being exactly what's necessary (should work)
\r
232 ret = LZ4_compressHC_limitedOutput((const char*)buf, (char*)&cbuf[FUZ_avail-len], LEN, lenHC);
\r
233 FUZ_CHECKTEST(ret==0, "HC compression failed despite sufficient space");
\r
235 // Test compression with just one missing byte into output buffer => must fail
\r
236 ret = LZ4_compress_limitedOutput((const char*)buf, (char*)&cbuf[FUZ_avail-(len-1)], LEN, len-1);
\r
237 FUZ_CHECKTEST(ret, "compression overran output buffer");
\r
238 FUZ_CHECKTEST(!test_canary(&cbuf[FUZ_avail]), "compression overran output buffer");
\r
240 // Test HC compression with just one missing byte into output buffer => must fail
\r
241 ret = LZ4_compressHC_limitedOutput((const char*)buf, (char*)&cbuf[FUZ_avail-(len-1)], LEN, lenHC-1);
\r
242 FUZ_CHECKTEST(ret, "HC compression overran output buffer");
\r
247 FUZ_rand(&randState);
\r
250 printf("all tests completed successfully \n");
\r
251 printf("compression ratio: %0.3f%%\n", (double)cbytes/bytes*100);
\r
252 printf("HC compression ratio: %0.3f%%\n", (double)hcbytes/bytes*100);
\r