• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2     frameTest - test tool for lz4frame
3     Copyright (C) Yann Collet 2014-2016
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 homepage : http://www.lz4.org
23     - LZ4 source repository : https://github.com/lz4/lz4
24 */
25 
26 /*-************************************
27 *  Compiler specific
28 **************************************/
29 #ifdef _MSC_VER    /* Visual Studio */
30 #  pragma warning(disable : 4127)        /* disable: C4127: conditional expression is constant */
31 #  pragma warning(disable : 4146)        /* disable: C4146: minus unsigned expression */
32 #endif
33 
34 
35 /*-************************************
36 *  Includes
37 **************************************/
38 #include "util.h"       /* U32 */
39 #include <stdlib.h>     /* malloc, free */
40 #include <stdio.h>      /* fprintf */
41 #include <string.h>     /* strcmp */
42 #include <time.h>       /* clock_t, clock(), CLOCKS_PER_SEC */
43 #include <assert.h>
44 #include "lz4frame.h"   /* include multiple times to test correctness/safety */
45 #include "lz4frame.h"
46 #define LZ4F_STATIC_LINKING_ONLY
47 #include "lz4frame.h"
48 #include "lz4frame.h"
49 #include "lz4.h"        /* LZ4_VERSION_STRING */
50 #define XXH_STATIC_LINKING_ONLY
51 #include "xxhash.h"     /* XXH64 */
52 
53 
54 /* unoptimized version; solves endianess & alignment issues */
FUZ_writeLE32(void * dstVoidPtr,U32 value32)55 static void FUZ_writeLE32 (void* dstVoidPtr, U32 value32)
56 {
57     BYTE* dstPtr = (BYTE*)dstVoidPtr;
58     dstPtr[0] = (BYTE)value32;
59     dstPtr[1] = (BYTE)(value32 >> 8);
60     dstPtr[2] = (BYTE)(value32 >> 16);
61     dstPtr[3] = (BYTE)(value32 >> 24);
62 }
63 
64 
65 /*-************************************
66 *  Constants
67 **************************************/
68 #define LZ4F_MAGIC_SKIPPABLE_START 0x184D2A50U
69 
70 #define KB *(1U<<10)
71 #define MB *(1U<<20)
72 #define GB *(1U<<30)
73 
74 static const U32 nbTestsDefault = 256 KB;
75 #define FUZ_COMPRESSIBILITY_DEFAULT 50
76 static const U32 prime1 = 2654435761U;
77 static const U32 prime2 = 2246822519U;
78 
79 
80 
81 /*-************************************
82 *  Macros
83 **************************************/
84 #define DISPLAY(...)          fprintf(stderr, __VA_ARGS__)
85 #define DISPLAYLEVEL(l, ...)  if (displayLevel>=l) { DISPLAY(__VA_ARGS__); }
86 #define DISPLAYUPDATE(l, ...) if (displayLevel>=l) { \
87             if ((FUZ_GetClockSpan(g_clockTime) > refreshRate) || (displayLevel>=4)) \
88             { g_clockTime = clock(); DISPLAY(__VA_ARGS__); \
89             if (displayLevel>=4) fflush(stdout); } }
90 static const clock_t refreshRate = CLOCKS_PER_SEC / 6;
91 static clock_t g_clockTime = 0;
92 
93 
94 /*-***************************************
95 *  Local Parameters
96 *****************************************/
97 static U32 no_prompt = 0;
98 static U32 displayLevel = 2;
99 static U32 use_pause = 0;
100 
101 
102 /*-*******************************************************
103 *  Fuzzer functions
104 *********************************************************/
105 #define MIN(a,b)  ( (a) < (b) ? (a) : (b) )
106 #define MAX(a,b)  ( (a) > (b) ? (a) : (b) )
107 
FUZ_GetClockSpan(clock_t clockStart)108 static clock_t FUZ_GetClockSpan(clock_t clockStart)
109 {
110     return clock() - clockStart;   /* works even if overflow; max span ~ 30 mn */
111 }
112 
113 
114 #define FUZ_rotl32(x,r) ((x << r) | (x >> (32 - r)))
FUZ_rand(unsigned int * src)115 unsigned int FUZ_rand(unsigned int* src)
116 {
117     U32 rand32 = *src;
118     rand32 *= prime1;
119     rand32 += prime2;
120     rand32  = FUZ_rotl32(rand32, 13);
121     *src = rand32;
122     return rand32 >> 5;
123 }
124 
125 
126 #define FUZ_RAND15BITS  (FUZ_rand(seed) & 0x7FFF)
127 #define FUZ_RANDLENGTH  ( (FUZ_rand(seed) & 3) ? (FUZ_rand(seed) % 15) : (FUZ_rand(seed) % 510) + 15)
FUZ_fillCompressibleNoiseBuffer(void * buffer,size_t bufferSize,double proba,U32 * seed)128 static void FUZ_fillCompressibleNoiseBuffer(void* buffer, size_t bufferSize, double proba, U32* seed)
129 {
130     BYTE* BBuffer = (BYTE*)buffer;
131     size_t pos = 0;
132     U32 P32 = (U32)(32768 * proba);
133 
134     /* First Byte */
135     BBuffer[pos++] = (BYTE)(FUZ_rand(seed));
136 
137     while (pos < bufferSize) {
138         /* Select : Literal (noise) or copy (within 64K) */
139         if (FUZ_RAND15BITS < P32) {
140             /* Copy (within 64K) */
141             size_t const lengthRand = FUZ_RANDLENGTH + 4;
142             size_t const length = MIN(lengthRand, bufferSize - pos);
143             size_t const end = pos + length;
144             size_t const offsetRand = FUZ_RAND15BITS + 1;
145             size_t const offset = MIN(offsetRand, pos);
146             size_t match = pos - offset;
147             while (pos < end) BBuffer[pos++] = BBuffer[match++];
148         } else {
149             /* Literal (noise) */
150             size_t const lengthRand = FUZ_RANDLENGTH + 4;
151             size_t const length = MIN(lengthRand, bufferSize - pos);
152             size_t const end = pos + length;
153             while (pos < end) BBuffer[pos++] = (BYTE)(FUZ_rand(seed) >> 5);
154         }
155     }
156 }
157 
158 
FUZ_highbit(U32 v32)159 static unsigned FUZ_highbit(U32 v32)
160 {
161     unsigned nbBits = 0;
162     if (v32==0) return 0;
163     while (v32) v32 >>= 1, nbBits ++;
164     return nbBits;
165 }
166 
167 
168 /*-*******************************************************
169 *  Tests
170 *********************************************************/
171 #define CHECK_V(v,f) v = f; if (LZ4F_isError(v)) { fprintf(stderr, "%s\n", LZ4F_getErrorName(v)); goto _output_error; }
172 #define CHECK(f)   { LZ4F_errorCode_t const CHECK_V(err_ , f); }
173 
basicTests(U32 seed,double compressibility)174 int basicTests(U32 seed, double compressibility)
175 {
176 #define COMPRESSIBLE_NOISE_LENGTH (2 MB)
177     void* const CNBuffer = malloc(COMPRESSIBLE_NOISE_LENGTH);
178     size_t const cBuffSize = LZ4F_compressFrameBound(COMPRESSIBLE_NOISE_LENGTH, NULL);
179     void* const compressedBuffer = malloc(cBuffSize);
180     void* const decodedBuffer = malloc(COMPRESSIBLE_NOISE_LENGTH);
181     U32 randState = seed;
182     size_t cSize, testSize;
183     LZ4F_decompressionContext_t dCtx = NULL;
184     LZ4F_compressionContext_t cctx = NULL;
185     U64 crcOrig;
186     int basicTests_error = 0;
187     LZ4F_preferences_t prefs;
188     memset(&prefs, 0, sizeof(prefs));
189 
190     if (!CNBuffer || !compressedBuffer || !decodedBuffer) {
191         DISPLAY("allocation error, not enough memory to start fuzzer tests \n");
192         goto _output_error;
193     }
194     FUZ_fillCompressibleNoiseBuffer(CNBuffer, COMPRESSIBLE_NOISE_LENGTH, compressibility, &randState);
195     crcOrig = XXH64(CNBuffer, COMPRESSIBLE_NOISE_LENGTH, 1);
196 
197     /* LZ4F_compressBound() : special case : srcSize == 0 */
198     DISPLAYLEVEL(3, "LZ4F_compressBound(0) = ");
199     {   size_t const cBound = LZ4F_compressBound(0, NULL);
200         if (cBound < 64 KB) goto _output_error;
201         DISPLAYLEVEL(3, " %u \n", (U32)cBound);
202     }
203 
204     /* Special case : null-content frame */
205     testSize = 0;
206     DISPLAYLEVEL(3, "LZ4F_compressFrame, compress null content : ");
207     CHECK_V(cSize, LZ4F_compressFrame(compressedBuffer, LZ4F_compressFrameBound(testSize, NULL), CNBuffer, testSize, NULL));
208     DISPLAYLEVEL(3, "null content encoded into a %u bytes frame \n", (unsigned)cSize);
209 
210     DISPLAYLEVEL(3, "LZ4F_createDecompressionContext \n");
211     CHECK ( LZ4F_createDecompressionContext(&dCtx, LZ4F_VERSION) );
212 
213     DISPLAYLEVEL(3, "LZ4F_getFrameInfo on null-content frame (#157) \n");
214     {   size_t avail_in = cSize;
215         LZ4F_frameInfo_t frame_info;
216         CHECK( LZ4F_getFrameInfo(dCtx, &frame_info, compressedBuffer, &avail_in) );
217     }
218 
219     DISPLAYLEVEL(3, "LZ4F_freeDecompressionContext \n");
220     CHECK( LZ4F_freeDecompressionContext(dCtx) );
221     dCtx = NULL;
222 
223     /* test one-pass frame compression */
224     testSize = COMPRESSIBLE_NOISE_LENGTH;
225 
226     DISPLAYLEVEL(3, "LZ4F_compressFrame, using fast level -3 : ");
227     {   LZ4F_preferences_t fastCompressPrefs;
228         memset(&fastCompressPrefs, 0, sizeof(fastCompressPrefs));
229         fastCompressPrefs.compressionLevel = -3;
230         CHECK_V(cSize, LZ4F_compressFrame(compressedBuffer, LZ4F_compressFrameBound(testSize, NULL), CNBuffer, testSize, &fastCompressPrefs));
231         DISPLAYLEVEL(3, "Compressed %u bytes into a %u bytes frame \n", (U32)testSize, (U32)cSize);
232     }
233 
234     DISPLAYLEVEL(3, "LZ4F_compressFrame, using default preferences : ");
235     CHECK_V(cSize, LZ4F_compressFrame(compressedBuffer, LZ4F_compressFrameBound(testSize, NULL), CNBuffer, testSize, NULL));
236     DISPLAYLEVEL(3, "Compressed %u bytes into a %u bytes frame \n", (U32)testSize, (U32)cSize);
237 
238     DISPLAYLEVEL(3, "Decompression test : \n");
239     {   size_t decodedBufferSize = COMPRESSIBLE_NOISE_LENGTH;
240         size_t compressedBufferSize = cSize;
241 
242         CHECK( LZ4F_createDecompressionContext(&dCtx, LZ4F_VERSION) );
243 
244         DISPLAYLEVEL(3, "Single Pass decompression : ");
245         CHECK( LZ4F_decompress(dCtx, decodedBuffer, &decodedBufferSize, compressedBuffer, &compressedBufferSize, NULL) );
246         { U64 const crcDest = XXH64(decodedBuffer, decodedBufferSize, 1);
247           if (crcDest != crcOrig) goto _output_error; }
248         DISPLAYLEVEL(3, "Regenerated %u bytes \n", (U32)decodedBufferSize);
249 
250         DISPLAYLEVEL(3, "Reusing decompression context \n");
251         {   size_t const missingBytes = 4;
252             size_t iSize = compressedBufferSize - missingBytes;
253             const BYTE* cBuff = (const BYTE*) compressedBuffer;
254             BYTE* const ostart = (BYTE*)decodedBuffer;
255             BYTE* op = ostart;
256             BYTE* const oend = (BYTE*)decodedBuffer + COMPRESSIBLE_NOISE_LENGTH;
257             size_t decResult, oSize = COMPRESSIBLE_NOISE_LENGTH;
258             DISPLAYLEVEL(3, "Missing last %u bytes : ", (U32)missingBytes);
259             CHECK_V(decResult, LZ4F_decompress(dCtx, op, &oSize, cBuff, &iSize, NULL));
260             if (decResult != missingBytes) {
261                 DISPLAY("%u bytes missing != %u bytes requested \n", (U32)missingBytes, (U32)decResult);
262                 goto _output_error;
263             }
264             DISPLAYLEVEL(3, "indeed, requests %u bytes \n", (unsigned)decResult);
265             cBuff += iSize;
266             iSize = decResult;
267             op += oSize;
268             oSize = (size_t)(oend-op);
269             decResult = LZ4F_decompress(dCtx, op, &oSize, cBuff, &iSize, NULL);
270             if (decResult != 0) goto _output_error;   /* should finish now */
271             op += oSize;
272             if (op>oend) { DISPLAY("decompression write overflow \n"); goto _output_error; }
273             {   U64 const crcDest = XXH64(decodedBuffer, op-ostart, 1);
274                 if (crcDest != crcOrig) goto _output_error;
275         }   }
276 
277         {   size_t oSize = 0;
278             size_t iSize = 0;
279             LZ4F_frameInfo_t fi;
280             const BYTE* ip = (BYTE*)compressedBuffer;
281 
282             DISPLAYLEVEL(3, "Start by feeding 0 bytes, to get next input size : ");
283             CHECK( LZ4F_decompress(dCtx, NULL, &oSize, ip, &iSize, NULL) );
284             //DISPLAYLEVEL(3, " %u  \n", (unsigned)errorCode);
285             DISPLAYLEVEL(3, " OK  \n");
286 
287             DISPLAYLEVEL(3, "LZ4F_getFrameInfo on zero-size input : ");
288             {   size_t nullSize = 0;
289                 size_t const fiError = LZ4F_getFrameInfo(dCtx, &fi, ip, &nullSize);
290                 if (LZ4F_getErrorCode(fiError) != LZ4F_ERROR_frameHeader_incomplete) {
291                     DISPLAYLEVEL(3, "incorrect error : %s != ERROR_frameHeader_incomplete \n",
292                                     LZ4F_getErrorName(fiError));
293                     goto _output_error;
294                 }
295                 DISPLAYLEVEL(3, " correctly failed : %s \n", LZ4F_getErrorName(fiError));
296             }
297 
298             DISPLAYLEVEL(3, "LZ4F_getFrameInfo on not enough input : ");
299             {   size_t inputSize = 6;
300                 size_t const fiError = LZ4F_getFrameInfo(dCtx, &fi, ip, &inputSize);
301                 if (LZ4F_getErrorCode(fiError) != LZ4F_ERROR_frameHeader_incomplete) {
302                     DISPLAYLEVEL(3, "incorrect error : %s != ERROR_frameHeader_incomplete \n", LZ4F_getErrorName(fiError));
303                     goto _output_error;
304                 }
305                 DISPLAYLEVEL(3, " correctly failed : %s \n", LZ4F_getErrorName(fiError));
306             }
307 
308             DISPLAYLEVEL(3, "LZ4F_getFrameInfo on enough input : ");
309             iSize = 15 - iSize;
310             CHECK( LZ4F_getFrameInfo(dCtx, &fi, ip, &iSize) );
311             DISPLAYLEVEL(3, " correctly decoded \n");
312             ip += iSize;
313         }
314 
315         DISPLAYLEVEL(3, "Decode a buggy input : ");
316         assert(COMPRESSIBLE_NOISE_LENGTH > 64);
317         assert(cSize > 48);
318         memcpy(decodedBuffer, (char*)compressedBuffer+16, 32);  /* save correct data */
319         memcpy((char*)compressedBuffer+16, (const char*)decodedBuffer+32, 32);  /* insert noise */
320         {   size_t dbSize = COMPRESSIBLE_NOISE_LENGTH;
321             size_t cbSize = cSize;
322             size_t const decompressError = LZ4F_decompress(dCtx, decodedBuffer, &dbSize,
323                                                                compressedBuffer, &cbSize,
324                                                                NULL);
325             if (!LZ4F_isError(decompressError)) goto _output_error;
326             DISPLAYLEVEL(3, "error detected : %s \n", LZ4F_getErrorName(decompressError));
327         }
328         memcpy((char*)compressedBuffer+16, decodedBuffer, 32);  /* restore correct data */
329 
330         DISPLAYLEVEL(3, "Reset decompression context, since it's left in error state \n");
331         LZ4F_resetDecompressionContext(dCtx);   /* always successful */
332 
333         DISPLAYLEVEL(3, "Byte after byte : ");
334         {   BYTE* const ostart = (BYTE*)decodedBuffer;
335             BYTE* op = ostart;
336             BYTE* const oend = (BYTE*)decodedBuffer + COMPRESSIBLE_NOISE_LENGTH;
337             const BYTE* ip = (const BYTE*) compressedBuffer;
338             const BYTE* const iend = ip + cSize;
339             while (ip < iend) {
340                 size_t oSize = oend-op;
341                 size_t iSize = 1;
342                 CHECK( LZ4F_decompress(dCtx, op, &oSize, ip, &iSize, NULL) );
343                 op += oSize;
344                 ip += iSize;
345             }
346             { U64 const crcDest = XXH64(decodedBuffer, COMPRESSIBLE_NOISE_LENGTH, 1);
347               if (crcDest != crcOrig) goto _output_error; }
348             DISPLAYLEVEL(3, "Regenerated %u/%u bytes \n", (unsigned)(op-ostart), COMPRESSIBLE_NOISE_LENGTH);
349         }
350     }
351 
352     DISPLAYLEVEL(3, "Using 64 KB block : ");
353     prefs.frameInfo.blockSizeID = LZ4F_max64KB;
354     prefs.frameInfo.contentChecksumFlag = LZ4F_contentChecksumEnabled;
355     CHECK_V(cSize, LZ4F_compressFrame(compressedBuffer, LZ4F_compressFrameBound(testSize, &prefs), CNBuffer, testSize, &prefs));
356     DISPLAYLEVEL(3, "Compressed %i bytes into a %i bytes frame \n", (int)testSize, (int)cSize);
357 
358     DISPLAYLEVEL(3, "without checksum : ");
359     prefs.frameInfo.contentChecksumFlag = LZ4F_noContentChecksum;
360     CHECK_V(cSize, LZ4F_compressFrame(compressedBuffer, LZ4F_compressFrameBound(testSize, &prefs), CNBuffer, testSize, &prefs));
361     DISPLAYLEVEL(3, "Compressed %i bytes into a %i bytes frame \n", (int)testSize, (int)cSize);
362 
363     DISPLAYLEVEL(3, "Using 256 KB block : ");
364     prefs.frameInfo.blockSizeID = LZ4F_max256KB;
365     prefs.frameInfo.contentChecksumFlag = LZ4F_contentChecksumEnabled;
366     CHECK_V(cSize, LZ4F_compressFrame(compressedBuffer, LZ4F_compressFrameBound(testSize, &prefs), CNBuffer, testSize, &prefs));
367     DISPLAYLEVEL(3, "Compressed %i bytes into a %i bytes frame \n", (int)testSize, (int)cSize);
368 
369     DISPLAYLEVEL(3, "Decompression test : \n");
370     {   size_t const decodedBufferSize = COMPRESSIBLE_NOISE_LENGTH;
371         unsigned const maxBits = FUZ_highbit((U32)decodedBufferSize);
372         BYTE* const ostart = (BYTE*)decodedBuffer;
373         BYTE* op = ostart;
374         BYTE* const oend = ostart + COMPRESSIBLE_NOISE_LENGTH;
375         const BYTE* ip = (const BYTE*)compressedBuffer;
376         const BYTE* const iend = (const BYTE*)compressedBuffer + cSize;
377 
378         DISPLAYLEVEL(3, "random segment sizes : ");
379         while (ip < iend) {
380             unsigned const nbBits = FUZ_rand(&randState) % maxBits;
381             size_t iSize = (FUZ_rand(&randState) & ((1<<nbBits)-1)) + 1;
382             size_t oSize = oend-op;
383             if (iSize > (size_t)(iend-ip)) iSize = iend-ip;
384             CHECK( LZ4F_decompress(dCtx, op, &oSize, ip, &iSize, NULL) );
385             op += oSize;
386             ip += iSize;
387         }
388         {   size_t const decodedSize = (size_t)(op - ostart);
389             U64 const crcDest = XXH64(decodedBuffer, decodedSize, 1);
390             if (crcDest != crcOrig) goto _output_error;
391             DISPLAYLEVEL(3, "Regenerated %u bytes \n", (U32)decodedSize);
392          }
393 
394         CHECK( LZ4F_freeDecompressionContext(dCtx) );
395         dCtx = NULL;
396     }
397 
398     DISPLAYLEVEL(3, "without checksum : ");
399     prefs.frameInfo.contentChecksumFlag = LZ4F_noContentChecksum;
400     CHECK_V(cSize, LZ4F_compressFrame(compressedBuffer, LZ4F_compressFrameBound(testSize, &prefs), CNBuffer, testSize, &prefs) );
401     DISPLAYLEVEL(3, "Compressed %i bytes into a %i bytes frame \n", (int)testSize, (int)cSize);
402 
403     DISPLAYLEVEL(3, "Using 1 MB block : ");
404     prefs.frameInfo.blockSizeID = LZ4F_max1MB;
405     prefs.frameInfo.contentChecksumFlag = LZ4F_contentChecksumEnabled;
406     CHECK_V(cSize, LZ4F_compressFrame(compressedBuffer, LZ4F_compressFrameBound(testSize, &prefs), CNBuffer, testSize, &prefs) );
407     DISPLAYLEVEL(3, "Compressed %i bytes into a %i bytes frame \n", (int)testSize, (int)cSize);
408 
409     DISPLAYLEVEL(3, "without frame checksum : ");
410     prefs.frameInfo.contentChecksumFlag = LZ4F_noContentChecksum;
411     CHECK_V(cSize, LZ4F_compressFrame(compressedBuffer, LZ4F_compressFrameBound(testSize, &prefs), CNBuffer, testSize, &prefs) );
412     DISPLAYLEVEL(3, "Compressed %i bytes into a %i bytes frame \n", (int)testSize, (int)cSize);
413 
414     DISPLAYLEVEL(3, "Using 4 MB block : ");
415     prefs.frameInfo.blockSizeID = LZ4F_max4MB;
416     prefs.frameInfo.contentChecksumFlag = LZ4F_contentChecksumEnabled;
417     {   size_t const dstCapacity = LZ4F_compressFrameBound(testSize, &prefs);
418         DISPLAYLEVEL(4, "dstCapacity = %u  ; ", (U32)dstCapacity)
419         CHECK_V(cSize, LZ4F_compressFrame(compressedBuffer, dstCapacity, CNBuffer, testSize, &prefs) );
420         DISPLAYLEVEL(3, "Compressed %u bytes into a %u bytes frame \n", (U32)testSize, (U32)cSize);
421     }
422 
423     DISPLAYLEVEL(3, "without frame checksum : ");
424     prefs.frameInfo.contentChecksumFlag = LZ4F_noContentChecksum;
425     {   size_t const dstCapacity = LZ4F_compressFrameBound(testSize, &prefs);
426         DISPLAYLEVEL(4, "dstCapacity = %u  ; ", (U32)dstCapacity)
427         CHECK_V(cSize, LZ4F_compressFrame(compressedBuffer, dstCapacity, CNBuffer, testSize, &prefs) );
428         DISPLAYLEVEL(3, "Compressed %u bytes into a %u bytes frame \n", (U32)testSize, (U32)cSize);
429     }
430 
431     DISPLAYLEVEL(3, "LZ4F_compressFrame with block checksum : ");
432     memset(&prefs, 0, sizeof(prefs));
433     prefs.frameInfo.blockChecksumFlag = LZ4F_blockChecksumEnabled;
434     CHECK_V(cSize, LZ4F_compressFrame(compressedBuffer, LZ4F_compressFrameBound(testSize, &prefs), CNBuffer, testSize, &prefs) );
435     DISPLAYLEVEL(3, "Compressed %i bytes into a %i bytes frame \n", (int)testSize, (int)cSize);
436 
437     DISPLAYLEVEL(3, "Decompress with block checksum : ");
438     {   size_t iSize = cSize;
439         size_t decodedSize = COMPRESSIBLE_NOISE_LENGTH;
440         LZ4F_decompressionContext_t dctx;
441         CHECK( LZ4F_createDecompressionContext(&dctx, LZ4F_VERSION) );
442         CHECK( LZ4F_decompress(dctx, decodedBuffer, &decodedSize, compressedBuffer, &iSize, NULL) );
443         if (decodedSize != testSize) goto _output_error;
444         if (iSize != cSize) goto _output_error;
445         {   U64 const crcDest = XXH64(decodedBuffer, decodedSize, 1);
446             U64 const crcSrc = XXH64(CNBuffer, testSize, 1);
447             if (crcDest != crcSrc) goto _output_error;
448         }
449         DISPLAYLEVEL(3, "Regenerated %u bytes \n", (U32)decodedSize);
450 
451         CHECK( LZ4F_freeDecompressionContext(dctx) );
452     }
453 
454     /* frame content size tests */
455     {   size_t cErr;
456         BYTE* const ostart = (BYTE*)compressedBuffer;
457         BYTE* op = ostart;
458         CHECK( LZ4F_createCompressionContext(&cctx, LZ4F_VERSION) );
459 
460         DISPLAYLEVEL(3, "compress without frameSize : ");
461         memset(&(prefs.frameInfo), 0, sizeof(prefs.frameInfo));
462         CHECK_V(cErr, LZ4F_compressBegin(cctx, compressedBuffer, testSize, &prefs));
463         op += cErr;
464         CHECK_V(cErr, LZ4F_compressUpdate(cctx, op, LZ4F_compressBound(testSize, &prefs), CNBuffer, testSize, NULL));
465         op += cErr;
466         CHECK( LZ4F_compressEnd(cctx, compressedBuffer, testSize, NULL) );
467         DISPLAYLEVEL(3, "Compressed %i bytes into a %i bytes frame \n", (int)testSize, (int)(op-ostart));
468 
469         DISPLAYLEVEL(3, "compress with frameSize : ");
470         prefs.frameInfo.contentSize = testSize;
471         op = ostart;
472         CHECK_V(cErr, LZ4F_compressBegin(cctx, compressedBuffer, testSize, &prefs));
473         op += cErr;
474         CHECK_V(cErr, LZ4F_compressUpdate(cctx, op, LZ4F_compressBound(testSize, &prefs), CNBuffer, testSize, NULL));
475         op += cErr;
476         CHECK( LZ4F_compressEnd(cctx, compressedBuffer, testSize, NULL) );
477         DISPLAYLEVEL(3, "Compressed %i bytes into a %i bytes frame \n", (int)testSize, (int)(op-ostart));
478 
479         DISPLAYLEVEL(3, "compress with wrong frameSize : ");
480         prefs.frameInfo.contentSize = testSize+1;
481         op = ostart;
482         CHECK_V(cErr, LZ4F_compressBegin(cctx, compressedBuffer, testSize, &prefs));
483         op += cErr;
484         CHECK_V(cErr, LZ4F_compressUpdate(cctx, op, LZ4F_compressBound(testSize, &prefs), CNBuffer, testSize, NULL));
485         op += cErr;
486         cErr = LZ4F_compressEnd(cctx, op, testSize, NULL);
487         if (!LZ4F_isError(cErr)) goto _output_error;
488         DISPLAYLEVEL(3, "Error correctly detected : %s \n", LZ4F_getErrorName(cErr));
489 
490         CHECK( LZ4F_freeCompressionContext(cctx) );
491         cctx = NULL;
492     }
493 
494     /* dictID tests */
495     {   size_t cErr;
496         U32 const dictID = 0x99;
497         CHECK( LZ4F_createCompressionContext(&cctx, LZ4F_VERSION) );
498 
499         DISPLAYLEVEL(3, "insert a dictID : ");
500         memset(&prefs.frameInfo, 0, sizeof(prefs.frameInfo));
501         prefs.frameInfo.dictID = dictID;
502         CHECK_V(cErr, LZ4F_compressBegin(cctx, compressedBuffer, testSize, &prefs));
503         DISPLAYLEVEL(3, "created frame header of size %i bytes  \n", (int)cErr);
504 
505         DISPLAYLEVEL(3, "read a dictID : ");
506         CHECK( LZ4F_createDecompressionContext(&dCtx, LZ4F_VERSION) );
507         memset(&prefs.frameInfo, 0, sizeof(prefs.frameInfo));
508         CHECK( LZ4F_getFrameInfo(dCtx, &prefs.frameInfo, compressedBuffer, &cErr) );
509         if (prefs.frameInfo.dictID != dictID) goto _output_error;
510         DISPLAYLEVEL(3, "%u \n", (U32)prefs.frameInfo.dictID);
511 
512         CHECK( LZ4F_freeDecompressionContext(dCtx) ); dCtx = NULL;
513         CHECK( LZ4F_freeCompressionContext(cctx) ); cctx = NULL;
514     }
515 
516     /* Dictionary compression test */
517     {   size_t const dictSize = 63 KB;
518         size_t const dstCapacity = LZ4F_compressFrameBound(dictSize, NULL);
519         size_t cSizeNoDict, cSizeWithDict;
520         LZ4F_CDict* const cdict = LZ4F_createCDict(CNBuffer, dictSize);
521         if (cdict == NULL) goto _output_error;
522         CHECK( LZ4F_createCompressionContext(&cctx, LZ4F_VERSION) );
523 
524         DISPLAYLEVEL(3, "LZ4F_compressFrame_usingCDict, with NULL dict : ");
525         CHECK_V(cSizeNoDict,
526                 LZ4F_compressFrame_usingCDict(cctx, compressedBuffer, dstCapacity,
527                                               CNBuffer, dictSize,
528                                               NULL, NULL) );
529         DISPLAYLEVEL(3, "%u bytes \n", (unsigned)cSizeNoDict);
530 
531         CHECK( LZ4F_freeCompressionContext(cctx) );
532         CHECK( LZ4F_createCompressionContext(&cctx, LZ4F_VERSION) );
533         DISPLAYLEVEL(3, "LZ4F_compressFrame_usingCDict, with dict : ");
534         CHECK_V(cSizeWithDict,
535                 LZ4F_compressFrame_usingCDict(cctx, compressedBuffer, dstCapacity,
536                                               CNBuffer, dictSize,
537                                               cdict, NULL) );
538         DISPLAYLEVEL(3, "compressed %u bytes into %u bytes \n",
539                         (unsigned)dictSize, (unsigned)cSizeWithDict);
540         if (cSizeWithDict >= cSizeNoDict) goto _output_error;  /* must be more efficient */
541         crcOrig = XXH64(CNBuffer, dictSize, 0);
542 
543         DISPLAYLEVEL(3, "LZ4F_decompress_usingDict : ");
544         {   LZ4F_dctx* dctx;
545             size_t decodedSize = COMPRESSIBLE_NOISE_LENGTH;
546             size_t compressedSize = cSizeWithDict;
547             CHECK( LZ4F_createDecompressionContext(&dctx, LZ4F_VERSION) );
548             CHECK( LZ4F_decompress_usingDict(dctx,
549                                         decodedBuffer, &decodedSize,
550                                         compressedBuffer, &compressedSize,
551                                         CNBuffer, dictSize,
552                                         NULL) );
553             if (compressedSize != cSizeWithDict) goto _output_error;
554             if (decodedSize != dictSize) goto _output_error;
555             { U64 const crcDest = XXH64(decodedBuffer, decodedSize, 0);
556               if (crcDest != crcOrig) goto _output_error; }
557             DISPLAYLEVEL(3, "Regenerated %u bytes \n", (U32)decodedSize);
558             CHECK( LZ4F_freeDecompressionContext(dctx) );
559         }
560 
561         DISPLAYLEVEL(3, "LZ4F_compressFrame_usingCDict, with dict, negative level : ");
562         {   size_t cSizeLevelMax;
563             LZ4F_preferences_t cParams;
564             memset(&cParams, 0, sizeof(cParams));
565             cParams.compressionLevel = -3;
566             CHECK_V(cSizeLevelMax,
567                 LZ4F_compressFrame_usingCDict(cctx, compressedBuffer, dstCapacity,
568                                               CNBuffer, dictSize,
569                                               cdict, &cParams) );
570             DISPLAYLEVEL(3, "%u bytes \n", (unsigned)cSizeLevelMax);
571         }
572 
573         DISPLAYLEVEL(3, "LZ4F_compressFrame_usingCDict, with dict, level max : ");
574         {   size_t cSizeLevelMax;
575             LZ4F_preferences_t cParams;
576             memset(&cParams, 0, sizeof(cParams));
577             cParams.compressionLevel = LZ4F_compressionLevel_max();
578             CHECK_V(cSizeLevelMax,
579                 LZ4F_compressFrame_usingCDict(cctx, compressedBuffer, dstCapacity,
580                                               CNBuffer, dictSize,
581                                               cdict, &cParams) );
582             DISPLAYLEVEL(3, "%u bytes \n", (unsigned)cSizeLevelMax);
583         }
584 
585         DISPLAYLEVEL(3, "LZ4F_compressFrame_usingCDict, multiple linked blocks : ");
586         {   size_t cSizeContiguous;
587             size_t const inSize = dictSize * 3;
588             size_t const outCapacity = LZ4F_compressFrameBound(inSize, NULL);
589             LZ4F_preferences_t cParams;
590             memset(&cParams, 0, sizeof(cParams));
591             cParams.frameInfo.blockMode = LZ4F_blockLinked;
592             cParams.frameInfo.blockSizeID = LZ4F_max64KB;
593             CHECK_V(cSizeContiguous,
594                 LZ4F_compressFrame_usingCDict(cctx, compressedBuffer, outCapacity,
595                                               CNBuffer, inSize,
596                                               cdict, &cParams) );
597             DISPLAYLEVEL(3, "compressed %u bytes into %u bytes \n",
598                         (unsigned)inSize, (unsigned)cSizeContiguous);
599 
600             DISPLAYLEVEL(3, "LZ4F_decompress_usingDict on multiple linked blocks : ");
601             {   LZ4F_dctx* dctx;
602                 size_t decodedSize = COMPRESSIBLE_NOISE_LENGTH;
603                 size_t compressedSize = cSizeContiguous;
604                 CHECK( LZ4F_createDecompressionContext(&dctx, LZ4F_VERSION) );
605                 CHECK( LZ4F_decompress_usingDict(dctx,
606                                             decodedBuffer, &decodedSize,
607                                             compressedBuffer, &compressedSize,
608                                             CNBuffer, dictSize,
609                                             NULL) );
610                 if (compressedSize != cSizeContiguous) goto _output_error;
611                 if (decodedSize != inSize) goto _output_error;
612                 crcOrig = XXH64(CNBuffer, inSize, 0);
613                 { U64 const crcDest = XXH64(decodedBuffer, decodedSize, 0);
614                   if (crcDest != crcOrig) goto _output_error; }
615                 DISPLAYLEVEL(3, "Regenerated %u bytes \n", (U32)decodedSize);
616                 CHECK( LZ4F_freeDecompressionContext(dctx) );
617             }
618         }
619 
620 
621         DISPLAYLEVEL(3, "LZ4F_compressFrame_usingCDict, multiple independent blocks : ");
622         {   size_t cSizeIndep;
623             size_t const inSize = dictSize * 3;
624             size_t const outCapacity = LZ4F_compressFrameBound(inSize, NULL);
625             LZ4F_preferences_t cParams;
626             memset(&cParams, 0, sizeof(cParams));
627             cParams.frameInfo.blockMode = LZ4F_blockIndependent;
628             cParams.frameInfo.blockSizeID = LZ4F_max64KB;
629             CHECK_V(cSizeIndep,
630                 LZ4F_compressFrame_usingCDict(cctx, compressedBuffer, outCapacity,
631                                               CNBuffer, inSize,
632                                               cdict, &cParams) );
633             DISPLAYLEVEL(3, "compressed %u bytes into %u bytes \n",
634                         (unsigned)inSize, (unsigned)cSizeIndep);
635 
636             DISPLAYLEVEL(3, "LZ4F_decompress_usingDict on multiple independent blocks : ");
637             {   LZ4F_dctx* dctx;
638                 size_t decodedSize = COMPRESSIBLE_NOISE_LENGTH;
639                 size_t compressedSize = cSizeIndep;
640                 CHECK( LZ4F_createDecompressionContext(&dctx, LZ4F_VERSION) );
641                 CHECK( LZ4F_decompress_usingDict(dctx,
642                                             decodedBuffer, &decodedSize,
643                                             compressedBuffer, &compressedSize,
644                                             CNBuffer, dictSize,
645                                             NULL) );
646                 if (compressedSize != cSizeIndep) goto _output_error;
647                 if (decodedSize != inSize) goto _output_error;
648                 crcOrig = XXH64(CNBuffer, inSize, 0);
649                 { U64 const crcDest = XXH64(decodedBuffer, decodedSize, 0);
650                   if (crcDest != crcOrig) goto _output_error; }
651                 DISPLAYLEVEL(3, "Regenerated %u bytes \n", (U32)decodedSize);
652                 CHECK( LZ4F_freeDecompressionContext(dctx) );
653             }
654         }
655 
656         LZ4F_freeCDict(cdict);
657         CHECK( LZ4F_freeCompressionContext(cctx) ); cctx = NULL;
658     }
659 
660 
661     DISPLAYLEVEL(3, "Skippable frame test : \n");
662     {   size_t decodedBufferSize = COMPRESSIBLE_NOISE_LENGTH;
663         unsigned maxBits = FUZ_highbit((U32)decodedBufferSize);
664         BYTE* op = (BYTE*)decodedBuffer;
665         BYTE* const oend = (BYTE*)decodedBuffer + COMPRESSIBLE_NOISE_LENGTH;
666         BYTE* ip = (BYTE*)compressedBuffer;
667         BYTE* iend = (BYTE*)compressedBuffer + cSize + 8;
668 
669         CHECK( LZ4F_createDecompressionContext(&dCtx, LZ4F_VERSION) );
670 
671         /* generate skippable frame */
672         FUZ_writeLE32(ip, LZ4F_MAGIC_SKIPPABLE_START);
673         FUZ_writeLE32(ip+4, (U32)cSize);
674 
675         DISPLAYLEVEL(3, "random segment sizes : \n");
676         while (ip < iend) {
677             unsigned nbBits = FUZ_rand(&randState) % maxBits;
678             size_t iSize = (FUZ_rand(&randState) & ((1<<nbBits)-1)) + 1;
679             size_t oSize = oend-op;
680             if (iSize > (size_t)(iend-ip)) iSize = iend-ip;
681             CHECK( LZ4F_decompress(dCtx, op, &oSize, ip, &iSize, NULL) );
682             op += oSize;
683             ip += iSize;
684         }
685         DISPLAYLEVEL(3, "Skipped %i bytes \n", (int)decodedBufferSize);
686 
687         /* generate zero-size skippable frame */
688         DISPLAYLEVEL(3, "zero-size skippable frame\n");
689         ip = (BYTE*)compressedBuffer;
690         op = (BYTE*)decodedBuffer;
691         FUZ_writeLE32(ip, LZ4F_MAGIC_SKIPPABLE_START+1);
692         FUZ_writeLE32(ip+4, 0);
693         iend = ip+8;
694 
695         while (ip < iend) {
696             unsigned const nbBits = FUZ_rand(&randState) % maxBits;
697             size_t iSize = (FUZ_rand(&randState) & ((1<<nbBits)-1)) + 1;
698             size_t oSize = oend-op;
699             if (iSize > (size_t)(iend-ip)) iSize = iend-ip;
700             CHECK( LZ4F_decompress(dCtx, op, &oSize, ip, &iSize, NULL) );
701             op += oSize;
702             ip += iSize;
703         }
704         DISPLAYLEVEL(3, "Skipped %i bytes \n", (int)(ip - (BYTE*)compressedBuffer - 8));
705 
706         DISPLAYLEVEL(3, "Skippable frame header complete in first call \n");
707         ip = (BYTE*)compressedBuffer;
708         op = (BYTE*)decodedBuffer;
709         FUZ_writeLE32(ip, LZ4F_MAGIC_SKIPPABLE_START+2);
710         FUZ_writeLE32(ip+4, 10);
711         iend = ip+18;
712         while (ip < iend) {
713             size_t iSize = 10;
714             size_t oSize = 10;
715             if (iSize > (size_t)(iend-ip)) iSize = iend-ip;
716             CHECK( LZ4F_decompress(dCtx, op, &oSize, ip, &iSize, NULL) );
717             op += oSize;
718             ip += iSize;
719         }
720         DISPLAYLEVEL(3, "Skipped %i bytes \n", (int)(ip - (BYTE*)compressedBuffer - 8));
721     }
722 
723     DISPLAY("Basic tests completed \n");
724 _end:
725     free(CNBuffer);
726     free(compressedBuffer);
727     free(decodedBuffer);
728     LZ4F_freeDecompressionContext(dCtx); dCtx = NULL;
729     LZ4F_freeCompressionContext(cctx); cctx = NULL;
730     return basicTests_error;
731 
732 _output_error:
733     basicTests_error = 1;
734     DISPLAY("Error detected ! \n");
735     goto _end;
736 }
737 
738 
locateBuffDiff(const void * buff1,const void * buff2,size_t size,unsigned nonContiguous)739 static void locateBuffDiff(const void* buff1, const void* buff2, size_t size, unsigned nonContiguous)
740 {
741     size_t p=0;
742     const BYTE* b1=(const BYTE*)buff1;
743     const BYTE* b2=(const BYTE*)buff2;
744     DISPLAY("locateBuffDiff: looking for error position \n");
745     if (nonContiguous) {
746         DISPLAY("mode %u: non-contiguous output (%zu bytes), cannot search \n", nonContiguous, size);
747         return;
748     }
749     while (p < size && b1[p]==b2[p]) p++;
750     if (p != size) {
751         DISPLAY("Error at pos %i/%i : %02X != %02X \n", (int)p, (int)size, b1[p], b2[p]);
752     }
753 }
754 
755 
fuzzerTests(U32 seed,unsigned nbTests,unsigned startTest,double compressibility,U32 duration_s)756 int fuzzerTests(U32 seed, unsigned nbTests, unsigned startTest, double compressibility, U32 duration_s)
757 {
758     unsigned testResult = 0;
759     unsigned testNb = 0;
760     size_t const srcDataLength = 9 MB;  /* needs to be > 2x4MB to test large blocks */
761     void* srcBuffer = NULL;
762     size_t const compressedBufferSize = LZ4F_compressFrameBound(srcDataLength, NULL);
763     void* compressedBuffer = NULL;
764     void* decodedBuffer = NULL;
765     U32 coreRand = seed;
766     LZ4F_decompressionContext_t dCtx = NULL;
767     LZ4F_compressionContext_t cCtx = NULL;
768     size_t result;
769     clock_t const startClock = clock();
770     clock_t const clockDuration = duration_s * CLOCKS_PER_SEC;
771 #   undef CHECK
772 #   define CHECK(cond, ...) if (cond) { DISPLAY("Error => "); DISPLAY(__VA_ARGS__); \
773                             DISPLAY(" (seed %u, test nb %u)  \n", seed, testNb); goto _output_error; }
774 
775     /* Create buffers */
776     result = LZ4F_createDecompressionContext(&dCtx, LZ4F_VERSION);
777     CHECK(LZ4F_isError(result), "Allocation failed (error %i)", (int)result);
778     result = LZ4F_createCompressionContext(&cCtx, LZ4F_VERSION);
779     CHECK(LZ4F_isError(result), "Allocation failed (error %i)", (int)result);
780     srcBuffer = malloc(srcDataLength);
781     CHECK(srcBuffer==NULL, "srcBuffer Allocation failed");
782     compressedBuffer = malloc(compressedBufferSize);
783     CHECK(compressedBuffer==NULL, "compressedBuffer Allocation failed");
784     decodedBuffer = calloc(1, srcDataLength);   /* calloc avoids decodedBuffer being considered "garbage" by scan-build */
785     CHECK(decodedBuffer==NULL, "decodedBuffer Allocation failed");
786     FUZ_fillCompressibleNoiseBuffer(srcBuffer, srcDataLength, compressibility, &coreRand);
787 
788     /* jump to requested testNb */
789     for (testNb =0; (testNb < startTest); testNb++) (void)FUZ_rand(&coreRand);   /* sync randomizer */
790 
791     /* main fuzzer test loop */
792     for ( ; (testNb < nbTests) || (clockDuration > FUZ_GetClockSpan(startClock)) ; testNb++) {
793         U32 randState = coreRand ^ prime1;
794         unsigned const srcBits = (FUZ_rand(&randState) % (FUZ_highbit((U32)(srcDataLength-1)) - 1)) + 1;
795         size_t const srcSize = (FUZ_rand(&randState) & ((1<<srcBits)-1)) + 1;
796         size_t const srcStartId = FUZ_rand(&randState) % (srcDataLength - srcSize);
797         const BYTE* const srcStart = (const BYTE*)srcBuffer + srcStartId;
798         unsigned const neverFlush = (FUZ_rand(&randState) & 15) == 1;
799         U64 const crcOrig = XXH64(srcStart, srcSize, 1);
800         LZ4F_preferences_t prefs;
801         const LZ4F_preferences_t* prefsPtr = &prefs;
802         size_t cSize;
803 
804         (void)FUZ_rand(&coreRand);   /* update seed */
805         memset(&prefs, 0, sizeof(prefs));
806         prefs.frameInfo.blockMode = (LZ4F_blockMode_t)(FUZ_rand(&randState) & 1);
807         prefs.frameInfo.blockSizeID = (LZ4F_blockSizeID_t)(4 + (FUZ_rand(&randState) & 3));
808         prefs.frameInfo.blockChecksumFlag = (LZ4F_blockChecksum_t)(FUZ_rand(&randState) & 1);
809         prefs.frameInfo.contentChecksumFlag = (LZ4F_contentChecksum_t)(FUZ_rand(&randState) & 1);
810         prefs.frameInfo.contentSize = ((FUZ_rand(&randState) & 0xF) == 1) ? srcSize : 0;
811         prefs.autoFlush = neverFlush ? 0 : (FUZ_rand(&randState) & 7) == 2;
812         prefs.compressionLevel = -5 + (int)(FUZ_rand(&randState) % 11);
813         if ((FUZ_rand(&randState) & 0xF) == 1) prefsPtr = NULL;
814 
815         DISPLAYUPDATE(2, "\r%5u   ", testNb);
816 
817         if ((FUZ_rand(&randState) & 0xFFF) == 0) {
818             /* create a skippable frame (rare case) */
819             BYTE* op = (BYTE*)compressedBuffer;
820             FUZ_writeLE32(op, LZ4F_MAGIC_SKIPPABLE_START + (FUZ_rand(&randState) & 15));
821             FUZ_writeLE32(op+4, (U32)srcSize);
822             cSize = srcSize+8;
823         } else if ((FUZ_rand(&randState) & 0xF) == 2) {  /* single pass compression (simple) */
824             cSize = LZ4F_compressFrame(compressedBuffer, LZ4F_compressFrameBound(srcSize, prefsPtr), srcStart, srcSize, prefsPtr);
825             CHECK(LZ4F_isError(cSize), "LZ4F_compressFrame failed : error %i (%s)", (int)cSize, LZ4F_getErrorName(cSize));
826         } else {   /* multi-segments compression */
827             const BYTE* ip = srcStart;
828             const BYTE* const iend = srcStart + srcSize;
829             BYTE* op = (BYTE*)compressedBuffer;
830             BYTE* const oend = op + (neverFlush ? LZ4F_compressFrameBound(srcSize, prefsPtr) : compressedBufferSize);  /* when flushes are possible, can't guarantee a max compressed size */
831             unsigned const maxBits = FUZ_highbit((U32)srcSize);
832             LZ4F_compressOptions_t cOptions;
833             memset(&cOptions, 0, sizeof(cOptions));
834             result = LZ4F_compressBegin(cCtx, op, oend-op, prefsPtr);
835             CHECK(LZ4F_isError(result), "Compression header failed (error %i)", (int)result);
836             op += result;
837             while (ip < iend) {
838                 unsigned const nbBitsSeg = FUZ_rand(&randState) % maxBits;
839                 size_t const sampleMax = (FUZ_rand(&randState) & ((1<<nbBitsSeg)-1)) + 1;
840                 size_t const iSize = MIN(sampleMax, (size_t)(iend-ip));
841                 size_t const oSize = LZ4F_compressBound(iSize, prefsPtr);
842                 cOptions.stableSrc = ((FUZ_rand(&randState) & 3) == 1);
843                 DISPLAYLEVEL(6, "Sending %zi bytes to compress (stableSrc:%u) \n",
844                                 iSize, cOptions.stableSrc);
845 
846                 result = LZ4F_compressUpdate(cCtx, op, oSize, ip, iSize, &cOptions);
847                 CHECK(LZ4F_isError(result), "Compression failed (error %i : %s)", (int)result, LZ4F_getErrorName(result));
848                 op += result;
849                 ip += iSize;
850 
851                 {   unsigned const forceFlush = neverFlush ? 0 : ((FUZ_rand(&randState) & 3) == 1);
852                     if (forceFlush) {
853                         result = LZ4F_flush(cCtx, op, oend-op, &cOptions);
854                         CHECK(LZ4F_isError(result), "Compression failed (error %i)", (int)result);
855                         op += result;
856                 }   }
857             }
858             CHECK(op>=oend, "LZ4F_compressFrameBound overflow");
859             result = LZ4F_compressEnd(cCtx, op, oend-op, &cOptions);
860             CHECK(LZ4F_isError(result), "Compression completion failed (error %i : %s)", (int)result, LZ4F_getErrorName(result));
861             op += result;
862             cSize = op-(BYTE*)compressedBuffer;
863             DISPLAYLEVEL(5, "\nCompressed %u bytes into %u \n", (U32)srcSize, (U32)cSize);
864         }
865 
866         /* multi-segments decompression */
867         {   const BYTE* ip = (const BYTE*)compressedBuffer;
868             const BYTE* const iend = ip + cSize;
869             BYTE* op = (BYTE*)decodedBuffer;
870             BYTE* const oend = op + srcDataLength;
871             unsigned const suggestedBits = FUZ_highbit((U32)cSize);
872             unsigned const maxBits = MAX(3, suggestedBits);
873             unsigned const nonContiguousDst = FUZ_rand(&randState) % 3;   /* 0 : contiguous; 1 : non-contiguous; 2 : dst overwritten */
874             size_t totalOut = 0;
875             XXH64_state_t xxh64;
876             XXH64_reset(&xxh64, 1);
877             while (ip < iend) {
878                 unsigned const nbBitsI = (FUZ_rand(&randState) % (maxBits-1)) + 1;
879                 unsigned const nbBitsO = (FUZ_rand(&randState) % (maxBits)) + 1;
880                 size_t const iSizeMax = (FUZ_rand(&randState) & ((1<<nbBitsI)-1)) + 1;
881                 size_t iSize = MIN(iSizeMax, (size_t)(iend-ip));
882                 size_t const oSizeMax = (FUZ_rand(&randState) & ((1<<nbBitsO)-1)) + 2;
883                 size_t oSize = MIN(oSizeMax, (size_t)(oend-op));
884                 LZ4F_decompressOptions_t dOptions;
885                 memset(&dOptions, 0, sizeof(dOptions));
886                 dOptions.stableDst = FUZ_rand(&randState) & 1;
887                 if (nonContiguousDst==2) dOptions.stableDst = 0;   /* overwrite mode */
888                 result = LZ4F_decompress(dCtx, op, &oSize, ip, &iSize, &dOptions);
889                 if (LZ4F_getErrorCode(result) == LZ4F_ERROR_contentChecksum_invalid)
890                     locateBuffDiff(srcStart, decodedBuffer, srcSize, nonContiguousDst);
891                 CHECK(LZ4F_isError(result), "Decompression failed (error %i:%s)", (int)result, LZ4F_getErrorName(result));
892                 XXH64_update(&xxh64, op, (U32)oSize);
893                 totalOut += oSize;
894                 op += oSize;
895                 ip += iSize;
896                 op += nonContiguousDst;
897                 if (nonContiguousDst==2) op = (BYTE*)decodedBuffer;   /* overwritten destination */
898             }
899             CHECK(result != 0, "Frame decompression failed (error %i)", (int)result);
900             if (totalOut) {  /* otherwise, it's a skippable frame */
901                 U64 const crcDecoded = XXH64_digest(&xxh64);
902                 if (crcDecoded != crcOrig) locateBuffDiff(srcStart, decodedBuffer, srcSize, nonContiguousDst);
903                 CHECK(crcDecoded != crcOrig, "Decompression corruption");
904             }
905         }
906     }
907 
908     DISPLAYLEVEL(2, "\rAll tests completed   \n");
909 
910 _end:
911     LZ4F_freeDecompressionContext(dCtx);
912     LZ4F_freeCompressionContext(cCtx);
913     free(srcBuffer);
914     free(compressedBuffer);
915     free(decodedBuffer);
916 
917     if (use_pause) {
918         DISPLAY("press enter to finish \n");
919         (void)getchar();
920     }
921     return testResult;
922 
923 _output_error:
924     testResult = 1;
925     goto _end;
926 }
927 
928 
FUZ_usage(const char * programName)929 int FUZ_usage(const char* programName)
930 {
931     DISPLAY( "Usage :\n");
932     DISPLAY( "      %s [args]\n", programName);
933     DISPLAY( "\n");
934     DISPLAY( "Arguments :\n");
935     DISPLAY( " -i#    : Nb of tests (default:%u) \n", nbTestsDefault);
936     DISPLAY( " -T#    : Duration of tests, in seconds (default: use Nb of tests) \n");
937     DISPLAY( " -s#    : Select seed (default:prompt user)\n");
938     DISPLAY( " -t#    : Select starting test number (default:0)\n");
939     DISPLAY( " -P#    : Select compressibility in %% (default:%i%%)\n", FUZ_COMPRESSIBILITY_DEFAULT);
940     DISPLAY( " -v     : verbose\n");
941     DISPLAY( " -h     : display help and exit\n");
942     return 0;
943 }
944 
945 
main(int argc,const char ** argv)946 int main(int argc, const char** argv)
947 {
948     U32 seed=0;
949     int seedset=0;
950     int argNb;
951     int nbTests = nbTestsDefault;
952     int testNb = 0;
953     int proba = FUZ_COMPRESSIBILITY_DEFAULT;
954     int result=0;
955     U32 duration=0;
956     const char* const programName = argv[0];
957 
958     /* Check command line */
959     for (argNb=1; argNb<argc; argNb++) {
960         const char* argument = argv[argNb];
961 
962         if(!argument) continue;   /* Protection if argument empty */
963 
964         /* Decode command (note : aggregated short commands are allowed) */
965         if (argument[0]=='-') {
966             if (!strcmp(argument, "--no-prompt")) {
967                 no_prompt=1;
968                 seedset=1;
969                 displayLevel=1;
970                 continue;
971             }
972             argument++;
973 
974             while (*argument!=0) {
975                 switch(*argument)
976                 {
977                 case 'h':
978                     return FUZ_usage(programName);
979                 case 'v':
980                     argument++;
981                     displayLevel++;
982                     break;
983                 case 'q':
984                     argument++;
985                     displayLevel--;
986                     break;
987                 case 'p': /* pause at the end */
988                     argument++;
989                     use_pause = 1;
990                     break;
991 
992                 case 'i':
993                     argument++;
994                     nbTests=0; duration=0;
995                     while ((*argument>='0') && (*argument<='9')) {
996                         nbTests *= 10;
997                         nbTests += *argument - '0';
998                         argument++;
999                     }
1000                     break;
1001 
1002                 case 'T':
1003                     argument++;
1004                     nbTests = 0; duration = 0;
1005                     for (;;) {
1006                         switch(*argument)
1007                         {
1008                             case 'm': duration *= 60; argument++; continue;
1009                             case 's':
1010                             case 'n': argument++; continue;
1011                             case '0':
1012                             case '1':
1013                             case '2':
1014                             case '3':
1015                             case '4':
1016                             case '5':
1017                             case '6':
1018                             case '7':
1019                             case '8':
1020                             case '9': duration *= 10; duration += *argument++ - '0'; continue;
1021                         }
1022                         break;
1023                     }
1024                     break;
1025 
1026                 case 's':
1027                     argument++;
1028                     seed=0;
1029                     seedset=1;
1030                     while ((*argument>='0') && (*argument<='9')) {
1031                         seed *= 10;
1032                         seed += *argument - '0';
1033                         argument++;
1034                     }
1035                     break;
1036                 case 't':
1037                     argument++;
1038                     testNb=0;
1039                     while ((*argument>='0') && (*argument<='9')) {
1040                         testNb *= 10;
1041                         testNb += *argument - '0';
1042                         argument++;
1043                     }
1044                     break;
1045                 case 'P':   /* compressibility % */
1046                     argument++;
1047                     proba=0;
1048                     while ((*argument>='0') && (*argument<='9')) {
1049                         proba *= 10;
1050                         proba += *argument - '0';
1051                         argument++;
1052                     }
1053                     if (proba<0) proba=0;
1054                     if (proba>100) proba=100;
1055                     break;
1056                 default:
1057                     ;
1058                     return FUZ_usage(programName);
1059                 }
1060             }
1061         }
1062     }
1063 
1064     /* Get Seed */
1065     DISPLAY("Starting lz4frame tester (%i-bits, %s)\n", (int)(sizeof(size_t)*8), LZ4_VERSION_STRING);
1066 
1067     if (!seedset) {
1068         time_t const t = time(NULL);
1069         U32 const h = XXH32(&t, sizeof(t), 1);
1070         seed = h % 10000;
1071     }
1072     DISPLAY("Seed = %u\n", seed);
1073     if (proba!=FUZ_COMPRESSIBILITY_DEFAULT) DISPLAY("Compressibility : %i%%\n", proba);
1074 
1075     if (nbTests<=0) nbTests=1;
1076 
1077     if (testNb==0) result = basicTests(seed, ((double)proba) / 100);
1078     if (result) return 1;
1079     return fuzzerTests(seed, nbTests, testNb, ((double)proba) / 100, duration);
1080 }
1081