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