xref: /aosp_15_r20/external/lz4/tests/frametest.c (revision 27162e4e17433d5aa7cb38e7b6a433a09405fc7f)
1 /*
2     frameTest - test tool for lz4frame
3     Copyright (C) Yann Collet 2014-2020
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 : 26451)     /* disable: Arithmetic overflow */
31 #  pragma warning(disable : 4127)    /* disable: C4127: conditional expression is constant */
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"   /* included 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 #define LZ4_STATIC_LINKING_ONLY  /* LZ4_DISTANCE_MAX */
50 #include "lz4.h"        /* LZ4_VERSION_STRING */
51 #define XXH_STATIC_LINKING_ONLY
52 #include "xxhash.h"     /* XXH64 */
53 
54 
55 /* unoptimized version; solves endianness & alignment issues */
FUZ_writeLE32(void * dstVoidPtr,U32 value32)56 static void FUZ_writeLE32 (void* dstVoidPtr, U32 value32)
57 {
58     BYTE* const dstPtr = (BYTE*)dstVoidPtr;
59     dstPtr[0] = (BYTE) value32;
60     dstPtr[1] = (BYTE)(value32 >> 8);
61     dstPtr[2] = (BYTE)(value32 >> 16);
62     dstPtr[3] = (BYTE)(value32 >> 24);
63 }
64 
65 
66 /*-************************************
67 *  Constants
68 **************************************/
69 #define KB *(1U<<10)
70 #define MB *(1U<<20)
71 #define GB *(1U<<30)
72 
73 static const U32 nbTestsDefault = 256 KB;
74 #define FUZ_COMPRESSIBILITY_DEFAULT 50
75 static const U32 prime1 = 2654435761U;
76 static const U32 prime2 = 2246822519U;
77 
78 
79 /*-************************************
80 *  Macros
81 **************************************/
82 #define DISPLAY(...)          fprintf(stderr, __VA_ARGS__)
83 #define DISPLAYLEVEL(l, ...)  do { if (displayLevel>=(l)) DISPLAY(__VA_ARGS__); } while (0)
84 #define DISPLAYUPDATE(l, ...) do { if (displayLevel>=(l)) { \
85             if ((FUZ_GetClockSpan(g_clockTime) > refreshRate) || (displayLevel>=4)) \
86             { g_clockTime = clock(); DISPLAY(__VA_ARGS__); \
87             if (displayLevel>=4) fflush(stdout); } } } while (0)
88 static const clock_t refreshRate = CLOCKS_PER_SEC / 6;
89 static clock_t g_clockTime = 0;
90 
91 
92 /*-***************************************
93 *  Local Parameters
94 *****************************************/
95 static U32 no_prompt = 0;
96 static U32 displayLevel = 2;
97 static U32 use_pause = 0;
98 
99 
100 /*-*******************************************************
101 *  Fuzzer functions
102 *********************************************************/
103 #define MIN(a,b)  ( (a) < (b) ? (a) : (b) )
104 #define MAX(a,b)  ( (a) > (b) ? (a) : (b) )
105 
106 typedef struct {
107     int nbAllocs;
108 } Test_alloc_state;
109 static Test_alloc_state g_testAllocState = { 0 };
110 
dummy_malloc(void * state,size_t s)111 static void* dummy_malloc(void* state, size_t s)
112 {
113     Test_alloc_state* const t = (Test_alloc_state*)state;
114     void* const p = malloc(s);
115     if (p==NULL) return NULL;
116     assert(t != NULL);
117     t->nbAllocs += 1;
118     DISPLAYLEVEL(6, "Allocating %u bytes at address %p \n", (unsigned)s, p);
119     DISPLAYLEVEL(5, "nb allocated memory segments : %i \n", t->nbAllocs);
120     return p;
121 }
122 
dummy_calloc(void * state,size_t s)123 static void* dummy_calloc(void* state, size_t s)
124 {
125     Test_alloc_state* const t = (Test_alloc_state*)state;
126     void* const p = calloc(1, s);
127     if (p==NULL) return NULL;
128     assert(t != NULL);
129     t->nbAllocs += 1;
130     DISPLAYLEVEL(6, "Allocating and zeroing %u bytes at address %p \n", (unsigned)s, p);
131     DISPLAYLEVEL(5, "nb allocated memory segments : %i \n", t->nbAllocs);
132     return p;
133 }
134 
dummy_free(void * state,void * p)135 static void dummy_free(void* state, void* p)
136 {
137     Test_alloc_state* const t = (Test_alloc_state*)state;
138     if (p==NULL) {
139         DISPLAYLEVEL(5, "free() on NULL \n");
140         return;
141     }
142     DISPLAYLEVEL(6, "freeing memory at address %p \n", p);
143     free(p);
144     assert(t != NULL);
145     t->nbAllocs -= 1;
146     DISPLAYLEVEL(5, "nb of allocated memory segments after this free : %i \n", t->nbAllocs);
147     assert(t->nbAllocs >= 0);
148 }
149 
150 static const LZ4F_CustomMem lz4f_cmem_test = {
151     dummy_malloc,
152     dummy_calloc,
153     dummy_free,
154     &g_testAllocState
155 };
156 
157 
FUZ_GetClockSpan(clock_t clockStart)158 static clock_t FUZ_GetClockSpan(clock_t clockStart)
159 {
160     return clock() - clockStart;   /* works even if overflow; max span ~ 30 mn */
161 }
162 
163 #define FUZ_rotl32(x,r) ((x << r) | (x >> (32 - r)))
FUZ_rand(unsigned int * src)164 unsigned int FUZ_rand(unsigned int* src)
165 {
166     U32 rand32 = *src;
167     rand32 *= prime1;
168     rand32 += prime2;
169     rand32  = FUZ_rotl32(rand32, 13);
170     *src = rand32;
171     return rand32 >> 5;
172 }
173 
174 #define RAND_BITS(N) (FUZ_rand(randState) & ((1 << (N))-1))
175 #define FUZ_LITERAL (RAND_BITS(6) + '0')
176 #define FUZ_ABOUT(_R) ((FUZ_rand(randState) % (_R)) + (FUZ_rand(randState) % (_R)) + 1)
FUZ_fillCompressibleNoiseBuffer(void * buffer,size_t bufferSize,double proba,U32 * randState)177 static void FUZ_fillCompressibleNoiseBuffer(void* buffer, size_t bufferSize, double proba, U32* randState)
178 {
179     BYTE* BBuffer = (BYTE*)buffer;
180     size_t pos = 0;
181     U32 P32 = (U32)(32768 * proba);
182 
183     /* First Byte */
184     BBuffer[pos++] = FUZ_LITERAL;
185 
186     while (pos < bufferSize) {
187         /* Select : Literal (noise) or copy (within 64K) */
188         if (RAND_BITS(15) < P32) {
189             /* Copy (within 64K) */
190             size_t const lengthRand = FUZ_ABOUT(8) + 4;
191             size_t const length = MIN(lengthRand, bufferSize - pos);
192             size_t const end = pos + length;
193             size_t const offsetRand = RAND_BITS(15) + 1;
194             size_t const offset = MIN(offsetRand, pos);
195             size_t match = pos - offset;
196             while (pos < end) BBuffer[pos++] = BBuffer[match++];
197         } else {
198             /* Literal (noise) */
199             size_t const lengthRand = FUZ_ABOUT(4);
200             size_t const length = MIN(lengthRand, bufferSize - pos);
201             size_t const end = pos + length;
202             while (pos < end) BBuffer[pos++] = FUZ_LITERAL;
203     }   }
204 }
205 
FUZ_highbit(U32 v32)206 static unsigned FUZ_highbit(U32 v32)
207 {
208     unsigned nbBits = 0;
209     if (v32==0) return 0;
210     while (v32) {v32 >>= 1; nbBits ++;}
211     return nbBits;
212 }
213 
214 
215 /*-*******************************************************
216 *  Tests
217 *********************************************************/
218 
219 #define CONTROL(c) { \
220     if (!(c)) {      \
221         DISPLAY("Error (line %i) => %s not respected \n", __LINE__, #c); \
222         return 1;    \
223 }   }
224 
bug1227(void)225 static int bug1227(void)
226 {
227     LZ4F_dctx* dctx;
228     CONTROL(!LZ4F_isError(LZ4F_createDecompressionContext(&dctx, LZ4F_VERSION)));
229 
230     /* first session */
231     {   const char s9Buffer[9] = { 0 };
232         char d9Buffer[sizeof(s9Buffer)];
233         size_t const c9SizeBound = LZ4F_compressFrameBound(sizeof(s9Buffer), NULL);
234         void* const c9Buffer = malloc(c9SizeBound);
235         /* First compress a valid frame */
236         LZ4F_preferences_t pref = LZ4F_INIT_PREFERENCES;
237         pref.frameInfo.contentSize = sizeof(s9Buffer);
238         CONTROL(c9Buffer != NULL);
239         {   size_t const c9Size = LZ4F_compressFrame(c9Buffer, c9SizeBound, s9Buffer, sizeof(s9Buffer), &pref);
240             CONTROL(!LZ4F_isError(c9Size));
241             assert(c9Size > 15);
242             /* decompress it, but do not complete the process - state not terminated correctly */
243             {   size_t dstSize = sizeof(d9Buffer);
244                 size_t srcSize = 15;
245                 size_t const d9Size = LZ4F_decompress(dctx, d9Buffer, &dstSize, c9Buffer, &srcSize, NULL);
246                 CONTROL(!LZ4F_isError(d9Size));
247                 CONTROL(srcSize < c9Size); /* not entirely consumed */
248             }
249         }
250         free(c9Buffer);
251     }
252     LZ4F_resetDecompressionContext(dctx); /* unfinished session -> reset should make it clean */
253 
254     /* second session : generate a valid 0-size frame with no content size field (default) */
255     {   size_t const c0SizeBound = LZ4F_compressFrameBound(0, NULL);
256         void* const c0Buffer = malloc(c0SizeBound);
257         char d0Buffer[1];
258         CONTROL(c0Buffer != NULL);
259         {   size_t const c0Size = LZ4F_compressFrame(c0Buffer, c0SizeBound, NULL, 0, NULL);
260             CONTROL(!LZ4F_isError(c0Size));
261             /* now decompress this valid empty frame */
262             {   size_t dstSize = sizeof(d0Buffer);
263                 size_t srcSize = c0Size;
264                 size_t const d0Size = LZ4F_decompress(dctx, d0Buffer, &dstSize, c0Buffer, &srcSize, NULL);
265                 CONTROL(!LZ4F_isError(d0Size));
266                 CONTROL(dstSize == 0);
267                 CONTROL(srcSize == c0Size);
268         }   }
269         free(c0Buffer);
270     }
271 
272     LZ4F_freeDecompressionContext(dctx);
273     return 0;
274 }
275 
276 #define CHECK_V(v,f) v = f; if (LZ4F_isError(v)) { fprintf(stderr, "%s \n", LZ4F_getErrorName(v)); goto _output_error; }
277 #define CHECK(f)   { LZ4F_errorCode_t const CHECK_V(err_ , f); }
278 
unitTests(U32 seed,double compressibility)279 static int unitTests(U32 seed, double compressibility)
280 {
281 #define COMPRESSIBLE_NOISE_LENGTH (2 MB)
282     void* const CNBuffer = malloc(COMPRESSIBLE_NOISE_LENGTH);
283     size_t const cBuffSize = LZ4F_compressFrameBound(COMPRESSIBLE_NOISE_LENGTH, NULL);
284     void* const compressedBuffer = malloc(cBuffSize);
285     void* const decodedBuffer = malloc(COMPRESSIBLE_NOISE_LENGTH);
286     U32 randVal = seed;
287     U32* const randState = &randVal;
288     size_t cSize, testSize;
289     LZ4F_decompressionContext_t dCtx = NULL;
290     LZ4F_compressionContext_t cctx = NULL;
291     U64 crcOrig;
292     int basicTests_error = 0;
293     LZ4F_preferences_t prefs;
294     memset(&prefs, 0, sizeof(prefs));
295 
296     if (!CNBuffer || !compressedBuffer || !decodedBuffer) {
297         DISPLAY("allocation error, not enough memory to start fuzzer tests \n");
298         goto _output_error;
299     }
300     FUZ_fillCompressibleNoiseBuffer(CNBuffer, COMPRESSIBLE_NOISE_LENGTH, compressibility, randState);
301     crcOrig = XXH64(CNBuffer, COMPRESSIBLE_NOISE_LENGTH, 1);
302 
303     /* LZ4F_compressBound() : special case : srcSize == 0 */
304     DISPLAYLEVEL(3, "LZ4F_compressBound(0) = ");
305     {   size_t const cBound = LZ4F_compressBound(0, NULL);
306         if (cBound < 64 KB) goto _output_error;
307         DISPLAYLEVEL(3, " %u \n", (U32)cBound);
308     }
309 
310     /* LZ4F_compressBound() : special case : automatic flushing enabled */
311     DISPLAYLEVEL(3, "LZ4F_compressBound(1 KB, autoFlush=1) = ");
312     {   size_t cBound;
313         LZ4F_preferences_t autoFlushPrefs;
314         memset(&autoFlushPrefs, 0, sizeof(autoFlushPrefs));
315         autoFlushPrefs.autoFlush = 1;
316         cBound = LZ4F_compressBound(1 KB, &autoFlushPrefs);
317         if (cBound > 64 KB) goto _output_error;
318         DISPLAYLEVEL(3, " %u \n", (U32)cBound);
319     }
320 
321     /* LZ4F_compressBound() : special case : automatic flushing disabled */
322     DISPLAYLEVEL(3, "LZ4F_compressBound(1 KB, autoFlush=0) = ");
323     {   size_t const cBound = LZ4F_compressBound(1 KB, &prefs);
324         if (cBound < 64 KB) goto _output_error;
325         DISPLAYLEVEL(3, " %u \n", (U32)cBound);
326     }
327 
328     /* Special case : null-content frame */
329     testSize = 0;
330     DISPLAYLEVEL(3, "LZ4F_compressFrame, compress null content : ");
331     CHECK_V(cSize, LZ4F_compressFrame(compressedBuffer, LZ4F_compressFrameBound(testSize, NULL), CNBuffer, testSize, NULL));
332     DISPLAYLEVEL(3, "null content encoded into a %u bytes frame \n", (unsigned)cSize);
333 
334     DISPLAYLEVEL(3, "LZ4F_createDecompressionContext \n");
335     CHECK ( LZ4F_createDecompressionContext(&dCtx, LZ4F_VERSION) );
336 
337     DISPLAYLEVEL(3, "LZ4F_getFrameInfo on null-content frame (#157) \n");
338     assert(cSize >= LZ4F_MIN_SIZE_TO_KNOW_HEADER_LENGTH);
339     {   LZ4F_frameInfo_t frame_info;
340         size_t const fhs = LZ4F_headerSize(compressedBuffer, LZ4F_MIN_SIZE_TO_KNOW_HEADER_LENGTH);
341         size_t avail_in = fhs;
342         CHECK( fhs );
343         CHECK( LZ4F_getFrameInfo(dCtx, &frame_info, compressedBuffer, &avail_in) );
344         if (avail_in != fhs) goto _output_error;  /* must consume all, since header size is supposed to be exact */
345     }
346 
347     DISPLAYLEVEL(3, "LZ4F_freeDecompressionContext \n");
348     CHECK( LZ4F_freeDecompressionContext(dCtx) );
349     dCtx = NULL;
350 
351     /* test one-pass frame compression */
352     testSize = COMPRESSIBLE_NOISE_LENGTH;
353 
354     DISPLAYLEVEL(3, "LZ4F_compressFrame, using fast level -3 : ");
355     {   LZ4F_preferences_t fastCompressPrefs;
356         memset(&fastCompressPrefs, 0, sizeof(fastCompressPrefs));
357         fastCompressPrefs.compressionLevel = -3;
358         CHECK_V(cSize, LZ4F_compressFrame(compressedBuffer, LZ4F_compressFrameBound(testSize, NULL), CNBuffer, testSize, &fastCompressPrefs));
359         DISPLAYLEVEL(3, "Compressed %u bytes into a %u bytes frame \n", (U32)testSize, (U32)cSize);
360     }
361 
362     DISPLAYLEVEL(3, "LZ4F_compressFrame, using default preferences : ");
363     CHECK_V(cSize, LZ4F_compressFrame(compressedBuffer, LZ4F_compressFrameBound(testSize, NULL), CNBuffer, testSize, NULL));
364     DISPLAYLEVEL(3, "Compressed %u bytes into a %u bytes frame \n", (U32)testSize, (U32)cSize);
365 
366     DISPLAYLEVEL(3, "Decompression test : \n");
367     {   size_t decodedBufferSize = COMPRESSIBLE_NOISE_LENGTH;
368         size_t compressedBufferSize = cSize;
369 
370         CHECK( LZ4F_createDecompressionContext(&dCtx, LZ4F_VERSION) );
371 
372         DISPLAYLEVEL(3, "Single Pass decompression : ");
373         CHECK( LZ4F_decompress(dCtx, decodedBuffer, &decodedBufferSize, compressedBuffer, &compressedBufferSize, NULL) );
374         { U64 const crcDest = XXH64(decodedBuffer, decodedBufferSize, 1);
375           if (crcDest != crcOrig) goto _output_error; }
376         DISPLAYLEVEL(3, "Regenerated %u bytes \n", (U32)decodedBufferSize);
377 
378         DISPLAYLEVEL(3, "Reusing decompression context \n");
379         {   size_t const missingBytes = 4;
380             size_t iSize = compressedBufferSize - missingBytes;
381             const BYTE* cBuff = (const BYTE*) compressedBuffer;
382             BYTE* const ostart = (BYTE*)decodedBuffer;
383             BYTE* op = ostart;
384             BYTE* const oend = (BYTE*)decodedBuffer + COMPRESSIBLE_NOISE_LENGTH;
385             size_t decResult, oSize = COMPRESSIBLE_NOISE_LENGTH;
386             DISPLAYLEVEL(3, "Missing last %u bytes : ", (U32)missingBytes);
387             CHECK_V(decResult, LZ4F_decompress(dCtx, op, &oSize, cBuff, &iSize, NULL));
388             if (decResult != missingBytes) {
389                 DISPLAY("%u bytes missing != %u bytes requested \n", (U32)missingBytes, (U32)decResult);
390                 goto _output_error;
391             }
392             DISPLAYLEVEL(3, "indeed, requests %u bytes \n", (unsigned)decResult);
393             cBuff += iSize;
394             iSize = decResult;
395             op += oSize;
396             oSize = (size_t)(oend-op);
397             decResult = LZ4F_decompress(dCtx, op, &oSize, cBuff, &iSize, NULL);
398             if (decResult != 0) goto _output_error;   /* should finish now */
399             op += oSize;
400             if (op>oend) { DISPLAY("decompression write overflow \n"); goto _output_error; }
401             {   U64 const crcDest = XXH64(decodedBuffer, (size_t)(op-ostart), 1);
402                 if (crcDest != crcOrig) goto _output_error;
403         }   }
404 
405         {   size_t oSize = 0;
406             size_t iSize = 0;
407             LZ4F_frameInfo_t fi;
408             const BYTE* ip = (BYTE*)compressedBuffer;
409 
410             DISPLAYLEVEL(3, "Start by feeding 0 bytes, to get next input size : ");
411             CHECK( LZ4F_decompress(dCtx, NULL, &oSize, ip, &iSize, NULL) );
412             //DISPLAYLEVEL(3, " %u  \n", (unsigned)errorCode);
413             DISPLAYLEVEL(3, " OK  \n");
414 
415             DISPLAYLEVEL(3, "LZ4F_getFrameInfo on zero-size input : ");
416             {   size_t nullSize = 0;
417                 size_t const fiError = LZ4F_getFrameInfo(dCtx, &fi, ip, &nullSize);
418                 if (LZ4F_getErrorCode(fiError) != LZ4F_ERROR_frameHeader_incomplete) {
419                     DISPLAYLEVEL(3, "incorrect error : %s != ERROR_frameHeader_incomplete \n",
420                                     LZ4F_getErrorName(fiError));
421                     goto _output_error;
422                 }
423                 DISPLAYLEVEL(3, " correctly failed : %s \n", LZ4F_getErrorName(fiError));
424             }
425 
426             DISPLAYLEVEL(3, "LZ4F_getFrameInfo on not enough input : ");
427             {   size_t inputSize = 6;
428                 size_t const fiError = LZ4F_getFrameInfo(dCtx, &fi, ip, &inputSize);
429                 if (LZ4F_getErrorCode(fiError) != LZ4F_ERROR_frameHeader_incomplete) {
430                     DISPLAYLEVEL(3, "incorrect error : %s != ERROR_frameHeader_incomplete \n", LZ4F_getErrorName(fiError));
431                     goto _output_error;
432                 }
433                 DISPLAYLEVEL(3, " correctly failed : %s \n", LZ4F_getErrorName(fiError));
434             }
435 
436             DISPLAYLEVEL(3, "LZ4F_getFrameInfo on enough input : ");
437             iSize = LZ4F_headerSize(ip, LZ4F_MIN_SIZE_TO_KNOW_HEADER_LENGTH);
438             CHECK( iSize );
439             CHECK( LZ4F_getFrameInfo(dCtx, &fi, ip, &iSize) );
440             DISPLAYLEVEL(3, " correctly decoded \n");
441         }
442 
443         DISPLAYLEVEL(3, "Decode a buggy input : ");
444         assert(COMPRESSIBLE_NOISE_LENGTH > 64);
445         assert(cSize > 48);
446         memcpy(decodedBuffer, (char*)compressedBuffer+16, 32);  /* save correct data */
447         memcpy((char*)compressedBuffer+16, (const char*)decodedBuffer+32, 32);  /* insert noise */
448         {   size_t dbSize = COMPRESSIBLE_NOISE_LENGTH;
449             size_t cbSize = cSize;
450             size_t const decompressError = LZ4F_decompress(dCtx, decodedBuffer, &dbSize,
451                                                                compressedBuffer, &cbSize,
452                                                                NULL);
453             if (!LZ4F_isError(decompressError)) goto _output_error;
454             DISPLAYLEVEL(3, "error detected : %s \n", LZ4F_getErrorName(decompressError));
455         }
456         memcpy((char*)compressedBuffer+16, decodedBuffer, 32);  /* restore correct data */
457 
458         DISPLAYLEVEL(3, "Reset decompression context, since it's left in error state \n");
459         LZ4F_resetDecompressionContext(dCtx);   /* always successful */
460 
461         DISPLAYLEVEL(3, "Byte after byte : ");
462         {   BYTE* const ostart = (BYTE*)decodedBuffer;
463             BYTE* op = ostart;
464             BYTE* const oend = (BYTE*)decodedBuffer + COMPRESSIBLE_NOISE_LENGTH;
465             const BYTE* ip = (const BYTE*) compressedBuffer;
466             const BYTE* const iend = ip + cSize;
467             while (ip < iend) {
468                 size_t oSize = (size_t)(oend-op);
469                 size_t iSize = 1;
470                 CHECK( LZ4F_decompress(dCtx, op, &oSize, ip, &iSize, NULL) );
471                 op += oSize;
472                 ip += iSize;
473             }
474             {   U64 const crcDest = XXH64(decodedBuffer, COMPRESSIBLE_NOISE_LENGTH, 1);
475                 if (crcDest != crcOrig) goto _output_error;
476             }
477             DISPLAYLEVEL(3, "Regenerated %u/%u bytes \n", (unsigned)(op-ostart), (unsigned)COMPRESSIBLE_NOISE_LENGTH);
478         }
479     }
480 
481     DISPLAYLEVEL(3, "Using 64 KB block : ");
482     prefs.frameInfo.blockSizeID = LZ4F_max64KB;
483     prefs.frameInfo.contentChecksumFlag = LZ4F_contentChecksumEnabled;
484     CHECK_V(cSize, LZ4F_compressFrame(compressedBuffer, LZ4F_compressFrameBound(testSize, &prefs), CNBuffer, testSize, &prefs));
485     DISPLAYLEVEL(3, "Compressed %i bytes into a %i bytes frame \n", (int)testSize, (int)cSize);
486 
487     DISPLAYLEVEL(3, "without checksum : ");
488     prefs.frameInfo.contentChecksumFlag = LZ4F_noContentChecksum;
489     CHECK_V(cSize, LZ4F_compressFrame(compressedBuffer, LZ4F_compressFrameBound(testSize, &prefs), CNBuffer, testSize, &prefs));
490     DISPLAYLEVEL(3, "Compressed %i bytes into a %i bytes frame \n", (int)testSize, (int)cSize);
491 
492     DISPLAYLEVEL(3, "Using 256 KB block : ");
493     prefs.frameInfo.blockSizeID = LZ4F_max256KB;
494     prefs.frameInfo.contentChecksumFlag = LZ4F_contentChecksumEnabled;
495     CHECK_V(cSize, LZ4F_compressFrame(compressedBuffer, LZ4F_compressFrameBound(testSize, &prefs), CNBuffer, testSize, &prefs));
496     DISPLAYLEVEL(3, "Compressed %i bytes into a %i bytes frame \n", (int)testSize, (int)cSize);
497 
498     DISPLAYLEVEL(3, "Decompression test : \n");
499     {   size_t const decodedBufferSize = COMPRESSIBLE_NOISE_LENGTH;
500         unsigned const maxBits = FUZ_highbit((U32)decodedBufferSize);
501         BYTE* const ostart = (BYTE*)decodedBuffer;
502         BYTE* op = ostart;
503         BYTE* const oend = ostart + COMPRESSIBLE_NOISE_LENGTH;
504         const BYTE* ip = (const BYTE*)compressedBuffer;
505         const BYTE* const iend = (const BYTE*)compressedBuffer + cSize;
506 
507         DISPLAYLEVEL(3, "random segment sizes : ");
508         while (ip < iend) {
509             unsigned const nbBits = FUZ_rand(randState) % maxBits;
510             size_t iSize = RAND_BITS(nbBits) + 1;
511             size_t oSize = (size_t)(oend-op);
512             if (iSize > (size_t)(iend-ip)) iSize = (size_t)(iend-ip);
513             CHECK( LZ4F_decompress(dCtx, op, &oSize, ip, &iSize, NULL) );
514             op += oSize;
515             ip += iSize;
516         }
517         {   size_t const decodedSize = (size_t)(op - ostart);
518             U64 const crcDest = XXH64(decodedBuffer, decodedSize, 1);
519             if (crcDest != crcOrig) goto _output_error;
520             DISPLAYLEVEL(3, "Regenerated %u bytes \n", (U32)decodedSize);
521          }
522 
523         CHECK( LZ4F_freeDecompressionContext(dCtx) );
524         dCtx = NULL;
525     }
526 
527     DISPLAYLEVEL(3, "without checksum : ");
528     prefs.frameInfo.contentChecksumFlag = LZ4F_noContentChecksum;
529     CHECK_V(cSize, LZ4F_compressFrame(compressedBuffer, LZ4F_compressFrameBound(testSize, &prefs), CNBuffer, testSize, &prefs) );
530     DISPLAYLEVEL(3, "Compressed %i bytes into a %i bytes frame \n", (int)testSize, (int)cSize);
531 
532     DISPLAYLEVEL(3, "Using 1 MB block : ");
533     prefs.frameInfo.blockSizeID = LZ4F_max1MB;
534     prefs.frameInfo.contentChecksumFlag = LZ4F_contentChecksumEnabled;
535     CHECK_V(cSize, LZ4F_compressFrame(compressedBuffer, LZ4F_compressFrameBound(testSize, &prefs), CNBuffer, testSize, &prefs) );
536     DISPLAYLEVEL(3, "Compressed %i bytes into a %i bytes frame \n", (int)testSize, (int)cSize);
537 
538     DISPLAYLEVEL(3, "without frame checksum : ");
539     prefs.frameInfo.contentChecksumFlag = LZ4F_noContentChecksum;
540     CHECK_V(cSize, LZ4F_compressFrame(compressedBuffer, LZ4F_compressFrameBound(testSize, &prefs), CNBuffer, testSize, &prefs) );
541     DISPLAYLEVEL(3, "Compressed %i bytes into a %i bytes frame \n", (int)testSize, (int)cSize);
542 
543     DISPLAYLEVEL(3, "Using 4 MB block : ");
544     prefs.frameInfo.blockSizeID = LZ4F_max4MB;
545     prefs.frameInfo.contentChecksumFlag = LZ4F_contentChecksumEnabled;
546     {   size_t const dstCapacity = LZ4F_compressFrameBound(testSize, &prefs);
547         DISPLAYLEVEL(4, "dstCapacity = %u  ; ", (U32)dstCapacity);
548         CHECK_V(cSize, LZ4F_compressFrame(compressedBuffer, dstCapacity, CNBuffer, testSize, &prefs) );
549         DISPLAYLEVEL(3, "Compressed %u bytes into a %u bytes frame \n", (U32)testSize, (U32)cSize);
550     }
551 
552     DISPLAYLEVEL(3, "without frame checksum : ");
553     prefs.frameInfo.contentChecksumFlag = LZ4F_noContentChecksum;
554     {   size_t const dstCapacity = LZ4F_compressFrameBound(testSize, &prefs);
555         DISPLAYLEVEL(4, "dstCapacity = %u  ; ", (U32)dstCapacity);
556         CHECK_V(cSize, LZ4F_compressFrame(compressedBuffer, dstCapacity, CNBuffer, testSize, &prefs) );
557         DISPLAYLEVEL(3, "Compressed %u bytes into a %u bytes frame \n", (U32)testSize, (U32)cSize);
558     }
559 
560     DISPLAYLEVEL(3, "LZ4F_compressFrame with block checksum : ");
561     memset(&prefs, 0, sizeof(prefs));
562     prefs.frameInfo.blockChecksumFlag = LZ4F_blockChecksumEnabled;
563     CHECK_V(cSize, LZ4F_compressFrame(compressedBuffer, LZ4F_compressFrameBound(testSize, &prefs), CNBuffer, testSize, &prefs) );
564     DISPLAYLEVEL(3, "Compressed %i bytes into a %i bytes frame \n", (int)testSize, (int)cSize);
565 
566     DISPLAYLEVEL(3, "Decompress with block checksum : ");
567     {   size_t iSize = cSize;
568         size_t decodedSize = COMPRESSIBLE_NOISE_LENGTH;
569         LZ4F_decompressionContext_t dctx;
570         CHECK( LZ4F_createDecompressionContext(&dctx, LZ4F_VERSION) );
571         CHECK( LZ4F_decompress(dctx, decodedBuffer, &decodedSize, compressedBuffer, &iSize, NULL) );
572         if (decodedSize != testSize) goto _output_error;
573         if (iSize != cSize) goto _output_error;
574         {   U64 const crcDest = XXH64(decodedBuffer, decodedSize, 1);
575             U64 const crcSrc = XXH64(CNBuffer, testSize, 1);
576             if (crcDest != crcSrc) goto _output_error;
577         }
578         DISPLAYLEVEL(3, "Regenerated %u bytes \n", (U32)decodedSize);
579 
580         CHECK( LZ4F_freeDecompressionContext(dctx) );
581     }
582 
583     /* frame content size tests */
584     {   size_t cErr;
585         BYTE* const ostart = (BYTE*)compressedBuffer;
586         BYTE* op = ostart;
587         CHECK( LZ4F_createCompressionContext(&cctx, LZ4F_VERSION) );
588 
589         DISPLAYLEVEL(3, "compress without frameSize : ");
590         memset(&(prefs.frameInfo), 0, sizeof(prefs.frameInfo));
591         CHECK_V(cErr, LZ4F_compressBegin(cctx, compressedBuffer, testSize, &prefs));
592         op += cErr;
593         CHECK_V(cErr, LZ4F_compressUpdate(cctx, op, LZ4F_compressBound(testSize, &prefs), CNBuffer, testSize, NULL));
594         op += cErr;
595         CHECK( LZ4F_compressEnd(cctx, compressedBuffer, testSize, NULL) );
596         DISPLAYLEVEL(3, "Compressed %i bytes into a %i bytes frame \n", (int)testSize, (int)(op-ostart));
597 
598         DISPLAYLEVEL(3, "compress with frameSize : ");
599         prefs.frameInfo.contentSize = testSize;
600         op = ostart;
601         CHECK_V(cErr, LZ4F_compressBegin(cctx, compressedBuffer, testSize, &prefs));
602         op += cErr;
603         CHECK_V(cErr, LZ4F_compressUpdate(cctx, op, LZ4F_compressBound(testSize, &prefs), CNBuffer, testSize, NULL));
604         op += cErr;
605         CHECK( LZ4F_compressEnd(cctx, compressedBuffer, testSize, NULL) );
606         DISPLAYLEVEL(3, "Compressed %i bytes into a %i bytes frame \n", (int)testSize, (int)(op-ostart));
607 
608         DISPLAYLEVEL(3, "compress with wrong frameSize : ");
609         prefs.frameInfo.contentSize = testSize+1;
610         op = ostart;
611         CHECK_V(cErr, LZ4F_compressBegin(cctx, compressedBuffer, testSize, &prefs));
612         op += cErr;
613         CHECK_V(cErr, LZ4F_compressUpdate(cctx, op, LZ4F_compressBound(testSize, &prefs), CNBuffer, testSize, NULL));
614         op += cErr;
615         cErr = LZ4F_compressEnd(cctx, op, testSize, NULL);
616         if (!LZ4F_isError(cErr)) goto _output_error;
617         DISPLAYLEVEL(3, "Error correctly detected : %s \n", LZ4F_getErrorName(cErr));
618 
619         CHECK( LZ4F_freeCompressionContext(cctx) );
620         cctx = NULL;
621     }
622 
623     /* dictID tests */
624     {   size_t cErr;
625         U32 const dictID = 0x99;
626         /* test advanced variant with custom allocator functions */
627         cctx = LZ4F_createCompressionContext_advanced(lz4f_cmem_test, LZ4F_VERSION);
628         if (cctx==NULL) goto _output_error;
629 
630         DISPLAYLEVEL(3, "insert a dictID : ");
631         memset(&prefs.frameInfo, 0, sizeof(prefs.frameInfo));
632         prefs.frameInfo.dictID = dictID;
633         CHECK_V(cErr, LZ4F_compressBegin(cctx, compressedBuffer, testSize, &prefs));
634         DISPLAYLEVEL(3, "created frame header of size %i bytes  \n", (int)cErr);
635 
636         DISPLAYLEVEL(3, "read a dictID : ");
637         CHECK( LZ4F_createDecompressionContext(&dCtx, LZ4F_VERSION) );
638         memset(&prefs.frameInfo, 0, sizeof(prefs.frameInfo));
639         CHECK( LZ4F_getFrameInfo(dCtx, &prefs.frameInfo, compressedBuffer, &cErr) );
640         if (prefs.frameInfo.dictID != dictID) goto _output_error;
641         DISPLAYLEVEL(3, "%u \n", (U32)prefs.frameInfo.dictID);
642 
643         CHECK( LZ4F_freeDecompressionContext(dCtx) ); dCtx = NULL;
644         CHECK( LZ4F_freeCompressionContext(cctx) ); cctx = NULL;
645     }
646 
647     /* Raw Dictionary compression test */
648     {   size_t const dictSize = 7 KB; /* small enough for LZ4_MEMORY_USAGE == 10 */
649         size_t const srcSize = 66 KB; /* must be > 64 KB to avoid short-size optimizations */
650         size_t const dstCapacity = LZ4F_compressFrameBound(srcSize, NULL);
651         size_t cSizeNoDict, cSizeWithDict;
652         const void* dict = CNBuffer;
653         const void* src = (const char*)CNBuffer + dictSize;
654         char* cPtr = (char*)compressedBuffer;
655         CHECK( LZ4F_createCompressionContext(&cctx, LZ4F_VERSION) );
656 
657         /* compress without dictionary, just to establish a comparison point */
658         CHECK_V(cSizeNoDict,
659                 LZ4F_compressFrame(compressedBuffer, dstCapacity,
660                                     src, srcSize,
661                                     NULL) );
662         /* note: NULL preferences ==> 64 KB linked blocks */
663 
664         /* now compress with dictionary */
665         DISPLAYLEVEL(3, "LZ4F_compressBegin_usingDict: ");
666         cSizeWithDict = 0;
667         {   size_t hSize = LZ4F_compressBegin_usingDict(cctx, cPtr, dstCapacity, dict, dictSize, NULL);
668             //size_t hSize = LZ4F_compressBegin(cctx, cPtr, dstCapacity, NULL);
669             CHECK(hSize);
670             cSizeWithDict += hSize;
671             cPtr += hSize;
672         }
673         {   size_t bSize = LZ4F_compressUpdate(cctx, cPtr, dstCapacity, src, srcSize, NULL);
674             CHECK(bSize);
675             cSizeWithDict += bSize;
676             cPtr += bSize;
677         }
678         {   size_t endSize = LZ4F_compressEnd(cctx, cPtr, dstCapacity, NULL);
679             CHECK(endSize);
680             cSizeWithDict += endSize;
681         }
682         DISPLAYLEVEL(3, "compress %u bytes into %u bytes with dict (< %u bytes without) \n",
683                         (unsigned)srcSize, (unsigned)cSizeWithDict, (unsigned)cSizeNoDict);
684         if (cSizeWithDict >= cSizeNoDict) {
685             DISPLAYLEVEL(3, "cSizeWithDict (%u) should have been more compact than cSizeNoDict(%u) \n", (unsigned)cSizeWithDict, (unsigned)cSizeNoDict);
686             goto _output_error;  /* must be more efficient */
687         }
688         crcOrig = XXH64(src, srcSize, 0);
689 
690         DISPLAYLEVEL(3, "LZ4F_decompress_usingDict: ");
691         {   LZ4F_dctx* dctx;
692             size_t decodedSize = srcSize;
693             size_t compressedSize = cSizeWithDict;
694             CHECK( LZ4F_createDecompressionContext(&dctx, LZ4F_VERSION) );
695             CHECK( LZ4F_decompress_usingDict(dctx,
696                                         decodedBuffer, &decodedSize,
697                                         compressedBuffer, &compressedSize,
698                                         CNBuffer, dictSize,
699                                         NULL) );
700             if (compressedSize != cSizeWithDict) goto _output_error;
701             if (decodedSize != srcSize) goto _output_error;
702             { U64 const crcDest = XXH64(decodedBuffer, decodedSize, 0);
703               if (crcDest != crcOrig) goto _output_error; }
704             DISPLAYLEVEL(3, "Regenerated %u bytes \n", (U32)decodedSize);
705             CHECK( LZ4F_freeDecompressionContext(dctx) );
706         }
707 
708         /* clean */
709         CHECK( LZ4F_freeCompressionContext(cctx) );
710     }
711 
712     /* Digested Dictionary (cdict) compression test */
713     {   size_t const dictSize = 7 KB; /* small enough for LZ4_MEMORY_USAGE == 10 */
714         size_t const srcSize = 65 KB; /* must be > 64 KB to avoid short-size optimizations */
715         size_t const dstCapacity = LZ4F_compressFrameBound(srcSize, NULL);
716         size_t cSizeNoDict, cSizeWithDict;
717         LZ4F_CDict* const cdict = LZ4F_createCDict(CNBuffer, dictSize);
718         if (cdict == NULL) goto _output_error;
719         CHECK( LZ4F_createCompressionContext(&cctx, LZ4F_VERSION) );
720 
721         DISPLAYLEVEL(3, "Testing LZ4F_createCDict_advanced : ");
722         {   LZ4F_CDict* const cda = LZ4F_createCDict_advanced(lz4f_cmem_test, CNBuffer, dictSize);
723             if (cda == NULL) goto _output_error;
724             LZ4F_freeCDict(cda);
725         }
726         DISPLAYLEVEL(3, "OK \n");
727 
728         DISPLAYLEVEL(3, "LZ4F_compressFrame_usingCDict, with NULL dict : ");
729         CHECK_V(cSizeNoDict,
730                 LZ4F_compressFrame_usingCDict(cctx, compressedBuffer, dstCapacity,
731                                               CNBuffer, srcSize,
732                                               NULL, NULL) );
733         DISPLAYLEVEL(3, "%u bytes \n", (unsigned)cSizeNoDict);
734 
735         DISPLAYLEVEL(3, "LZ4F_compressFrame_usingCDict, with dict : ");
736         CHECK( LZ4F_freeCompressionContext(cctx) );
737         CHECK( LZ4F_createCompressionContext(&cctx, LZ4F_VERSION) );
738         CHECK_V(cSizeWithDict,
739                 LZ4F_compressFrame_usingCDict(cctx, compressedBuffer, dstCapacity,
740                                               CNBuffer, srcSize,
741                                               cdict, NULL) );
742         DISPLAYLEVEL(3, "compressed %u bytes into %u bytes \n",
743                         (unsigned)srcSize, (unsigned)cSizeWithDict);
744         if (cSizeWithDict > cSizeNoDict) {
745             DISPLAYLEVEL(3, "cSizeWithDict (%u) should have been more compact than cSizeNoDict(%u) \n", (unsigned)cSizeWithDict, (unsigned)cSizeNoDict);
746             goto _output_error;  /* must be more efficient */
747         }
748         crcOrig = XXH64(CNBuffer, srcSize, 0);
749 
750         DISPLAYLEVEL(3, "LZ4F_decompress_usingDict : ");
751         {   LZ4F_dctx* dctx;
752             size_t decodedSize = srcSize;
753             size_t compressedSize = cSizeWithDict;
754             CHECK( LZ4F_createDecompressionContext(&dctx, LZ4F_VERSION) );
755             CHECK( LZ4F_decompress_usingDict(dctx,
756                                         decodedBuffer, &decodedSize,
757                                         compressedBuffer, &compressedSize,
758                                         CNBuffer, dictSize,
759                                         NULL) );
760             if (compressedSize != cSizeWithDict) goto _output_error;
761             if (decodedSize != srcSize) goto _output_error;
762             { U64 const crcDest = XXH64(decodedBuffer, decodedSize, 0);
763               if (crcDest != crcOrig) goto _output_error; }
764             DISPLAYLEVEL(3, "Regenerated %u bytes \n", (U32)decodedSize);
765             CHECK( LZ4F_freeDecompressionContext(dctx) );
766         }
767 
768         DISPLAYLEVEL(3, "LZ4F_compressFrame_usingCDict, with dict, negative level : ");
769         {   size_t cSizeLevelMax;
770             LZ4F_preferences_t cParams;
771             memset(&cParams, 0, sizeof(cParams));
772             cParams.compressionLevel = -3;
773             CHECK_V(cSizeLevelMax,
774                 LZ4F_compressFrame_usingCDict(cctx, compressedBuffer, dstCapacity,
775                                               CNBuffer, dictSize,
776                                               cdict, &cParams) );
777             DISPLAYLEVEL(3, "%u bytes \n", (unsigned)cSizeLevelMax);
778         }
779 
780         DISPLAYLEVEL(3, "LZ4F_compressFrame_usingCDict, with dict, level max : ");
781         {   size_t cSizeLevelMax;
782             LZ4F_preferences_t cParams;
783             memset(&cParams, 0, sizeof(cParams));
784             cParams.compressionLevel = LZ4F_compressionLevel_max();
785             CHECK_V(cSizeLevelMax,
786                 LZ4F_compressFrame_usingCDict(cctx, compressedBuffer, dstCapacity,
787                                               CNBuffer, dictSize,
788                                               cdict, &cParams) );
789             DISPLAYLEVEL(3, "%u bytes \n", (unsigned)cSizeLevelMax);
790         }
791 
792         DISPLAYLEVEL(3, "LZ4F_compressFrame_usingCDict, multiple linked blocks : ");
793         {   size_t cSizeContiguous;
794             size_t const inSize = dictSize * 3;
795             size_t const outCapacity = LZ4F_compressFrameBound(inSize, NULL);
796             LZ4F_preferences_t cParams;
797             memset(&cParams, 0, sizeof(cParams));
798             cParams.frameInfo.blockMode = LZ4F_blockLinked;
799             cParams.frameInfo.blockSizeID = LZ4F_max64KB;
800             CHECK_V(cSizeContiguous,
801                 LZ4F_compressFrame_usingCDict(cctx, compressedBuffer, outCapacity,
802                                               CNBuffer, inSize,
803                                               cdict, &cParams) );
804             DISPLAYLEVEL(3, "compressed %u bytes into %u bytes \n",
805                         (unsigned)inSize, (unsigned)cSizeContiguous);
806 
807             DISPLAYLEVEL(3, "LZ4F_decompress_usingDict on multiple linked blocks : ");
808             {   LZ4F_dctx* dctx;
809                 size_t decodedSize = COMPRESSIBLE_NOISE_LENGTH;
810                 size_t compressedSize = cSizeContiguous;
811                 CHECK( LZ4F_createDecompressionContext(&dctx, LZ4F_VERSION) );
812                 CHECK( LZ4F_decompress_usingDict(dctx,
813                                             decodedBuffer, &decodedSize,
814                                             compressedBuffer, &compressedSize,
815                                             CNBuffer, dictSize,
816                                             NULL) );
817                 if (compressedSize != cSizeContiguous) goto _output_error;
818                 if (decodedSize != inSize) goto _output_error;
819                 crcOrig = XXH64(CNBuffer, inSize, 0);
820                 { U64 const crcDest = XXH64(decodedBuffer, decodedSize, 0);
821                   if (crcDest != crcOrig) goto _output_error; }
822                 DISPLAYLEVEL(3, "Regenerated %u bytes \n", (U32)decodedSize);
823                 CHECK( LZ4F_freeDecompressionContext(dctx) );
824             }
825         }
826 
827         DISPLAYLEVEL(3, "LZ4F_compressFrame_usingCDict, multiple independent blocks : ");
828         {   size_t cSizeIndep;
829             size_t const inSize = dictSize * 3;
830             size_t const outCapacity = LZ4F_compressFrameBound(inSize, NULL);
831             LZ4F_preferences_t cParams;
832             memset(&cParams, 0, sizeof(cParams));
833             cParams.frameInfo.blockMode = LZ4F_blockIndependent;
834             cParams.frameInfo.blockSizeID = LZ4F_max64KB;
835             CHECK_V(cSizeIndep,
836                 LZ4F_compressFrame_usingCDict(cctx, compressedBuffer, outCapacity,
837                                               CNBuffer, inSize,
838                                               cdict, &cParams) );
839             DISPLAYLEVEL(3, "compressed %u bytes into %u bytes \n",
840                         (unsigned)inSize, (unsigned)cSizeIndep);
841 
842             DISPLAYLEVEL(3, "LZ4F_decompress_usingDict on multiple independent blocks : ");
843             {   LZ4F_dctx* dctx;
844                 size_t decodedSize = COMPRESSIBLE_NOISE_LENGTH;
845                 size_t compressedSize = cSizeIndep;
846                 CHECK( LZ4F_createDecompressionContext(&dctx, LZ4F_VERSION) );
847                 CHECK( LZ4F_decompress_usingDict(dctx,
848                                             decodedBuffer, &decodedSize,
849                                             compressedBuffer, &compressedSize,
850                                             CNBuffer, dictSize,
851                                             NULL) );
852                 if (compressedSize != cSizeIndep) goto _output_error;
853                 if (decodedSize != inSize) goto _output_error;
854                 crcOrig = XXH64(CNBuffer, inSize, 0);
855                 { U64 const crcDest = XXH64(decodedBuffer, decodedSize, 0);
856                   if (crcDest != crcOrig) goto _output_error; }
857                 DISPLAYLEVEL(3, "Regenerated %u bytes \n", (U32)decodedSize);
858                 CHECK( LZ4F_freeDecompressionContext(dctx) );
859             }
860         }
861 
862         LZ4F_freeCDict(cdict);
863         CHECK( LZ4F_freeCompressionContext(cctx) ); cctx = NULL;
864     }
865 
866     DISPLAYLEVEL(3, "getBlockSize test: \n");
867     { size_t result;
868       unsigned blockSizeID;
869       for (blockSizeID = 4; blockSizeID < 8; ++blockSizeID) {
870         result = LZ4F_getBlockSize((LZ4F_blockSizeID_t)blockSizeID);
871         CHECK(result);
872         DISPLAYLEVEL(3, "Returned block size of %u bytes for blockID %u \n",
873                          (unsigned)result, blockSizeID);
874       }
875 
876       /* Test an invalid input that's too large */
877       result = LZ4F_getBlockSize((LZ4F_blockSizeID_t)8);
878       if(!LZ4F_isError(result) ||
879           LZ4F_getErrorCode(result) != LZ4F_ERROR_maxBlockSize_invalid)
880         goto _output_error;
881 
882       /* Test an invalid input that's too small */
883       result = LZ4F_getBlockSize((LZ4F_blockSizeID_t)3);
884       if(!LZ4F_isError(result) ||
885           LZ4F_getErrorCode(result) != LZ4F_ERROR_maxBlockSize_invalid)
886         goto _output_error;
887     }
888 
889     DISPLAYLEVEL(3, "check bug1227: reused dctx after error => ");
890     if (bug1227()) goto _output_error;
891     DISPLAYLEVEL(3, "OK \n");
892 
893     DISPLAYLEVEL(3, "Skippable frame test : \n");
894     {   size_t decodedBufferSize = COMPRESSIBLE_NOISE_LENGTH;
895         unsigned maxBits = FUZ_highbit((U32)decodedBufferSize);
896         BYTE* op = (BYTE*)decodedBuffer;
897         BYTE* const oend = (BYTE*)decodedBuffer + COMPRESSIBLE_NOISE_LENGTH;
898         BYTE* ip = (BYTE*)compressedBuffer;
899         BYTE* iend = (BYTE*)compressedBuffer + cSize + 8;
900 
901         CHECK( LZ4F_createDecompressionContext(&dCtx, LZ4F_VERSION) );
902 
903         /* generate skippable frame */
904         FUZ_writeLE32(ip, LZ4F_MAGIC_SKIPPABLE_START);
905         FUZ_writeLE32(ip+4, (U32)cSize);
906 
907         DISPLAYLEVEL(3, "random segment sizes : \n");
908         while (ip < iend) {
909             unsigned nbBits = FUZ_rand(randState) % maxBits;
910             size_t iSize = RAND_BITS(nbBits) + 1;
911             size_t oSize = (size_t)(oend-op);
912             if (iSize > (size_t)(iend-ip)) iSize = (size_t)(iend-ip);
913             CHECK( LZ4F_decompress(dCtx, op, &oSize, ip, &iSize, NULL) );
914             op += oSize;
915             ip += iSize;
916         }
917         DISPLAYLEVEL(3, "Skipped %i bytes \n", (int)decodedBufferSize);
918 
919         /* generate zero-size skippable frame */
920         DISPLAYLEVEL(3, "zero-size skippable frame\n");
921         ip = (BYTE*)compressedBuffer;
922         op = (BYTE*)decodedBuffer;
923         FUZ_writeLE32(ip, LZ4F_MAGIC_SKIPPABLE_START+1);
924         FUZ_writeLE32(ip+4, 0);
925         iend = ip+8;
926 
927         while (ip < iend) {
928             unsigned const nbBits = FUZ_rand(randState) % maxBits;
929             size_t iSize = RAND_BITS(nbBits) + 1;
930             size_t oSize = (size_t)(oend-op);
931             if (iSize > (size_t)(iend-ip)) iSize = (size_t)(iend-ip);
932             CHECK( LZ4F_decompress(dCtx, op, &oSize, ip, &iSize, NULL) );
933             op += oSize;
934             ip += iSize;
935         }
936         DISPLAYLEVEL(3, "Skipped %i bytes \n", (int)(ip - (BYTE*)compressedBuffer - 8));
937 
938         DISPLAYLEVEL(3, "Skippable frame header complete in first call \n");
939         ip = (BYTE*)compressedBuffer;
940         op = (BYTE*)decodedBuffer;
941         FUZ_writeLE32(ip, LZ4F_MAGIC_SKIPPABLE_START+2);
942         FUZ_writeLE32(ip+4, 10);
943         iend = ip+18;
944         while (ip < iend) {
945             size_t iSize = 10;
946             size_t oSize = 10;
947             if (iSize > (size_t)(iend-ip)) iSize = (size_t)(iend-ip);
948             CHECK( LZ4F_decompress(dCtx, op, &oSize, ip, &iSize, NULL) );
949             op += oSize;
950             ip += iSize;
951         }
952         DISPLAYLEVEL(3, "Skipped %i bytes \n", (int)(ip - (BYTE*)compressedBuffer - 8));
953     }
954 
955     DISPLAY("Basic tests completed \n");
956 _end:
957     free(CNBuffer);
958     free(compressedBuffer);
959     free(decodedBuffer);
960     LZ4F_freeDecompressionContext(dCtx); dCtx = NULL;
961     LZ4F_freeCompressionContext(cctx); cctx = NULL;
962     return basicTests_error;
963 
964 _output_error:
965     basicTests_error = 1;
966     DISPLAY("Error detected ! \n");
967     goto _end;
968 }
969 
970 
971 typedef enum { o_contiguous, o_noncontiguous, o_overwrite } o_scenario_e;
972 
locateBuffDiff(const void * buff1,const void * buff2,size_t size,o_scenario_e o_scenario)973 static void locateBuffDiff(const void* buff1, const void* buff2, size_t size, o_scenario_e o_scenario)
974 {
975     if (displayLevel >= 2) {
976         size_t p=0;
977         const BYTE* b1=(const BYTE*)buff1;
978         const BYTE* b2=(const BYTE*)buff2;
979         DISPLAY("locateBuffDiff: looking for error position \n");
980         if (o_scenario != o_contiguous) {
981             DISPLAY("mode %i: non-contiguous output (%u bytes), cannot search \n",
982                     (int)o_scenario, (unsigned)size);
983             return;
984         }
985         while (p < size && b1[p]==b2[p]) p++;
986         if (p != size) {
987             DISPLAY("Error at pos %i/%i : %02X != %02X \n", (int)p, (int)size, b1[p], b2[p]);
988         }
989     }
990 }
991 
992 #define EXIT_MSG(...) { DISPLAY("Error => "); DISPLAY(__VA_ARGS__); \
993                         DISPLAY(" (seed %u, test nb %u)  \n", seed, testNb); exit(1); }
994 #undef CHECK
995 #define CHECK(cond, ...) { if (cond) { EXIT_MSG(__VA_ARGS__); } }
996 
test_lz4f_decompression_wBuffers(const void * cSrc,size_t cSize,void * dst,size_t dstCapacity,o_scenario_e o_scenario,const void * srcRef,size_t decompressedSize,U64 crcOrig,U32 * const randState,LZ4F_dctx * const dCtx,U32 seed,U32 testNb,int findErrorPos)997 size_t test_lz4f_decompression_wBuffers(
998           const void* cSrc, size_t cSize,
999                 void* dst, size_t dstCapacity, o_scenario_e o_scenario,
1000           const void* srcRef, size_t decompressedSize,
1001                 U64 crcOrig,
1002                 U32* const randState,
1003                 LZ4F_dctx* const dCtx,
1004                 U32 seed, U32 testNb,
1005                 int findErrorPos)
1006 {
1007     const BYTE* ip = (const BYTE*)cSrc;
1008     const BYTE* const iend = ip + cSize;
1009 
1010     BYTE* op = (BYTE*)dst;
1011     BYTE* const oend = op + dstCapacity;
1012 
1013     unsigned const suggestedBits = FUZ_highbit((U32)cSize);
1014     unsigned const maxBits = MAX(3, suggestedBits);
1015     size_t totalOut = 0;
1016     size_t moreToFlush = 0;
1017     XXH64_state_t xxh64;
1018     XXH64_reset(&xxh64, 1);
1019     assert(ip < iend);
1020     while (ip < iend) {
1021         unsigned const nbBitsI = (FUZ_rand(randState) % (maxBits-1)) + 1;
1022         unsigned const nbBitsO = (FUZ_rand(randState) % (maxBits)) + 1;
1023         size_t const iSizeCand = RAND_BITS(nbBitsI) + 1;
1024         size_t const iSizeMax = MIN(iSizeCand, (size_t)(iend-ip));
1025         size_t iSize = iSizeMax;
1026         size_t const oSizeCand = RAND_BITS(nbBitsO) + 2;
1027         size_t const oSizeMax = MIN(oSizeCand, (size_t)(oend-op));
1028         int const sentinelTest = (op + oSizeMax < oend);
1029         size_t oSize = oSizeMax;
1030         BYTE const mark = (BYTE)(RAND_BITS(8));
1031         LZ4F_decompressOptions_t dOptions;
1032         memset(&dOptions, 0, sizeof(dOptions));
1033         dOptions.stableDst = RAND_BITS(1);
1034         if (o_scenario == o_overwrite) dOptions.stableDst = 0;  /* overwrite mode */
1035         dOptions.skipChecksums = RAND_BITS(1);
1036         if (sentinelTest) op[oSizeMax] = mark;
1037 
1038         DISPLAYLEVEL(7, "dstCapacity=%u,  presentedInput=%u \n", (unsigned)oSize, (unsigned)iSize);
1039 
1040         /* read data from byte-exact buffer to catch out-of-bound reads */
1041         {   void* const iBuffer = malloc(iSizeMax);
1042             /*test NULL supported if size==0 */
1043             void* const tmpop = RAND_BITS(oSize == 0) ? NULL : op;
1044             const void* const tmpip = RAND_BITS(iSize == 0) ? NULL : iBuffer;
1045             assert(iBuffer != NULL);
1046             memcpy(iBuffer, ip, iSizeMax);
1047             moreToFlush = LZ4F_decompress(dCtx, tmpop, &oSize, tmpip, &iSize, &dOptions);
1048             free(iBuffer);
1049         }
1050         DISPLAYLEVEL(7, "oSize=%u,  readSize=%u \n", (unsigned)oSize, (unsigned)iSize);
1051 
1052         if (sentinelTest) {
1053             CHECK(op[oSizeMax] != mark, "op[oSizeMax] = %02X != %02X : "
1054                     "Decompression overwrites beyond assigned dst size",
1055                     op[oSizeMax], mark);
1056         }
1057         if (LZ4F_getErrorCode(moreToFlush) == LZ4F_ERROR_contentChecksum_invalid) {
1058             if (findErrorPos) DISPLAYLEVEL(2, "checksum error detected \n");
1059             if (findErrorPos) locateBuffDiff(srcRef, dst, decompressedSize, o_scenario);
1060         }
1061         if (LZ4F_isError(moreToFlush)) return moreToFlush;
1062 
1063         XXH64_update(&xxh64, op, oSize);
1064         totalOut += oSize;
1065         op += oSize;
1066         ip += iSize;
1067         if (o_scenario == o_noncontiguous) {
1068             if (op == oend) return LZ4F_ERROR_GENERIC;  /* can theoretically happen with bogus data */
1069             op++; /* create a gap between consecutive output */
1070         }
1071         if (o_scenario==o_overwrite) op = (BYTE*)dst;   /* overwrite destination */
1072         if ( (op == oend) /* no more room for output; can happen with bogus input */
1073           && (iSize == 0)) /* no input consumed */
1074             break;
1075     }
1076     if (moreToFlush != 0) return LZ4F_ERROR_decompressionFailed;
1077     if (totalOut) {  /* otherwise, it's a skippable frame */
1078         U64 const crcDecoded = XXH64_digest(&xxh64);
1079         if (crcDecoded != crcOrig) {
1080             if (findErrorPos) locateBuffDiff(srcRef, dst, decompressedSize, o_scenario);
1081             return LZ4F_ERROR_contentChecksum_invalid;
1082     }   }
1083     return 0;
1084 }
1085 
1086 
test_lz4f_decompression(const void * cSrc,size_t cSize,const void * srcRef,size_t decompressedSize,U64 crcOrig,U32 * const randState,LZ4F_dctx * const dCtx,U32 seed,U32 testNb,int findErrorPos)1087 size_t test_lz4f_decompression(const void* cSrc, size_t cSize,
1088                                const void* srcRef, size_t decompressedSize,
1089                                U64 crcOrig,
1090                                U32* const randState,
1091                                LZ4F_dctx* const dCtx,
1092                                U32 seed, U32 testNb,
1093                                int findErrorPos)
1094 {
1095     o_scenario_e const o_scenario = (o_scenario_e)(FUZ_rand(randState) % 3);   /* 0 : contiguous; 1 : non-contiguous; 2 : dst overwritten */
1096     /* tighten dst buffer conditions */
1097     size_t const dstCapacity = (o_scenario == o_noncontiguous) ?
1098                                (decompressedSize * 2) + 128 :
1099                                decompressedSize;
1100     size_t result;
1101     void* const dstBuffer = malloc(dstCapacity);
1102     assert(dstBuffer != NULL);
1103 
1104     result = test_lz4f_decompression_wBuffers(cSrc, cSize,
1105                                      dstBuffer, dstCapacity, o_scenario,
1106                                      srcRef, decompressedSize,
1107                                      crcOrig,
1108                                      randState,
1109                                      dCtx,
1110                                      seed, testNb, findErrorPos);
1111 
1112     free(dstBuffer);
1113     return result;
1114 }
1115 
1116 
fuzzerTests(U32 seed,unsigned nbTests,unsigned startTest,double compressibility,U32 duration_s)1117 int fuzzerTests(U32 seed, unsigned nbTests, unsigned startTest, double compressibility, U32 duration_s)
1118 {
1119     unsigned testNb = 0;
1120     size_t const CNBufferLength = 9 MB;  /* needs to be > 2x4MB to test large blocks */
1121     void* CNBuffer = NULL;
1122     size_t const compressedBufferSize = LZ4F_compressFrameBound(CNBufferLength, NULL) + 4 MB;  /* needs some margin */
1123     void* compressedBuffer = NULL;
1124     void* decodedBuffer = NULL;
1125     U32 coreRand = seed;
1126     LZ4F_decompressionContext_t dCtx = NULL;
1127     LZ4F_compressionContext_t cCtx = NULL;
1128     clock_t const startClock = clock();
1129     clock_t const clockDuration = duration_s * CLOCKS_PER_SEC;
1130 
1131     /* Create states & buffers */
1132     {   size_t const creationStatus = LZ4F_createDecompressionContext(&dCtx, LZ4F_VERSION);
1133         CHECK(LZ4F_isError(creationStatus), "Allocation failed (error %i)", (int)creationStatus); }
1134     {   size_t const creationStatus = LZ4F_createCompressionContext(&cCtx, LZ4F_VERSION);
1135         CHECK(LZ4F_isError(creationStatus), "Allocation failed (error %i)", (int)creationStatus); }
1136     CNBuffer = malloc(CNBufferLength);
1137     CHECK(CNBuffer==NULL, "CNBuffer Allocation failed");
1138     compressedBuffer = malloc(compressedBufferSize);
1139     CHECK(compressedBuffer==NULL, "compressedBuffer Allocation failed");
1140     decodedBuffer = calloc(1, CNBufferLength);   /* calloc avoids decodedBuffer being considered "garbage" by scan-build */
1141     CHECK(decodedBuffer==NULL, "decodedBuffer Allocation failed");
1142     FUZ_fillCompressibleNoiseBuffer(CNBuffer, CNBufferLength, compressibility, &coreRand);
1143 
1144     /* jump to requested testNb */
1145     for (testNb =0; (testNb < startTest); testNb++) (void)FUZ_rand(&coreRand);   /* sync randomizer */
1146 
1147     /* main fuzzer test loop */
1148     for ( ; (testNb < nbTests) || (clockDuration > FUZ_GetClockSpan(startClock)) ; testNb++) {
1149         U32 randState = coreRand ^ prime1;
1150         unsigned const srcBits = (FUZ_rand(&randState) % (FUZ_highbit((U32)(CNBufferLength-1)) - 1)) + 1;
1151         size_t const srcSize = (FUZ_rand(&randState) & ((1<<srcBits)-1));
1152         size_t const srcStartId = FUZ_rand(&randState) % (CNBufferLength - srcSize);
1153         const BYTE* const srcStart = (const BYTE*)CNBuffer + srcStartId;
1154         unsigned const neverFlush = (FUZ_rand(&randState) & 15) == 1;
1155         U64 const crcOrig = XXH64(srcStart, srcSize, 1);
1156         LZ4F_preferences_t prefs;
1157         const LZ4F_preferences_t* prefsPtr = &prefs;
1158         size_t cSize;
1159 
1160         (void)FUZ_rand(&coreRand);   /* update seed */
1161         memset(&prefs, 0, sizeof(prefs));
1162         prefs.frameInfo.blockMode = (LZ4F_blockMode_t)(FUZ_rand(&randState) & 1);
1163         prefs.frameInfo.blockSizeID = (LZ4F_blockSizeID_t)(4 + (FUZ_rand(&randState) & 3));
1164         prefs.frameInfo.blockChecksumFlag = (LZ4F_blockChecksum_t)(FUZ_rand(&randState) & 1);
1165         prefs.frameInfo.contentChecksumFlag = (LZ4F_contentChecksum_t)(FUZ_rand(&randState) & 1);
1166         prefs.frameInfo.contentSize = ((FUZ_rand(&randState) & 0xF) == 1) ? srcSize : 0;
1167         prefs.autoFlush = neverFlush ? 0 : (FUZ_rand(&randState) & 7) == 2;
1168         prefs.compressionLevel = -5 + (int)(FUZ_rand(&randState) % 11);
1169         if ((FUZ_rand(&randState) & 0xF) == 1) prefsPtr = NULL;
1170 
1171         DISPLAYUPDATE(2, "\r%5u   ", testNb);
1172 
1173         if ((FUZ_rand(&randState) & 0xFFF) == 0) {
1174             /* create a skippable frame (rare case) */
1175             BYTE* op = (BYTE*)compressedBuffer;
1176             FUZ_writeLE32(op, LZ4F_MAGIC_SKIPPABLE_START + (FUZ_rand(&randState) & 15));
1177             FUZ_writeLE32(op+4, (U32)srcSize);
1178             cSize = srcSize+8;
1179 
1180         } else if ((FUZ_rand(&randState) & 0xF) == 2) {  /* single pass compression (simple) */
1181             cSize = LZ4F_compressFrame(compressedBuffer, LZ4F_compressFrameBound(srcSize, prefsPtr), srcStart, srcSize, prefsPtr);
1182             CHECK(LZ4F_isError(cSize), "LZ4F_compressFrame failed : error %i (%s)", (int)cSize, LZ4F_getErrorName(cSize));
1183 
1184         } else {   /* multi-segments compression */
1185             const BYTE* ip = srcStart;
1186             const BYTE* const iend = srcStart + srcSize;
1187             BYTE* op = (BYTE*)compressedBuffer;
1188             BYTE* const oend = op + (neverFlush ? LZ4F_compressFrameBound(srcSize, prefsPtr) : compressedBufferSize);  /* when flushes are possible, can't guarantee a max compressed size */
1189             unsigned const maxBits = FUZ_highbit((U32)srcSize);
1190             LZ4F_compressOptions_t cOptions;
1191             memset(&cOptions, 0, sizeof(cOptions));
1192             {   size_t const fhSize = LZ4F_compressBegin(cCtx, op, (size_t)(oend-op), prefsPtr);
1193                 CHECK(LZ4F_isError(fhSize), "Compression header failed (error %i)",
1194                                             (int)fhSize);
1195                 op += fhSize;
1196             }
1197             while (ip < iend) {
1198                 unsigned const nbBitsSeg = FUZ_rand(&randState) % maxBits;
1199                 size_t const sampleMax = (FUZ_rand(&randState) & ((1<<nbBitsSeg)-1)) + 1;
1200                 size_t iSize = MIN(sampleMax, (size_t)(iend-ip));
1201                 size_t const oSize = LZ4F_compressBound(iSize, prefsPtr);
1202                 cOptions.stableSrc = ((FUZ_rand(&randState) & 3) == 1);
1203                 DISPLAYLEVEL(6, "Sending %u bytes to compress (stableSrc:%u) \n",
1204                                 (unsigned)iSize, cOptions.stableSrc);
1205 
1206 #if 1
1207                 /* insert uncompressed segment */
1208                 if ( (iSize>0)
1209                   && !neverFlush   /* do not mess with compressBound when neverFlush is set */
1210                   && prefsPtr != NULL   /* prefs are set */
1211                   && prefs.frameInfo.blockMode == LZ4F_blockIndependent  /* uncompressedUpdate is only valid with blockMode==independent */
1212                   && (FUZ_rand(&randState) & 15) == 1 ) {
1213                     size_t const uSize = FUZ_rand(&randState) % iSize;
1214                     size_t const flushedSize = LZ4F_uncompressedUpdate(cCtx, op, (size_t)(oend-op), ip, uSize, &cOptions);
1215                     CHECK(LZ4F_isError(flushedSize), "Insert uncompressed data failed (error %i : %s)",
1216                             (int)flushedSize, LZ4F_getErrorName(flushedSize));
1217                     op += flushedSize;
1218                     ip += uSize;
1219                     iSize -= uSize;
1220                 }
1221 #endif
1222 
1223                 {   size_t const flushedSize = LZ4F_compressUpdate(cCtx, op, oSize, ip, iSize, &cOptions);
1224                     CHECK(LZ4F_isError(flushedSize), "Compression failed (error %i : %s)",
1225                             (int)flushedSize, LZ4F_getErrorName(flushedSize));
1226                     op += flushedSize;
1227                     ip += iSize;
1228                 }
1229 
1230                 {   unsigned const forceFlush = neverFlush ? 0 : ((FUZ_rand(&randState) & 3) == 1);
1231                     if (forceFlush) {
1232                         size_t const flushSize = LZ4F_flush(cCtx, op, (size_t)(oend-op), &cOptions);
1233                         DISPLAYLEVEL(6,"flushing %u bytes \n", (unsigned)flushSize);
1234                         CHECK(LZ4F_isError(flushSize), "Compression failed (error %i)", (int)flushSize);
1235                         op += flushSize;
1236                         if ((FUZ_rand(&randState) % 1024) == 3) {
1237                             /* add an empty block (requires uncompressed flag) */
1238                             op[0] = op[1] = op[2] = 0;
1239                             op[3] = 0x80; /* 0x80000000U in little-endian format */
1240                             op += 4;
1241                             if ((prefsPtr!= NULL) && prefsPtr->frameInfo.blockChecksumFlag) {
1242                                 /* add block checksum (even for empty blocks) */
1243                                 FUZ_writeLE32(op, XXH32(op, 0, 0));
1244                                 op += 4;
1245                 }   }   }   }
1246             }  /* while (ip<iend) */
1247             CHECK(op>=oend, "LZ4F_compressFrameBound overflow");
1248             {   size_t const dstEndSafeSize = LZ4F_compressBound(0, prefsPtr);
1249                 int const tooSmallDstEnd = ((FUZ_rand(&randState) & 31) == 3);
1250                 size_t const dstEndTooSmallSize = (FUZ_rand(&randState) % dstEndSafeSize) + 1;
1251                 size_t const dstEndSize = tooSmallDstEnd ? dstEndTooSmallSize : dstEndSafeSize;
1252                 BYTE const canaryByte = (BYTE)(FUZ_rand(&randState) & 255);
1253                 size_t flushedSize;
1254                 DISPLAYLEVEL(7,"canaryByte at pos %u / %u \n",
1255                             (unsigned)((size_t)(op - (BYTE*)compressedBuffer) + dstEndSize),
1256                             (unsigned)compressedBufferSize);
1257                 assert(op + dstEndSize < (BYTE*)compressedBuffer + compressedBufferSize);
1258                 op[dstEndSize] = canaryByte;
1259                 flushedSize = LZ4F_compressEnd(cCtx, op, dstEndSize, &cOptions);
1260                 CHECK(op[dstEndSize] != canaryByte, "LZ4F_compressEnd writes beyond dstCapacity !");
1261                 if (LZ4F_isError(flushedSize)) {
1262                     if (tooSmallDstEnd) /* failure is allowed */ continue;
1263                     CHECK(!tooSmallDstEnd, "Compression completion failed (error %i : %s)",
1264                             (int)flushedSize, LZ4F_getErrorName(flushedSize));
1265                 }
1266                 op += flushedSize;
1267             }
1268             cSize = (size_t)(op - (BYTE*)compressedBuffer);
1269             DISPLAYLEVEL(5, "\nCompressed %u bytes into %u \n", (U32)srcSize, (U32)cSize);
1270         }
1271 
1272 
1273         /* multi-segments decompression */
1274         DISPLAYLEVEL(6, "normal decompression \n");
1275         {   size_t result = test_lz4f_decompression(compressedBuffer, cSize, srcStart, srcSize, crcOrig, &randState, dCtx, seed, testNb, 1 /*findError*/ );
1276             CHECK (LZ4F_isError(result), "multi-segment decompression failed (error %i => %s)",
1277                                         (int)result, LZ4F_getErrorName(result));
1278         }
1279 
1280         /* insert noise into src - ensure decoder survives with no sanitizer error */
1281         {   U32 const maxNbBits = FUZ_highbit((U32)cSize);
1282             size_t pos = 0;
1283             for (;;) {
1284                 /* keep some original src */
1285                 {   U32 const nbBits = FUZ_rand(&randState) % maxNbBits;
1286                     size_t const mask = (1<<nbBits) - 1;
1287                     size_t const skipLength = FUZ_rand(&randState) & mask;
1288                     pos += skipLength;
1289                 }
1290                 if (pos >= cSize) break;
1291                 /* add noise */
1292                 {   U32 const nbBitsCodes = FUZ_rand(&randState) % maxNbBits;
1293                     U32 const nbBits = nbBitsCodes ? nbBitsCodes-1 : 0;
1294                     size_t const mask = (1<<nbBits) - 1;
1295                     size_t const rNoiseLength = (FUZ_rand(&randState) & mask) + 1;
1296                     size_t const noiseLength = MIN(rNoiseLength, cSize-pos);
1297                     size_t const noiseStart = FUZ_rand(&randState) % (CNBufferLength - noiseLength);
1298                     memcpy((BYTE*)compressedBuffer + pos, (const char*)CNBuffer + noiseStart, noiseLength);
1299                     pos += noiseLength;
1300         }   }   }
1301 
1302         /* test decompression on noisy src */
1303         DISPLAYLEVEL(6, "noisy decompression \n");
1304         test_lz4f_decompression(compressedBuffer, cSize, srcStart, srcSize, crcOrig, &randState, dCtx, seed, testNb, 0 /*don't search error Pos*/ );
1305         /* note : we don't analyze result here : it probably failed, which is expected.
1306          * The sole purpose is to catch potential out-of-bound reads and writes. */
1307         LZ4F_resetDecompressionContext(dCtx);  /* state must be reset to clean after an error */
1308 
1309     }   /* for ( ; (testNb < nbTests) ; ) */
1310 
1311     DISPLAYLEVEL(2, "\rAll tests completed   \n");
1312 
1313     LZ4F_freeDecompressionContext(dCtx);
1314     LZ4F_freeCompressionContext(cCtx);
1315     free(CNBuffer);
1316     free(compressedBuffer);
1317     free(decodedBuffer);
1318 
1319     if (use_pause) {
1320         DISPLAY("press enter to finish \n");
1321         (void)getchar();
1322     }
1323     return 0;
1324 }
1325 
1326 
FUZ_usage(const char * programName)1327 int FUZ_usage(const char* programName)
1328 {
1329     DISPLAY( "Usage :\n");
1330     DISPLAY( "      %s [args]\n", programName);
1331     DISPLAY( "\n");
1332     DISPLAY( "Arguments :\n");
1333     DISPLAY( " -i#    : Nb of tests (default:%u) \n", nbTestsDefault);
1334     DISPLAY( " -T#    : Duration of tests, in seconds (default: use Nb of tests) \n");
1335     DISPLAY( " -s#    : Select seed (default:prompt user)\n");
1336     DISPLAY( " -t#    : Select starting test number (default:0)\n");
1337     DISPLAY( " -P#    : Select compressibility in %% (default:%i%%)\n", FUZ_COMPRESSIBILITY_DEFAULT);
1338     DISPLAY( " -v     : verbose\n");
1339     DISPLAY( " -h     : display help and exit\n");
1340     return 0;
1341 }
1342 
1343 
main(int argc,const char ** argv)1344 int main(int argc, const char** argv)
1345 {
1346     U32 seed=0;
1347     int seedset=0;
1348     int argNb;
1349     unsigned nbTests = nbTestsDefault;
1350     unsigned testNb = 0;
1351     int proba = FUZ_COMPRESSIBILITY_DEFAULT;
1352     U32 duration=0;
1353     const char* const programName = argv[0];
1354 
1355     /* Check command line */
1356     for (argNb=1; argNb<argc; argNb++) {
1357         const char* argument = argv[argNb];
1358 
1359         if(!argument) continue;   /* Protection if argument empty */
1360 
1361         /* Decode command (note : aggregated short commands are allowed) */
1362         if (argument[0]=='-') {
1363             if (!strcmp(argument, "--no-prompt")) {
1364                 no_prompt=1;
1365                 seedset=1;
1366                 displayLevel=1;
1367                 continue;
1368             }
1369             argument++;
1370 
1371             while (*argument!=0) {
1372                 switch(*argument)
1373                 {
1374                 case 'h':
1375                     return FUZ_usage(programName);
1376                 case 'v':
1377                     argument++;
1378                     displayLevel++;
1379                     break;
1380                 case 'q':
1381                     argument++;
1382                     displayLevel--;
1383                     break;
1384                 case 'p': /* pause at the end */
1385                     argument++;
1386                     use_pause = 1;
1387                     break;
1388 
1389                 case 'i':
1390                     argument++;
1391                     nbTests=0; duration=0;
1392                     while ((*argument>='0') && (*argument<='9')) {
1393                         nbTests *= 10;
1394                         nbTests += (unsigned)(*argument - '0');
1395                         argument++;
1396                     }
1397                     break;
1398 
1399                 case 'T':
1400                     argument++;
1401                     nbTests = 0; duration = 0;
1402                     for (;;) {
1403                         switch(*argument)
1404                         {
1405                             case 'm': duration *= 60; argument++; continue;
1406                             case 's':
1407                             case 'n': argument++; continue;
1408                             case '0':
1409                             case '1':
1410                             case '2':
1411                             case '3':
1412                             case '4':
1413                             case '5':
1414                             case '6':
1415                             case '7':
1416                             case '8':
1417                             case '9': duration *= 10; duration += (U32)(*argument++ - '0'); continue;
1418                         }
1419                         break;
1420                     }
1421                     break;
1422 
1423                 case 's':
1424                     argument++;
1425                     seed=0;
1426                     seedset=1;
1427                     while ((*argument>='0') && (*argument<='9')) {
1428                         seed *= 10;
1429                         seed += (U32)(*argument - '0');
1430                         argument++;
1431                     }
1432                     break;
1433                 case 't':
1434                     argument++;
1435                     testNb=0;
1436                     while ((*argument>='0') && (*argument<='9')) {
1437                         testNb *= 10;
1438                         testNb += (unsigned)(*argument - '0');
1439                         argument++;
1440                     }
1441                     break;
1442                 case 'P':   /* compressibility % */
1443                     argument++;
1444                     proba=0;
1445                     while ((*argument>='0') && (*argument<='9')) {
1446                         proba *= 10;
1447                         proba += *argument - '0';
1448                         argument++;
1449                     }
1450                     if (proba<0) proba=0;
1451                     if (proba>100) proba=100;
1452                     break;
1453                 default:
1454                     ;
1455                     return FUZ_usage(programName);
1456                 }
1457             }
1458         } /* if (argument[0]=='-') */
1459     } /* for (argNb=1; argNb<argc; argNb++) */
1460 
1461     DISPLAY("Starting lz4frame tester (%i-bits, %s) \n", (int)(sizeof(size_t)*8), LZ4_VERSION_STRING);
1462 
1463     /* Select a random seed if none given */
1464     if (!seedset) {
1465         time_t const t = time(NULL);
1466         U32 const h = XXH32(&t, sizeof(t), 1);
1467         seed = h % 10000;
1468     }
1469     DISPLAY("Seed = %u \n", seed);
1470     if (proba != FUZ_COMPRESSIBILITY_DEFAULT)
1471         DISPLAY("Compressibility : %i%% \n", proba);
1472 
1473     {   double const compressibility = (double)proba / 100;
1474         /* start by unit tests if not requesting a specific run nb */
1475         if (testNb==0) {
1476             if (unitTests(seed, compressibility))
1477                 return 1;
1478         }
1479 
1480         nbTests += (nbTests==0);  /* avoid zero */
1481         return fuzzerTests(seed, nbTests, testNb, compressibility, duration);
1482     }
1483 }
1484