1 /*
2 fuzzer.c - Fuzzer test tool for Lizard
3 Copyright (C) Yann Collet 2012-2016
4 Copyright (C) Przemyslaw Skibinski 2016-2017
5
6 GPL v2 License
7
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 2 of the License, or
11 (at your option) any later version.
12
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
17
18 You should have received a copy of the GNU General Public License along
19 with this program; if not, write to the Free Software Foundation, Inc.,
20 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
21
22 You can contact the author at :
23 - Lizard source repo : https://github.com/inikep/lizard
24 */
25
26 /*-************************************
27 * Compiler options
28 **************************************/
29 #ifdef _MSC_VER /* Visual Studio */
30 # define _CRT_SECURE_NO_WARNINGS /* fgets */
31 # pragma warning(disable : 4127) /* disable: C4127: conditional expression is constant */
32 # pragma warning(disable : 4146) /* disable: C4146: minus unsigned expression */
33 # pragma warning(disable : 4310) /* disable: C4310: constant char value > 127 */
34 #endif
35
36 /* S_ISREG & gettimeofday() are not supported by MSVC */
37 #if defined(_MSC_VER) || defined(_WIN32)
38 # define FUZ_LEGACY_TIMER 1
39 #endif
40
41
42 /*-************************************
43 * Includes
44 **************************************/
45 #include <stdlib.h>
46 #include <stdio.h> /* fgets, sscanf */
47 #include <string.h> /* strcmp */
48 #include <time.h> /* clock_t, clock, CLOCKS_PER_SEC */
49 #include "lizard_compress.h" /* LIZARD_VERSION_STRING */
50 #include "lizard_decompress.h"
51 #include "lizard_common.h"
52 #define XXH_STATIC_LINKING_ONLY
53 #include "xxhash/xxhash.h"
54
55
56
57 /*-************************************
58 * Constants
59 **************************************/
60 #define NB_ATTEMPTS (1<<16)
61 #define COMPRESSIBLE_NOISE_LENGTH (1 << 21)
62 #define FUZ_MAX_BLOCK_SIZE (1 << 17)
63 #define FUZ_MAX_DICT_SIZE (1 << 15)
64 #define FUZ_COMPRESSIBILITY_DEFAULT 60
65 #define PRIME1 2654435761U
66 #define PRIME2 2246822519U
67 #define PRIME3 3266489917U
68
69
70 /*-***************************************
71 * Macros
72 *****************************************/
73 #define DISPLAY(...) fprintf(stderr, __VA_ARGS__)
74 #define DISPLAYLEVEL(l, ...) if (g_displayLevel>=l) { DISPLAY(__VA_ARGS__); }
75 static int g_displayLevel = 2;
76 static const clock_t g_refreshRate = CLOCKS_PER_SEC * 25 / 100;
77 static clock_t g_time = 0;
78
79
80 /*-*******************************************************
81 * Fuzzer functions
82 *********************************************************/
FUZ_GetClockSpan(clock_t clockStart)83 static clock_t FUZ_GetClockSpan(clock_t clockStart)
84 {
85 return clock() - clockStart; /* works even if overflow; max span ~ 30mn */
86 }
87
FUZ_rotl32(U32 u32,U32 nbBits)88 static U32 FUZ_rotl32(U32 u32, U32 nbBits)
89 {
90 return ((u32 << nbBits) | (u32 >> (32 - nbBits)));
91 }
92
FUZ_rand(U32 * src)93 static U32 FUZ_rand(U32* src)
94 {
95 U32 rand32 = *src;
96 rand32 *= PRIME1;
97 rand32 ^= PRIME2;
98 rand32 = FUZ_rotl32(rand32, 13);
99 *src = rand32;
100 return rand32;
101 }
102
103
104 #define FUZ_RAND15BITS ((FUZ_rand(seed) >> 3) & 32767)
105 #define FUZ_RANDLENGTH ( ((FUZ_rand(seed) >> 7) & 3) ? (FUZ_rand(seed) % 15) : (FUZ_rand(seed) % 510) + 15)
FUZ_fillCompressibleNoiseBuffer(void * buffer,size_t bufferSize,double proba,U32 * seed)106 static void FUZ_fillCompressibleNoiseBuffer(void* buffer, size_t bufferSize, double proba, U32* seed)
107 {
108 BYTE* BBuffer = (BYTE*)buffer;
109 size_t pos = 0;
110 U32 P32 = (U32)(32768 * proba);
111
112 /* First Bytes */
113 while (pos < 20)
114 BBuffer[pos++] = (BYTE)(FUZ_rand(seed));
115
116 while (pos < bufferSize)
117 {
118 /* Select : Literal (noise) or copy (within 64K) */
119 if (FUZ_RAND15BITS < P32)
120 {
121 /* Copy (within 64K) */
122 size_t match, d;
123 size_t length = FUZ_RANDLENGTH + 4;
124 size_t offset = FUZ_RAND15BITS + 1;
125 while (offset > pos) offset >>= 1;
126 d = pos + length;
127 while (d > bufferSize) d = bufferSize;
128 match = pos - offset;
129 while (pos < d) BBuffer[pos++] = BBuffer[match++];
130 }
131 else
132 {
133 /* Literal (noise) */
134 size_t d;
135 size_t length = FUZ_RANDLENGTH;
136 d = pos + length;
137 if (d > bufferSize) d = bufferSize;
138 while (pos < d) BBuffer[pos++] = (BYTE)(FUZ_rand(seed) >> 5);
139 }
140 }
141 }
142
143
144 #define MAX_NB_BUFF_I134 150
145 #define BLOCKSIZE_I134 (32 MB)
146 /*! FUZ_AddressOverflow() :
147 * Aggressively pushes memory allocation limits,
148 * and generates patterns which create address space overflow.
149 * only possible in 32-bits mode */
FUZ_AddressOverflow(U32 * seed)150 static int FUZ_AddressOverflow(U32* seed)
151 {
152 char* buffers[MAX_NB_BUFF_I134];
153 int i, nbBuff=0;
154 int highAddress = 0;
155
156 DISPLAY("Overflow tests : ");
157
158 /* Only possible in 32-bits */
159 /* if (sizeof(void*)==8)
160 {
161 DISPLAY("64 bits mode : no overflow \n");
162 fflush(stdout);
163 return 0;
164 }*/
165
166 buffers[0] = (char*)malloc(BLOCKSIZE_I134);
167 buffers[1] = (char*)malloc(BLOCKSIZE_I134);
168 if ((!buffers[0]) || (!buffers[1])) {
169 DISPLAY("not enough memory for tests \n");
170 return 0;
171 }
172
173 for (nbBuff=2; nbBuff < MAX_NB_BUFF_I134; nbBuff++) {
174 DISPLAY("%3i \b\b\b\b", nbBuff);
175 buffers[nbBuff] = (char*)malloc(BLOCKSIZE_I134);
176 if (buffers[nbBuff]==NULL) goto _endOfTests;
177
178 if (((size_t)buffers[nbBuff] > (size_t)0x80000000) && (!highAddress)) {
179 DISPLAY("high address detected : ");
180 fflush(stdout);
181 highAddress=1;
182 }
183
184 { int const nbOf255 = 1 + (FUZ_rand(seed) % (BLOCKSIZE_I134-1));
185 char* const input = buffers[nbBuff-1];
186 char* output = buffers[nbBuff];
187 int r;
188 BYTE cLevel = LIZARD_MIN_CLEVEL + (FUZ_rand(seed) % (1+LIZARD_MAX_CLEVEL-LIZARD_MIN_CLEVEL));
189 for(i = 5; i < nbOf255; i++) input[i] = (char)0xff;
190 for(i = 5; i < nbOf255; i+=(FUZ_rand(seed) % 128)) input[i] = (BYTE)(FUZ_rand(seed)%256);
191
192 input[0] = (char)cLevel; /* Compression Level */
193 input[1] = (char)0xF0; /* Literal length overflow */
194 input[2] = (char)0xFF;
195 input[3] = (char)0xFF;
196 input[4] = (char)0xFF;
197 r = Lizard_decompress_safe(input, output, nbOf255, BLOCKSIZE_I134);
198 if (r>0 && r<nbOf255) goto _overflowError;
199
200 input[0] = (char)cLevel; /* Compression Level */
201 input[1] = (char)0x1F; /* Match length overflow */
202 input[2] = (char)0x01;
203 input[3] = (char)0x01;
204 input[4] = (char)0x00;
205 r = Lizard_decompress_safe(input, output, nbOf255, BLOCKSIZE_I134);
206 if (r>0 && r<nbOf255) goto _overflowError;
207
208 output = buffers[nbBuff-2]; /* Reverse in/out pointer order */
209 input[0] = (char)cLevel; /* Compression Level */
210 input[1] = (char)0xF0; /* Literal length overflow */
211 input[2] = (char)0xFF;
212 input[3] = (char)0xFF;
213 input[4] = (char)0xFF;
214 r = Lizard_decompress_safe(input, output, nbOf255, BLOCKSIZE_I134);
215 if (r>0 && r<nbOf255) goto _overflowError;
216
217 input[0] = (char)cLevel; /* Compression Level */
218 input[1] = (char)0x1F; /* Match length overflow */
219 input[2] = (char)0x01;
220 input[3] = (char)0x01;
221 input[4] = (char)0x00;
222 r = Lizard_decompress_safe(input, output, nbOf255, BLOCKSIZE_I134);
223 if (r>0 && r<nbOf255) goto _overflowError;
224 }
225 }
226
227 _endOfTests:
228 for (i=0 ; i<nbBuff; i++) free(buffers[i]);
229 if (!highAddress) DISPLAY("high address not possible \n");
230 else DISPLAY("all overflows correctly detected \n");
231 return 0;
232
233 _overflowError:
234 DISPLAY("Address space overflow error !! \n");
235 exit(1);
236 }
237
238
FUZ_displayUpdate(unsigned testNb)239 static void FUZ_displayUpdate(unsigned testNb)
240 {
241 if ((FUZ_GetClockSpan(g_time) > g_refreshRate) | (g_displayLevel>=3)) {
242 g_time = clock();
243 DISPLAY("\r%5u ", testNb);
244 if (g_displayLevel>=3) fflush(stdout);
245 }
246 }
247
248
249 /*! FUZ_findDiff() :
250 * find the first different byte between buff1 and buff2.
251 * presumes buff1 != buff2.
252 * presumes a difference exists before end of either buffer.
253 * Typically invoked after a checksum mismatch.
254 */
FUZ_findDiff(const void * buff1,const void * buff2)255 static void FUZ_findDiff(const void* buff1, const void* buff2)
256 {
257 const BYTE* const b1 = (const BYTE*)buff1;
258 const BYTE* const b2 = (const BYTE*)buff2;
259 size_t i=0;
260 while (b1[i]==b2[i]) i++;
261 DISPLAY("Wrong Byte at position %u\n", (unsigned)i);
262 }
263
264
FUZ_test(U32 seed,U32 nbCycles,const U32 startCycle,const double compressibility,U32 duration_s)265 static int FUZ_test(U32 seed, U32 nbCycles, const U32 startCycle, const double compressibility, U32 duration_s)
266 {
267 unsigned long long bytes = 0;
268 unsigned long long cbytes = 0;
269 unsigned long long hcbytes = 0;
270 unsigned long long ccbytes = 0;
271 void* CNBuffer;
272 char* compressedBuffer;
273 char* decodedBuffer;
274 # define FUZ_max LIZARD_COMPRESSBOUND(LEN)
275 int ret;
276 unsigned cycleNb;
277 # define FUZ_CHECKTEST(cond, ...) if (cond) { printf("Test %u : ", testNb); printf(__VA_ARGS__); \
278 printf(" (seed %u, cycle %u) \n", seed, cycleNb); goto _output_error; }
279 # define FUZ_DISPLAYTEST { testNb++; g_displayLevel<3 ? 0 : printf("%2u\b\b", testNb); if (g_displayLevel==4) fflush(stdout); }
280 void* stateLizard = malloc(Lizard_sizeofState_MinLevel());
281 void* stateLizardHC = malloc(Lizard_sizeofState(0));
282 Lizard_stream_t* Lizarddict;
283 Lizard_stream_t* Lizard_streamHCPtr;
284 U32 crcOrig, crcCheck;
285 U32 coreRandState = seed;
286 U32 randState = coreRandState ^ PRIME3;
287 int result = 0;
288 clock_t const clockStart = clock();
289 clock_t const clockDuration = (clock_t)duration_s * CLOCKS_PER_SEC;
290
291
292 /* init */
293 Lizard_streamHCPtr = Lizard_createStream(0);
294 Lizarddict = Lizard_createStream_MinLevel();
295
296 /* Create compressible test buffer */
297 CNBuffer = malloc(COMPRESSIBLE_NOISE_LENGTH);
298 compressedBuffer = (char*)malloc(Lizard_compressBound(FUZ_MAX_BLOCK_SIZE));
299 decodedBuffer = (char*)malloc(FUZ_MAX_DICT_SIZE + FUZ_MAX_BLOCK_SIZE);
300
301 if (!stateLizard || !stateLizardHC || !Lizarddict || !Lizard_streamHCPtr || !CNBuffer || !compressedBuffer || !decodedBuffer) goto _output_error;
302
303 FUZ_fillCompressibleNoiseBuffer(CNBuffer, COMPRESSIBLE_NOISE_LENGTH, compressibility, &randState);
304
305 /* move to startCycle */
306 for (cycleNb = 0; cycleNb < startCycle; cycleNb++) {
307 (void)FUZ_rand(&coreRandState);
308
309 if (0) { /* some problems can be related to dictionary re-use; in this case, enable this loop */
310 int dictSize, blockSize, blockStart;
311 char* dict;
312 char* block;
313 FUZ_displayUpdate(cycleNb);
314 randState = coreRandState ^ PRIME3;
315 blockSize = FUZ_rand(&randState) % FUZ_MAX_BLOCK_SIZE;
316 blockStart = FUZ_rand(&randState) % (COMPRESSIBLE_NOISE_LENGTH - blockSize);
317 dictSize = FUZ_rand(&randState) % FUZ_MAX_DICT_SIZE;
318 if (dictSize > blockStart) dictSize = blockStart;
319 block = ((char*)CNBuffer) + blockStart;
320 dict = block - dictSize;
321 Lizard_loadDict(Lizarddict, dict, dictSize);
322 Lizard_compress_continue(Lizarddict, block, compressedBuffer, blockSize, Lizard_compressBound(blockSize));
323 Lizard_loadDict(Lizarddict, dict, dictSize);
324 Lizard_compress_continue(Lizarddict, block, compressedBuffer, blockSize, Lizard_compressBound(blockSize));
325 Lizard_loadDict(Lizarddict, dict, dictSize);
326 Lizard_compress_continue(Lizarddict, block, compressedBuffer, blockSize, Lizard_compressBound(blockSize));
327 } }
328
329 /* Main test loop */
330 for (cycleNb = startCycle; (cycleNb < nbCycles) || (FUZ_GetClockSpan(clockStart) < clockDuration) ; cycleNb++) {
331 U32 testNb = 0;
332 char* dict;
333 char* block;
334 int dictSize, blockSize, blockStart, compressedSize, HCcompressedSize;
335 int blockContinueCompressedSize;
336
337 FUZ_displayUpdate(cycleNb);
338 (void)FUZ_rand(&coreRandState);
339 randState = coreRandState ^ PRIME3;
340
341 /* Select block to test */
342 blockSize = (FUZ_rand(&randState) % (FUZ_MAX_BLOCK_SIZE-1)) + 1;
343 blockStart = FUZ_rand(&randState) % (COMPRESSIBLE_NOISE_LENGTH - blockSize);
344 dictSize = FUZ_rand(&randState) % FUZ_MAX_DICT_SIZE;
345 if (dictSize > blockStart) dictSize = blockStart;
346 block = ((char*)CNBuffer) + blockStart;
347 dict = block - dictSize;
348
349 /* Compression tests */
350
351 /* Test compression HC */
352 FUZ_DISPLAYTEST;
353 ret = Lizard_compress(block, compressedBuffer, blockSize, Lizard_compressBound(blockSize), 0);
354 FUZ_CHECKTEST(ret==0, "Lizard_compress() failed");
355 HCcompressedSize = ret;
356
357 /* Test compression HC using external state */
358 FUZ_DISPLAYTEST;
359 ret = Lizard_compress_extState(stateLizardHC, block, compressedBuffer, blockSize, Lizard_compressBound(blockSize), 0);
360 FUZ_CHECKTEST(ret==0, "Lizard_compress_extState() failed");
361
362 /* Test compression using external state */
363 FUZ_DISPLAYTEST;
364 ret = Lizard_compress_extState_MinLevel(stateLizard, block, compressedBuffer, blockSize, Lizard_compressBound(blockSize));
365 FUZ_CHECKTEST(ret==0, "Lizard_compress_extState_MinLevel(1) failed");
366
367 /* Test compression */
368 FUZ_DISPLAYTEST;
369 ret = Lizard_compress_MinLevel(block, compressedBuffer, blockSize, Lizard_compressBound(blockSize));
370 FUZ_CHECKTEST(ret==0, "Lizard_compress_MinLevel() failed");
371 compressedSize = ret;
372
373 /* Decompression tests */
374
375 crcOrig = XXH32(block, blockSize, 0);
376
377 /* Test decoding with output size exactly what's necessary => must work */
378 FUZ_DISPLAYTEST;
379 decodedBuffer[blockSize] = 0;
380 ret = Lizard_decompress_safe(compressedBuffer, decodedBuffer, compressedSize, blockSize);
381 FUZ_CHECKTEST(ret<0, "Lizard_decompress_safe failed despite sufficient space");
382 FUZ_CHECKTEST(ret!=blockSize, "Lizard_decompress_safe did not regenerate original data");
383 FUZ_CHECKTEST(decodedBuffer[blockSize], "Lizard_decompress_safe overrun specified output buffer size");
384 crcCheck = XXH32(decodedBuffer, blockSize, 0);
385 FUZ_CHECKTEST(crcCheck!=crcOrig, "Lizard_decompress_safe corrupted decoded data");
386
387 // Test decoding with more than enough output size => must work
388 FUZ_DISPLAYTEST;
389 decodedBuffer[blockSize] = 0;
390 decodedBuffer[blockSize+1] = 0;
391 ret = Lizard_decompress_safe(compressedBuffer, decodedBuffer, compressedSize, blockSize+1);
392 FUZ_CHECKTEST(ret<0, "Lizard_decompress_safe failed despite amply sufficient space");
393 FUZ_CHECKTEST(ret!=blockSize, "Lizard_decompress_safe did not regenerate original data");
394 //FUZ_CHECKTEST(decodedBuffer[blockSize], "Lizard_decompress_safe wrote more than (unknown) target size"); // well, is that an issue ?
395 FUZ_CHECKTEST(decodedBuffer[blockSize+1], "Lizard_decompress_safe overrun specified output buffer size");
396 crcCheck = XXH32(decodedBuffer, blockSize, 0);
397 FUZ_CHECKTEST(crcCheck!=crcOrig, "Lizard_decompress_safe corrupted decoded data");
398
399 // Test decoding with output size being one byte too short => must fail
400 FUZ_DISPLAYTEST;
401 decodedBuffer[blockSize-1] = 0;
402 ret = Lizard_decompress_safe(compressedBuffer, decodedBuffer, compressedSize, blockSize-1);
403 FUZ_CHECKTEST(ret>=0, "Lizard_decompress_safe should have failed, due to Output Size being one byte too short");
404 FUZ_CHECKTEST(decodedBuffer[blockSize-1], "Lizard_decompress_safe overrun specified output buffer size");
405
406 // Test decoding with output size being 10 bytes too short => must fail
407 FUZ_DISPLAYTEST;
408 if (blockSize>10)
409 {
410 decodedBuffer[blockSize-10] = 0;
411 ret = Lizard_decompress_safe(compressedBuffer, decodedBuffer, compressedSize, blockSize-10);
412 FUZ_CHECKTEST(ret>=0, "Lizard_decompress_safe should have failed, due to Output Size being 10 bytes too short");
413 FUZ_CHECKTEST(decodedBuffer[blockSize-10], "Lizard_decompress_safe overrun specified output buffer size");
414 }
415
416 // Test decoding with input size being one byte too short => must fail
417 FUZ_DISPLAYTEST;
418 ret = Lizard_decompress_safe(compressedBuffer, decodedBuffer, compressedSize-1, blockSize);
419 FUZ_CHECKTEST(ret>=0, "Lizard_decompress_safe should have failed, due to input size being one byte too short (blockSize=%i, ret=%i, compressedSize=%i)", blockSize, ret, compressedSize);
420
421 // Test decoding with input size being one byte too large => must fail
422 FUZ_DISPLAYTEST;
423 decodedBuffer[blockSize] = 0;
424 compressedBuffer[compressedSize] = 0; /* valgrind */
425 ret = Lizard_decompress_safe(compressedBuffer, decodedBuffer, compressedSize+1, blockSize);
426 FUZ_CHECKTEST(ret>=0, "Lizard_decompress_safe should have failed, due to input size being too large");
427 FUZ_CHECKTEST(decodedBuffer[blockSize], "Lizard_decompress_safe overrun specified output buffer size");
428
429 // Test partial decoding with target output size being max/2 => must work
430 FUZ_DISPLAYTEST;
431 ret = Lizard_decompress_safe_partial(compressedBuffer, decodedBuffer, compressedSize, blockSize/2, blockSize);
432 FUZ_CHECKTEST(ret<0, "Lizard_decompress_safe_partial failed despite sufficient space");
433
434 // Test partial decoding with target output size being just below max => must work
435 FUZ_DISPLAYTEST;
436 ret = Lizard_decompress_safe_partial(compressedBuffer, decodedBuffer, compressedSize, blockSize-3, blockSize);
437 FUZ_CHECKTEST(ret<0, "Lizard_decompress_safe_partial failed despite sufficient space");
438
439 /* Test Compression with limited output size */
440
441 /* Test compression with output size being exactly what's necessary (should work) */
442 FUZ_DISPLAYTEST;
443 ret = Lizard_compress_MinLevel(block, compressedBuffer, blockSize, compressedSize);
444 FUZ_CHECKTEST(ret==0, "Lizard_compress_MinLevel() failed despite sufficient space");
445
446 /* Test compression with output size being exactly what's necessary and external state (should work) */
447 FUZ_DISPLAYTEST;
448 ret = Lizard_compress_extState_MinLevel(stateLizard, block, compressedBuffer, blockSize, compressedSize);
449 FUZ_CHECKTEST(ret==0, "Lizard_compress_extState_MinLevel() failed despite sufficient space");
450
451 /* Test HC compression with output size being exactly what's necessary (should work) */
452 FUZ_DISPLAYTEST;
453 ret = Lizard_compress(block, compressedBuffer, blockSize, HCcompressedSize, 0);
454 FUZ_CHECKTEST(ret==0, "Lizard_compress() (limitedOutput) failed despite sufficient space");
455
456 /* Test HC compression with output size being exactly what's necessary (should work) */
457 FUZ_DISPLAYTEST;
458 ret = Lizard_compress_extState(stateLizardHC, block, compressedBuffer, blockSize, HCcompressedSize, 0);
459 FUZ_CHECKTEST(ret==0, "Lizard_compress_extState() failed despite sufficient space");
460
461 /* Test compression with missing bytes into output buffer => must fail */
462 FUZ_DISPLAYTEST;
463 { int missingBytes = (FUZ_rand(&randState) % 0x3F) + 1;
464 if (missingBytes >= compressedSize) missingBytes = compressedSize-1;
465 missingBytes += !missingBytes; /* avoid special case missingBytes==0 */
466 compressedBuffer[compressedSize-missingBytes] = 0;
467 ret = Lizard_compress_MinLevel(block, compressedBuffer, blockSize, compressedSize-missingBytes);
468 FUZ_CHECKTEST(ret, "Lizard_compress_MinLevel should have failed (output buffer too small by %i byte)", missingBytes);
469 FUZ_CHECKTEST(compressedBuffer[compressedSize-missingBytes], "Lizard_compress_MinLevel overran output buffer ! (%i missingBytes)", missingBytes)
470 }
471
472 /* Test HC compression with missing bytes into output buffer => must fail */
473 FUZ_DISPLAYTEST;
474 { int missingBytes = (FUZ_rand(&randState) % 0x3F) + 1;
475 if (missingBytes >= HCcompressedSize) missingBytes = HCcompressedSize-1;
476 missingBytes += !missingBytes; /* avoid special case missingBytes==0 */
477 compressedBuffer[HCcompressedSize-missingBytes] = 0;
478 ret = Lizard_compress(block, compressedBuffer, blockSize, HCcompressedSize-missingBytes, 0);
479 FUZ_CHECKTEST(ret, "Lizard_compress(limitedOutput) should have failed (output buffer too small by %i byte)", missingBytes);
480 FUZ_CHECKTEST(compressedBuffer[HCcompressedSize-missingBytes], "Lizard_compress overran output buffer ! (%i missingBytes)", missingBytes)
481 }
482
483
484 /*-******************/
485 /* Dictionary tests */
486 /*-******************/
487
488 /* Compress using dictionary */
489 FUZ_DISPLAYTEST;
490 { Lizard_stream_t* Lizard_stream = Lizard_createStream_MinLevel();
491 FUZ_CHECKTEST(Lizard_stream==NULL, "Lizard_createStream_MinLevel() allocation failed");
492 Lizard_stream = Lizard_resetStream_MinLevel(Lizard_stream);
493 FUZ_CHECKTEST(Lizard_stream==NULL, "Lizard_resetStream_MinLevel() failed");
494 Lizard_compress_continue (Lizard_stream, dict, compressedBuffer, dictSize, Lizard_compressBound(dictSize)); /* Just to fill hash tables */
495 blockContinueCompressedSize = Lizard_compress_continue (Lizard_stream, block, compressedBuffer, blockSize, Lizard_compressBound(blockSize));
496 FUZ_CHECKTEST(blockContinueCompressedSize==0, "Lizard_compress_continue failed");
497 Lizard_freeStream(Lizard_stream);
498 }
499
500 /* Compress using External dictionary */
501 FUZ_DISPLAYTEST;
502 dict -= (FUZ_rand(&randState) & 0xF) + 1; /* Separation, so it is an ExtDict */
503 if (dict < (char*)CNBuffer) dict = (char*)CNBuffer;
504 Lizard_loadDict(Lizarddict, dict, dictSize);
505 blockContinueCompressedSize = Lizard_compress_continue(Lizarddict, block, compressedBuffer, blockSize, Lizard_compressBound(blockSize));
506 FUZ_CHECKTEST(blockContinueCompressedSize==0, "Lizard_compress_continue failed");
507
508 FUZ_DISPLAYTEST;
509 Lizard_loadDict(Lizarddict, dict, dictSize);
510 ret = Lizard_compress_continue(Lizarddict, block, compressedBuffer, blockSize, blockContinueCompressedSize-1);
511 FUZ_CHECKTEST(ret>0, "Lizard_compress_continue using ExtDict should fail : one missing byte for output buffer : %i written, %i buffer", ret, blockContinueCompressedSize);
512
513 FUZ_DISPLAYTEST;
514 Lizard_loadDict(Lizarddict, dict, dictSize);
515 ret = Lizard_compress_continue(Lizarddict, block, compressedBuffer, blockSize, blockContinueCompressedSize);
516 FUZ_CHECKTEST(ret!=blockContinueCompressedSize, "Lizard_compress_limitedOutput_compressed size is different (%i != %i)", ret, blockContinueCompressedSize);
517 FUZ_CHECKTEST(ret<=0, "Lizard_compress_continue should work : enough size available within output buffer");
518
519 FUZ_DISPLAYTEST;
520 decodedBuffer[blockSize] = 0;
521 ret = Lizard_decompress_safe_usingDict(compressedBuffer, decodedBuffer, blockContinueCompressedSize, blockSize, dict, dictSize);
522 FUZ_CHECKTEST(ret!=blockSize, "2Lizard_decompress_safe_usingDict did not regenerate original data ret[%d]!=blockSize[%d]", (int)ret, (int)blockSize);
523 FUZ_CHECKTEST(decodedBuffer[blockSize], "Lizard_decompress_safe_usingDict overrun specified output buffer size")
524 crcCheck = XXH32(decodedBuffer, blockSize, 0);
525 FUZ_CHECKTEST(crcCheck!=crcOrig, "Lizard_decompress_safe_usingDict corrupted decoded data");
526
527 FUZ_DISPLAYTEST;
528 decodedBuffer[blockSize-1] = 0;
529 ret = Lizard_decompress_safe_usingDict(compressedBuffer, decodedBuffer, blockContinueCompressedSize, blockSize-1, dict, dictSize);
530 FUZ_CHECKTEST(ret>=0, "Lizard_decompress_safe_usingDict should have failed : not enough output size (-1 byte)");
531 FUZ_CHECKTEST(decodedBuffer[blockSize-1], "Lizard_decompress_safe_usingDict overrun specified output buffer size");
532
533 FUZ_DISPLAYTEST;
534 { U32 const missingBytes = (FUZ_rand(&randState) & 0xF) + 2;
535 if ((U32)blockSize > missingBytes) {
536 decodedBuffer[blockSize-missingBytes] = 0;
537 ret = Lizard_decompress_safe_usingDict(compressedBuffer, decodedBuffer, blockContinueCompressedSize, blockSize-missingBytes, dict, dictSize);
538 FUZ_CHECKTEST(ret>=0, "Lizard_decompress_safe_usingDict should have failed : output buffer too small (-%u byte)", missingBytes);
539 FUZ_CHECKTEST(decodedBuffer[blockSize-missingBytes], "Lizard_decompress_safe_usingDict overrun specified output buffer size (-%u byte) (blockSize=%i)", missingBytes, blockSize);
540 } }
541
542 /* Compress HC using External dictionary */
543 FUZ_DISPLAYTEST;
544 dict -= (FUZ_rand(&randState) & 7); /* even bigger separation */
545 if (dict < (char*)CNBuffer) dict = (char*)CNBuffer;
546 Lizard_streamHCPtr = Lizard_resetStream (Lizard_streamHCPtr, FUZ_rand(&randState) & 0x7);
547 FUZ_CHECKTEST(Lizard_streamHCPtr==NULL, "Lizard_resetStream failed");
548 Lizard_loadDict(Lizard_streamHCPtr, dict, dictSize);
549 blockContinueCompressedSize = Lizard_compress_continue(Lizard_streamHCPtr, block, compressedBuffer, blockSize, Lizard_compressBound(blockSize));
550 FUZ_CHECKTEST(blockContinueCompressedSize==0, "Lizard_compress_continue failed");
551
552 FUZ_DISPLAYTEST;
553 Lizard_loadDict(Lizard_streamHCPtr, dict, dictSize);
554 ret = Lizard_compress_continue(Lizard_streamHCPtr, block, compressedBuffer, blockSize, blockContinueCompressedSize-1);
555 FUZ_CHECKTEST(ret>0, "Lizard_compress_continue using ExtDict should fail : one missing byte for output buffer");
556
557 FUZ_DISPLAYTEST;
558 Lizard_loadDict(Lizard_streamHCPtr, dict, dictSize);
559 ret = Lizard_compress_continue(Lizard_streamHCPtr, block, compressedBuffer, blockSize, blockContinueCompressedSize);
560 FUZ_CHECKTEST(ret!=blockContinueCompressedSize, "Lizard_compress_limitedOutput_compressed size is different (%i != %i)", ret, blockContinueCompressedSize);
561 FUZ_CHECKTEST(ret<=0, "Lizard_compress_continue should work : enough size available within output buffer");
562
563 FUZ_DISPLAYTEST;
564 decodedBuffer[blockSize] = 0;
565 ret = Lizard_decompress_safe_usingDict(compressedBuffer, decodedBuffer, blockContinueCompressedSize, blockSize, dict, dictSize);
566 FUZ_CHECKTEST(ret!=blockSize, "3Lizard_decompress_safe_usingDict did not regenerate original data ret[%d]!=blockSize[%d]", (int)ret, (int)blockSize);
567 FUZ_CHECKTEST(decodedBuffer[blockSize], "Lizard_decompress_safe_usingDict overrun specified output buffer size")
568 crcCheck = XXH32(decodedBuffer, blockSize, 0);
569 if (crcCheck!=crcOrig)
570 FUZ_findDiff(block, decodedBuffer);
571 FUZ_CHECKTEST(crcCheck!=crcOrig, "Lizard_decompress_safe_usingDict corrupted decoded data");
572
573 /* ***** End of tests *** */
574 /* Fill stats */
575 bytes += blockSize;
576 cbytes += compressedSize;
577 hcbytes += HCcompressedSize;
578 ccbytes += blockContinueCompressedSize;
579 }
580
581 if (nbCycles<=1) nbCycles = cycleNb; /* end by time */
582 bytes += !bytes; /* avoid division by 0 */
583 printf("\r%7u /%7u - ", cycleNb, nbCycles);
584 printf("all tests completed successfully \n");
585 printf("compression ratio: %0.3f%%\n", (double)cbytes/bytes*100);
586 printf("HC compression ratio: %0.3f%%\n", (double)hcbytes/bytes*100);
587 printf("ratio with dict: %0.3f%%\n", (double)ccbytes/bytes*100);
588
589 /* release memory */
590 {
591 _exit:
592 free(CNBuffer);
593 free(compressedBuffer);
594 free(decodedBuffer);
595 free(stateLizard);
596 free(stateLizardHC);
597 Lizard_freeStream(Lizard_streamHCPtr);
598 Lizard_freeStream(Lizarddict);
599 return result;
600
601 _output_error:
602 result = 1;
603 goto _exit;
604 }
605 }
606
607
608 #define testInputSize (192 KB)
609 #define testCompressedSize (128 KB)
610 #define ringBufferSize (8 KB)
611
FUZ_unitTests(U32 seed)612 static void FUZ_unitTests(U32 seed)
613 {
614 const unsigned testNb = 0;
615 const unsigned cycleNb= 0;
616 char testInput[testInputSize];
617 char testCompressed[testCompressedSize];
618 char testVerify[testInputSize];
619 char ringBuffer[ringBufferSize];
620 U32 randState = seed ^ PRIME3;
621
622 /* Init */
623 FUZ_fillCompressibleNoiseBuffer(testInput, testInputSize, 0.50, &randState);
624
625 /* 32-bits address space overflow test */
626 FUZ_AddressOverflow(&randState);
627
628 /* Lizard streaming tests */
629 { Lizard_stream_t* statePtr;
630 Lizard_stream_t* streamingState;
631 U64 crcOrig;
632 U64 crcNew;
633 int result;
634
635 /* Allocation test */
636 statePtr = Lizard_createStream_MinLevel();
637 FUZ_CHECKTEST(statePtr==NULL, "Lizard_createStream_MinLevel() allocation failed");
638 Lizard_freeStream(statePtr);
639
640 streamingState = Lizard_createStream_MinLevel();
641 FUZ_CHECKTEST(streamingState==NULL, "Lizard_createStream_MinLevel() allocation failed");
642
643 /* simple compression test */
644 crcOrig = XXH64(testInput, testCompressedSize, 0);
645 streamingState = Lizard_resetStream_MinLevel(streamingState);
646 FUZ_CHECKTEST(streamingState==NULL, "Lizard_resetStream_MinLevel() failed");
647 result = Lizard_compress_continue(streamingState, testInput, testCompressed, testCompressedSize, testCompressedSize-1);
648 FUZ_CHECKTEST(result==0, "Lizard_compress_continue() compression failed");
649
650 result = Lizard_decompress_safe(testCompressed, testVerify, result, testCompressedSize);
651 FUZ_CHECKTEST(result!=(int)testCompressedSize, "Lizard_decompress_safe() decompression failed Level 1 (result=%d testCompressedSize=%d)", (int)result, (int)testCompressedSize);
652 crcNew = XXH64(testVerify, testCompressedSize, 0);
653 FUZ_CHECKTEST(crcOrig!=crcNew, "Lizard_decompress_safe() decompression corruption");
654
655 /* ring buffer test */
656 { XXH64_state_t xxhOrig;
657 XXH64_state_t xxhNew;
658 Lizard_streamDecode_t decodeState;
659 const U32 maxMessageSizeLog = 10;
660 const U32 maxMessageSizeMask = (1<<maxMessageSizeLog) - 1;
661 U32 messageSize = (FUZ_rand(&randState) & maxMessageSizeMask) + 1;
662 U32 iNext = 0;
663 U32 rNext = 0;
664 U32 dNext = 0;
665 const U32 dBufferSize = ringBufferSize + maxMessageSizeMask;
666
667 XXH64_reset(&xxhOrig, 0);
668 XXH64_reset(&xxhNew, 0);
669 streamingState = Lizard_resetStream_MinLevel(streamingState);
670 FUZ_CHECKTEST(streamingState==NULL, "Lizard_resetStream_MinLevel() failed");
671 Lizard_setStreamDecode(&decodeState, NULL, 0);
672
673 while (iNext + messageSize < testCompressedSize) {
674 XXH64_update(&xxhOrig, testInput + iNext, messageSize);
675 crcOrig = XXH64_digest(&xxhOrig);
676
677 memcpy (ringBuffer + rNext, testInput + iNext, messageSize);
678 result = Lizard_compress_continue(streamingState, ringBuffer + rNext, testCompressed, messageSize, testCompressedSize-ringBufferSize);
679 FUZ_CHECKTEST(result==0, "Lizard_compress_continue() compression failed");
680
681 result = Lizard_decompress_safe_continue(&decodeState, testCompressed, testVerify + dNext, result, messageSize);
682 FUZ_CHECKTEST(result!=(int)messageSize, "ringBuffer : Lizard_decompress_safe() test failed");
683
684 XXH64_update(&xxhNew, testVerify + dNext, messageSize);
685 crcNew = XXH64_digest(&xxhNew);
686 FUZ_CHECKTEST(crcOrig!=crcNew, "Lizard_decompress_safe() decompression corruption");
687
688 /* prepare next message */
689 iNext += messageSize;
690 rNext += messageSize;
691 dNext += messageSize;
692 messageSize = (FUZ_rand(&randState) & maxMessageSizeMask) + 1;
693 if (rNext + messageSize > ringBufferSize) rNext = 0;
694 if (dNext + messageSize > dBufferSize) dNext = 0;
695 }
696 }
697 Lizard_freeStream(streamingState);
698 }
699
700 /* Lizard streaming tests */
701 { Lizard_stream_t* streamPtr;
702 U64 crcOrig;
703 U64 crcNew;
704 int result;
705
706 /* Allocation test */
707 streamPtr = Lizard_createStream(0);
708 FUZ_CHECKTEST(streamPtr==NULL, "Lizard_createStream() allocation failed");
709
710 /* simple HC compression test */
711 crcOrig = XXH64(testInput, testCompressedSize, 0);
712 streamPtr = Lizard_resetStream(streamPtr, 0);
713 FUZ_CHECKTEST(streamPtr==NULL, "Lizard_resetStream failed");
714 result = Lizard_compress_continue(streamPtr, testInput, testCompressed, testCompressedSize, testCompressedSize-1);
715 FUZ_CHECKTEST(result==0, "Lizard_compress_continue() compression failed");
716
717 result = Lizard_decompress_safe(testCompressed, testVerify, result, testCompressedSize);
718 FUZ_CHECKTEST(result!=(int)testCompressedSize, "Lizard_decompress_safe() decompression failed Level 0 (result=%d testCompressedSize=%d)", (int)result, (int)testCompressedSize);
719 crcNew = XXH64(testVerify, testCompressedSize, 0);
720 FUZ_CHECKTEST(crcOrig!=crcNew, "Lizard_decompress_safe() decompression corruption");
721
722 /* simple dictionary HC compression test */
723 crcOrig = XXH64(testInput + testInputSize - testCompressedSize, testCompressedSize, 0);
724 streamPtr = Lizard_resetStream(streamPtr, 0);
725 FUZ_CHECKTEST(streamPtr==NULL, "Lizard_resetStream failed");
726 Lizard_loadDict(streamPtr, testInput, testInputSize - testCompressedSize);
727 result = Lizard_compress_continue(streamPtr, testInput + testInputSize - testCompressedSize, testCompressed, testCompressedSize, testCompressedSize-1);
728 FUZ_CHECKTEST(result==0, "Lizard_compress_continue() dictionary compression failed : result = %i", result);
729
730 result = Lizard_decompress_safe_usingDict(testCompressed, testVerify, result, testCompressedSize, testInput, testInputSize - testCompressedSize);
731 FUZ_CHECKTEST(result!=(int)testCompressedSize, "Lizard_decompress_safe() simple dictionary decompression test failed");
732 crcNew = XXH64(testVerify, testCompressedSize, 0);
733 FUZ_CHECKTEST(crcOrig!=crcNew, "Lizard_decompress_safe() simple dictionary decompression test : corruption");
734
735 /* multiple HC compression test with dictionary */
736 { int result1, result2;
737 int segSize = testCompressedSize / 2;
738 crcOrig = XXH64(testInput + segSize, testCompressedSize, 0);
739 streamPtr = Lizard_resetStream(streamPtr, 0);
740 FUZ_CHECKTEST(streamPtr==NULL, "Lizard_resetStream failed");
741 Lizard_loadDict(streamPtr, testInput, segSize);
742 result1 = Lizard_compress_continue(streamPtr, testInput + segSize, testCompressed, segSize, segSize -1);
743 FUZ_CHECKTEST(result1==0, "Lizard_compress_continue() dictionary compression failed : result = %i", result1);
744 result2 = Lizard_compress_continue(streamPtr, testInput + 2*segSize, testCompressed+result1, segSize, segSize-1);
745 FUZ_CHECKTEST(result2==0, "Lizard_compress_continue() dictionary compression failed : result = %i", result2);
746
747 result = Lizard_decompress_safe_usingDict(testCompressed, testVerify, result1, segSize, testInput, segSize);
748 FUZ_CHECKTEST(result!=segSize, "Lizard_decompress_safe() dictionary decompression part 1 failed");
749 result = Lizard_decompress_safe_usingDict(testCompressed+result1, testVerify+segSize, result2, segSize, testInput, 2*segSize);
750 FUZ_CHECKTEST(result!=segSize, "Lizard_decompress_safe() dictionary decompression part 2 failed");
751 crcNew = XXH64(testVerify, testCompressedSize, 0);
752 FUZ_CHECKTEST(crcOrig!=crcNew, "Lizard_decompress_safe() dictionary decompression corruption");
753 }
754
755 /* remote dictionary HC compression test */
756 crcOrig = XXH64(testInput + testInputSize - testCompressedSize, testCompressedSize, 0);
757 streamPtr = Lizard_resetStream(streamPtr, 0);
758 FUZ_CHECKTEST(streamPtr==NULL, "Lizard_resetStream failed");
759 Lizard_loadDict(streamPtr, testInput, 32 KB);
760 result = Lizard_compress_continue(streamPtr, testInput + testInputSize - testCompressedSize, testCompressed, testCompressedSize, testCompressedSize-1);
761 FUZ_CHECKTEST(result==0, "Lizard_compress_continue() remote dictionary failed : result = %i", result);
762
763 result = Lizard_decompress_safe_usingDict(testCompressed, testVerify, result, testCompressedSize, testInput, 32 KB);
764 FUZ_CHECKTEST(result!=(int)testCompressedSize, "Lizard_decompress_safe_usingDict() decompression failed following remote dictionary HC compression test");
765 crcNew = XXH64(testVerify, testCompressedSize, 0);
766 FUZ_CHECKTEST(crcOrig!=crcNew, "Lizard_decompress_safe_usingDict() decompression corruption");
767
768 /* multiple HC compression with ext. dictionary */
769 { XXH64_state_t crcOrigState;
770 XXH64_state_t crcNewState;
771 const char* dict = testInput + 3;
772 int dictSize = (FUZ_rand(&randState) & 8191);
773 char* dst = testVerify;
774
775 size_t segStart = dictSize + 7;
776 int segSize = (FUZ_rand(&randState) & 8191);
777 int segNb = 1;
778
779 streamPtr = Lizard_resetStream(streamPtr, 0);
780 FUZ_CHECKTEST(streamPtr==NULL, "Lizard_resetStream failed");
781 Lizard_loadDict(streamPtr, dict, dictSize);
782
783 XXH64_reset(&crcOrigState, 0);
784 XXH64_reset(&crcNewState, 0);
785
786 while (segStart + segSize < testInputSize) {
787 XXH64_update(&crcOrigState, testInput + segStart, segSize);
788 crcOrig = XXH64_digest(&crcOrigState);
789 result = Lizard_compress_continue(streamPtr, testInput + segStart, testCompressed, segSize, Lizard_compressBound(segSize));
790 FUZ_CHECKTEST(result==0, "Lizard_compress_continue() dictionary compression failed : result = %i", result);
791
792 result = Lizard_decompress_safe_usingDict(testCompressed, dst, result, segSize, dict, dictSize);
793 FUZ_CHECKTEST(result!=segSize, "Lizard_decompress_safe_usingDict() dictionary decompression part %i failed", segNb);
794 XXH64_update(&crcNewState, dst, segSize);
795 crcNew = XXH64_digest(&crcNewState);
796 if (crcOrig!=crcNew) {
797 size_t c=0;
798 while (dst[c] == testInput[segStart+c]) c++;
799 DISPLAY("Bad decompression at %u / %u \n", (U32)c, (U32)segSize);
800 }
801 FUZ_CHECKTEST(crcOrig!=crcNew, "Lizard_decompress_safe_usingDict() part %i corruption", segNb);
802
803 dict = dst;
804 //dict = testInput + segStart;
805 dictSize = segSize;
806
807 dst += segSize + 1;
808 segNb ++;
809
810 segStart += segSize + (FUZ_rand(&randState) & 0xF) + 1;
811 segSize = (FUZ_rand(&randState) & 8191);
812 }
813 }
814
815 /* ring buffer test */
816 { XXH64_state_t xxhOrig;
817 XXH64_state_t xxhNew;
818 Lizard_streamDecode_t decodeState;
819 const U32 maxMessageSizeLog = 10;
820 const U32 maxMessageSizeMask = (1<<maxMessageSizeLog) - 1;
821 U32 messageSize = (FUZ_rand(&randState) & maxMessageSizeMask) + 1;
822 U32 iNext = 0;
823 U32 rNext = 0;
824 U32 dNext = 0;
825 const U32 dBufferSize = ringBufferSize + maxMessageSizeMask;
826
827 XXH64_reset(&xxhOrig, 0);
828 XXH64_reset(&xxhNew, 0);
829 streamPtr = Lizard_resetStream(streamPtr, 0);
830 FUZ_CHECKTEST(streamPtr==NULL, "Lizard_resetStream failed");
831 Lizard_setStreamDecode(&decodeState, NULL, 0);
832
833 while (iNext + messageSize < testCompressedSize) {
834 XXH64_update(&xxhOrig, testInput + iNext, messageSize);
835 crcOrig = XXH64_digest(&xxhOrig);
836
837 memcpy (ringBuffer + rNext, testInput + iNext, messageSize);
838 result = Lizard_compress_continue(streamPtr, ringBuffer + rNext, testCompressed, messageSize, testCompressedSize-ringBufferSize);
839 FUZ_CHECKTEST(result==0, "Lizard_compress_continue() compression failed");
840
841 result = Lizard_decompress_safe_continue(&decodeState, testCompressed, testVerify + dNext, result, messageSize);
842 FUZ_CHECKTEST(result!=(int)messageSize, "ringBuffer : Lizard_decompress_safe() test failed");
843
844 XXH64_update(&xxhNew, testVerify + dNext, messageSize);
845 crcNew = XXH64_digest(&xxhNew);
846 FUZ_CHECKTEST(crcOrig!=crcNew, "Lizard_decompress_safe() decompression corruption");
847
848 /* prepare next message */
849 iNext += messageSize;
850 rNext += messageSize;
851 dNext += messageSize;
852 messageSize = (FUZ_rand(&randState) & maxMessageSizeMask) + 1;
853 if (rNext + messageSize > ringBufferSize) rNext = 0;
854 if (dNext + messageSize > dBufferSize) dNext = 0;
855 }
856 }
857
858 /* small decoder-side ring buffer test */
859 { XXH64_state_t xxhOrig;
860 XXH64_state_t xxhNew;
861 Lizard_streamDecode_t decodeState;
862 const U32 maxMessageSizeLog = 12;
863 const U32 maxMessageSizeMask = (1<<maxMessageSizeLog) - 1;
864 U32 messageSize;
865 U32 totalMessageSize = 0;
866 U32 iNext = 0;
867 U32 dNext = 0;
868 const U32 dBufferSize = 64 KB;
869
870 XXH64_reset(&xxhOrig, 0);
871 XXH64_reset(&xxhNew, 0);
872 streamPtr = Lizard_resetStream(streamPtr, 0);
873 FUZ_CHECKTEST(streamPtr==NULL, "Lizard_resetStream failed");
874 Lizard_setStreamDecode(&decodeState, NULL, 0);
875
876 #define BSIZE1 65537
877 #define BSIZE2 16435
878
879 /* first block */
880 messageSize = BSIZE1;
881 XXH64_update(&xxhOrig, testInput + iNext, messageSize);
882 crcOrig = XXH64_digest(&xxhOrig);
883
884 result = Lizard_compress_continue(streamPtr, testInput + iNext, testCompressed, messageSize, testCompressedSize-ringBufferSize);
885 FUZ_CHECKTEST(result==0, "Lizard_compress_continue() compression failed");
886
887 result = Lizard_decompress_safe_continue(&decodeState, testCompressed, testVerify + dNext, result, messageSize);
888 FUZ_CHECKTEST(result!=(int)messageSize, "64K D.ringBuffer : Lizard_decompress_safe() test failed");
889
890 XXH64_update(&xxhNew, testVerify + dNext, messageSize);
891 crcNew = XXH64_digest(&xxhNew);
892 FUZ_CHECKTEST(crcOrig!=crcNew, "Lizard_decompress_safe() decompression corruption");
893
894 /* prepare next message */
895 totalMessageSize += messageSize;
896 messageSize = BSIZE2;
897 dNext = 0;
898 iNext = 132000;
899 memcpy(testInput + iNext, testInput + WILDCOPYLENGTH, messageSize);
900
901 while (totalMessageSize < 9 MB) {
902 XXH64_update(&xxhOrig, testInput + iNext, messageSize);
903 crcOrig = XXH64_digest(&xxhOrig);
904
905 result = Lizard_compress_continue(streamPtr, testInput + iNext, testCompressed, messageSize, testCompressedSize-ringBufferSize);
906 FUZ_CHECKTEST(result==0, "Lizard_compress_continue() compression failed");
907
908 result = Lizard_decompress_safe_continue(&decodeState, testCompressed, testVerify + dNext, result, messageSize);
909 FUZ_CHECKTEST(result!=(int)messageSize, "64K D.ringBuffer : Lizard_decompress_safe() test failed");
910
911 XXH64_update(&xxhNew, testVerify + dNext, messageSize);
912 crcNew = XXH64_digest(&xxhNew);
913 if (crcOrig != crcNew)
914 FUZ_findDiff(testInput + iNext, testVerify + dNext);
915 FUZ_CHECKTEST(crcOrig!=crcNew, "Lizard_decompress_safe() decompression corruption during small decoder-side ring buffer test");
916
917 /* prepare next message */
918 dNext += messageSize;
919 totalMessageSize += messageSize;
920 messageSize = (FUZ_rand(&randState) & maxMessageSizeMask) + 1;
921 iNext = (FUZ_rand(&randState) & 65535);
922 if (dNext > dBufferSize) dNext = 0;
923 }
924 }
925
926 Lizard_freeStream(streamPtr);
927 }
928
929 printf("All unit tests completed successfully \n");
930 return;
931 _output_error:
932 exit(1);
933 }
934
935
FUZ_usage(char * programName)936 static int FUZ_usage(char* programName)
937 {
938 DISPLAY( "Usage :\n");
939 DISPLAY( " %s [args]\n", programName);
940 DISPLAY( "\n");
941 DISPLAY( "Arguments :\n");
942 DISPLAY( " -i# : Nb of tests (default:%i) \n", NB_ATTEMPTS);
943 DISPLAY( " -T# : Duration of tests, in seconds (default: use Nb of tests) \n");
944 DISPLAY( " -s# : Select seed (default:prompt user)\n");
945 DISPLAY( " -t# : Select starting test number (default:0)\n");
946 DISPLAY( " -P# : Select compressibility in %% (default:%i%%)\n", FUZ_COMPRESSIBILITY_DEFAULT);
947 DISPLAY( " -v : verbose\n");
948 DISPLAY( " -p : pause at the end\n");
949 DISPLAY( " -h : display help and exit\n");
950 return 0;
951 }
952
953
main(int argc,char ** argv)954 int main(int argc, char** argv)
955 {
956 U32 seed=0;
957 int seedset=0;
958 int argNb;
959 int nbTests = NB_ATTEMPTS;
960 int testNb = 0;
961 int proba = FUZ_COMPRESSIBILITY_DEFAULT;
962 int pause = 0;
963 char* programName = argv[0];
964 U32 duration = 0;
965
966 /* Check command line */
967 for(argNb=1; argNb<argc; argNb++) {
968 char* argument = argv[argNb];
969
970 if(!argument) continue; // Protection if argument empty
971
972 // Decode command (note : aggregated commands are allowed)
973 if (argument[0]=='-') {
974 if (!strcmp(argument, "--no-prompt")) { pause=0; seedset=1; g_displayLevel=1; continue; }
975 argument++;
976
977 while (*argument!=0) {
978 switch(*argument)
979 {
980 case 'h': /* display help */
981 return FUZ_usage(programName);
982
983 case 'v': /* verbose mode */
984 argument++;
985 g_displayLevel=4;
986 break;
987
988 case 'p': /* pause at the end */
989 argument++;
990 pause=1;
991 break;
992
993 case 'i':
994 argument++;
995 nbTests = 0; duration = 0;
996 while ((*argument>='0') && (*argument<='9')) {
997 nbTests *= 10;
998 nbTests += *argument - '0';
999 argument++;
1000 }
1001 break;
1002
1003 case 'T':
1004 argument++;
1005 nbTests = 0; duration = 0;
1006 for (;;) {
1007 switch(*argument)
1008 {
1009 case 'm': duration *= 60; argument++; continue;
1010 case 's':
1011 case 'n': argument++; continue;
1012 case '0':
1013 case '1':
1014 case '2':
1015 case '3':
1016 case '4':
1017 case '5':
1018 case '6':
1019 case '7':
1020 case '8':
1021 case '9': duration *= 10; duration += *argument++ - '0'; continue;
1022 }
1023 break;
1024 }
1025 break;
1026
1027 case 's':
1028 argument++;
1029 seed=0; seedset=1;
1030 while ((*argument>='0') && (*argument<='9')) {
1031 seed *= 10;
1032 seed += *argument - '0';
1033 argument++;
1034 }
1035 break;
1036
1037 case 't': /* select starting test nb */
1038 argument++;
1039 testNb=0;
1040 while ((*argument>='0') && (*argument<='9')) {
1041 testNb *= 10;
1042 testNb += *argument - '0';
1043 argument++;
1044 }
1045 break;
1046
1047 case 'P': /* change probability */
1048 argument++;
1049 proba=0;
1050 while ((*argument>='0') && (*argument<='9')) {
1051 proba *= 10;
1052 proba += *argument - '0';
1053 argument++;
1054 }
1055 if (proba<0) proba=0;
1056 if (proba>100) proba=100;
1057 break;
1058 default: ;
1059 }
1060 }
1061 }
1062 }
1063
1064 printf("Starting Lizard fuzzer (%i-bits, v%s)\n", (int)(sizeof(size_t)*8), LIZARD_VERSION_STRING);
1065
1066 if (!seedset) {
1067 time_t const t = time(NULL);
1068 U32 const h = XXH32(&t, sizeof(t), 1);
1069 seed = h % 10000;
1070 }
1071 printf("Seed = %u\n", seed);
1072
1073 if (proba!=FUZ_COMPRESSIBILITY_DEFAULT) printf("Compressibility : %i%%\n", proba);
1074
1075 if (testNb==0) FUZ_unitTests(seed);
1076
1077 if (nbTests<=0) nbTests=1;
1078
1079 { int const result = FUZ_test(seed, nbTests, testNb, ((double)proba) / 100, duration);
1080 if (pause) {
1081 DISPLAY("press enter ... \n");
1082 (void)getchar();
1083 }
1084 return result;
1085 }
1086 }
1087