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