]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/contrib/zstd/tests/zstreamtest.c
Import OpenCSD -- an ARM CoreSight(tm) Trace Decode Library.
[FreeBSD/FreeBSD.git] / sys / contrib / zstd / tests / zstreamtest.c
1 /*
2  * Copyright (c) 2016-present, Yann Collet, Facebook, Inc.
3  * All rights reserved.
4  *
5  * This source code is licensed under both the BSD-style license (found in the
6  * LICENSE file in the root directory of this source tree) and the GPLv2 (found
7  * in the COPYING file in the root directory of this source tree).
8  * You may select, at your option, one of the above-listed licenses.
9  */
10
11
12 /*-************************************
13 *  Compiler specific
14 **************************************/
15 #ifdef _MSC_VER    /* Visual Studio */
16 #  define _CRT_SECURE_NO_WARNINGS   /* fgets */
17 #  pragma warning(disable : 4127)   /* disable: C4127: conditional expression is constant */
18 #  pragma warning(disable : 4146)   /* disable: C4146: minus unsigned expression */
19 #endif
20
21
22 /*-************************************
23 *  Includes
24 **************************************/
25 #include <stdlib.h>       /* free */
26 #include <stdio.h>        /* fgets, sscanf */
27 #include <string.h>       /* strcmp */
28 #include <assert.h>       /* assert */
29 #include "mem.h"
30 #define ZSTD_STATIC_LINKING_ONLY  /* ZSTD_maxCLevel, ZSTD_customMem, ZSTD_getDictID_fromFrame */
31 #include "zstd.h"         /* ZSTD_compressBound */
32 #include "zstd_errors.h"  /* ZSTD_error_srcSize_wrong */
33 #include "zstdmt_compress.h"
34 #include "zdict.h"        /* ZDICT_trainFromBuffer */
35 #include "datagen.h"      /* RDG_genBuffer */
36 #define XXH_STATIC_LINKING_ONLY   /* XXH64_state_t */
37 #include "xxhash.h"       /* XXH64_* */
38 #include "seqgen.h"
39 #include "util.h"
40
41
42 /*-************************************
43 *  Constants
44 **************************************/
45 #define KB *(1U<<10)
46 #define MB *(1U<<20)
47 #define GB *(1U<<30)
48
49 static const U32 nbTestsDefault = 10000;
50 static const U32 g_cLevelMax_smallTests = 10;
51 #define COMPRESSIBLE_NOISE_LENGTH (10 MB)
52 #define FUZ_COMPRESSIBILITY_DEFAULT 50
53 static const U32 prime32 = 2654435761U;
54
55
56 /*-************************************
57 *  Display Macros
58 **************************************/
59 #define DISPLAY(...)          fprintf(stderr, __VA_ARGS__)
60 #define DISPLAYLEVEL(l, ...)  if (g_displayLevel>=l) {                     \
61                                   DISPLAY(__VA_ARGS__);                    \
62                                   if (g_displayLevel>=4) fflush(stderr); }
63 static U32 g_displayLevel = 2;
64
65 static const U64 g_refreshRate = SEC_TO_MICRO / 6;
66 static UTIL_time_t g_displayClock = UTIL_TIME_INITIALIZER;
67
68 #define DISPLAYUPDATE(l, ...) if (g_displayLevel>=l) { \
69             if ((UTIL_clockSpanMicro(g_displayClock) > g_refreshRate) || (g_displayLevel>=4)) \
70             { g_displayClock = UTIL_getTime(); DISPLAY(__VA_ARGS__); \
71             if (g_displayLevel>=4) fflush(stderr); } }
72
73 static U64 g_clockTime = 0;
74
75
76 /*-*******************************************************
77 *  Fuzzer functions
78 *********************************************************/
79 #undef MIN
80 #undef MAX
81 #define MIN(a,b) ((a)<(b)?(a):(b))
82 #define MAX(a,b) ((a)>(b)?(a):(b))
83 /*! FUZ_rand() :
84     @return : a 27 bits random value, from a 32-bits `seed`.
85     `seed` is also modified */
86 #define FUZ_rotl32(x,r) ((x << r) | (x >> (32 - r)))
87 unsigned int FUZ_rand(unsigned int* seedPtr)
88 {
89     static const U32 prime2 = 2246822519U;
90     U32 rand32 = *seedPtr;
91     rand32 *= prime32;
92     rand32 += prime2;
93     rand32  = FUZ_rotl32(rand32, 13);
94     *seedPtr = rand32;
95     return rand32 >> 5;
96 }
97
98 #define CHECK(cond, ...) {                                   \
99     if (cond) {                                              \
100         DISPLAY("Error => ");                                \
101         DISPLAY(__VA_ARGS__);                                \
102         DISPLAY(" (seed %u, test nb %u, line %u) \n",        \
103                 seed, testNb, __LINE__);                     \
104         goto _output_error;                                  \
105 }   }
106
107 #define CHECK_Z(f) {                                         \
108     size_t const err = f;                                    \
109     CHECK(ZSTD_isError(err), "%s : %s ",                     \
110           #f, ZSTD_getErrorName(err));                       \
111 }
112
113
114 /*======================================================
115 *   Basic Unit tests
116 ======================================================*/
117
118 typedef struct {
119     void* start;
120     size_t size;
121     size_t filled;
122 } buffer_t;
123
124 static const buffer_t g_nullBuffer = { NULL, 0 , 0 };
125
126 static buffer_t FUZ_createDictionary(const void* src, size_t srcSize, size_t blockSize, size_t requestedDictSize)
127 {
128     buffer_t dict = { NULL, 0, 0 };
129     size_t const nbBlocks = (srcSize + (blockSize-1)) / blockSize;
130     size_t* const blockSizes = (size_t*) malloc(nbBlocks * sizeof(size_t));
131     if (!blockSizes) return dict;
132     dict.start = malloc(requestedDictSize);
133     if (!dict.start) { free(blockSizes); return dict; }
134     {   size_t nb;
135         for (nb=0; nb<nbBlocks-1; nb++) blockSizes[nb] = blockSize;
136         blockSizes[nbBlocks-1] = srcSize - (blockSize * (nbBlocks-1));
137     }
138     {   size_t const dictSize = ZDICT_trainFromBuffer(dict.start, requestedDictSize, src, blockSizes, (unsigned)nbBlocks);
139         free(blockSizes);
140         if (ZDICT_isError(dictSize)) { free(dict.start); return g_nullBuffer; }
141         dict.size = requestedDictSize;
142         dict.filled = dictSize;
143         return dict;   /* how to return dictSize ? */
144     }
145 }
146
147 static void FUZ_freeDictionary(buffer_t dict)
148 {
149     free(dict.start);
150 }
151
152 /* Round trips data and updates xxh with the decompressed data produced */
153 static size_t SEQ_roundTrip(ZSTD_CCtx* cctx, ZSTD_DCtx* dctx,
154                             XXH64_state_t* xxh, void* data, size_t size,
155                             ZSTD_EndDirective endOp)
156 {
157     static BYTE compressed[1024];
158     static BYTE uncompressed[1024];
159
160     ZSTD_inBuffer cin = {data, size, 0};
161     size_t cret;
162
163     do {
164         ZSTD_outBuffer cout = {compressed, sizeof(compressed), 0};
165         ZSTD_inBuffer din = {compressed, 0, 0};
166         ZSTD_outBuffer dout = {uncompressed, 0, 0};
167
168         cret = ZSTD_compress_generic(cctx, &cout, &cin, endOp);
169         if (ZSTD_isError(cret))
170             return cret;
171
172         din.size = cout.pos;
173         while (din.pos < din.size || (endOp == ZSTD_e_end && cret == 0)) {
174             size_t dret;
175
176             dout.pos = 0;
177             dout.size = sizeof(uncompressed);
178             dret = ZSTD_decompressStream(dctx, &dout, &din);
179             if (ZSTD_isError(dret))
180                 return dret;
181             XXH64_update(xxh, dout.dst, dout.pos);
182             if (dret == 0)
183                 break;
184         }
185     } while (cin.pos < cin.size || (endOp != ZSTD_e_continue && cret != 0));
186     return 0;
187 }
188
189 /* Generates some data and round trips it */
190 static size_t SEQ_generateRoundTrip(ZSTD_CCtx* cctx, ZSTD_DCtx* dctx,
191                                     XXH64_state_t* xxh, SEQ_stream* seq,
192                                     SEQ_gen_type type, unsigned value)
193 {
194     static BYTE data[1024];
195     size_t gen;
196
197     do {
198         SEQ_outBuffer sout = {data, sizeof(data), 0};
199         size_t ret;
200         gen = SEQ_gen(seq, type, value, &sout);
201
202         ret = SEQ_roundTrip(cctx, dctx, xxh, sout.dst, sout.pos, ZSTD_e_continue);
203         if (ZSTD_isError(ret))
204             return ret;
205     } while (gen != 0);
206
207     return 0;
208 }
209
210 static int basicUnitTests(U32 seed, double compressibility)
211 {
212     size_t const CNBufferSize = COMPRESSIBLE_NOISE_LENGTH;
213     void* CNBuffer = malloc(CNBufferSize);
214     size_t const skippableFrameSize = 200 KB;
215     size_t const compressedBufferSize = (8 + skippableFrameSize) + ZSTD_compressBound(COMPRESSIBLE_NOISE_LENGTH);
216     void* compressedBuffer = malloc(compressedBufferSize);
217     size_t const decodedBufferSize = CNBufferSize;
218     void* decodedBuffer = malloc(decodedBufferSize);
219     size_t cSize;
220     int testResult = 0;
221     U32 testNb = 1;
222     U32 coreSeed = 0;  /* this name to conform with CHECK_Z macro display */
223     ZSTD_CStream* zc = ZSTD_createCStream();
224     ZSTD_DStream* zd = ZSTD_createDStream();
225     ZSTDMT_CCtx* mtctx = ZSTDMT_createCCtx(2);
226
227     ZSTD_inBuffer  inBuff, inBuff2;
228     ZSTD_outBuffer outBuff;
229     buffer_t dictionary = g_nullBuffer;
230     size_t const dictSize = 128 KB;
231     unsigned dictID = 0;
232
233     /* Create compressible test buffer */
234     if (!CNBuffer || !compressedBuffer || !decodedBuffer || !zc || !zd) {
235         DISPLAY("Not enough memory, aborting \n");
236         goto _output_error;
237     }
238     RDG_genBuffer(CNBuffer, CNBufferSize, compressibility, 0., seed);
239
240     /* Create dictionary */
241     DISPLAYLEVEL(3, "creating dictionary for unit tests \n");
242     dictionary = FUZ_createDictionary(CNBuffer, CNBufferSize / 3, 16 KB, 48 KB);
243     if (!dictionary.start) {
244         DISPLAY("Error creating dictionary, aborting \n");
245         goto _output_error;
246     }
247     dictID = ZDICT_getDictID(dictionary.start, dictionary.filled);
248
249     /* Basic compression test */
250     DISPLAYLEVEL(3, "test%3i : compress %u bytes : ", testNb++, COMPRESSIBLE_NOISE_LENGTH);
251     CHECK_Z( ZSTD_initCStream(zc, 1 /* cLevel */) );
252     outBuff.dst = (char*)(compressedBuffer);
253     outBuff.size = compressedBufferSize;
254     outBuff.pos = 0;
255     inBuff.src = CNBuffer;
256     inBuff.size = CNBufferSize;
257     inBuff.pos = 0;
258     CHECK_Z( ZSTD_compressStream(zc, &outBuff, &inBuff) );
259     if (inBuff.pos != inBuff.size) goto _output_error;   /* entire input should be consumed */
260     { size_t const r = ZSTD_endStream(zc, &outBuff);
261       if (r != 0) goto _output_error; }  /* error, or some data not flushed */
262     DISPLAYLEVEL(3, "OK (%u bytes)\n", (U32)outBuff.pos);
263
264     /* generate skippable frame */
265     MEM_writeLE32(compressedBuffer, ZSTD_MAGIC_SKIPPABLE_START);
266     MEM_writeLE32(((char*)compressedBuffer)+4, (U32)skippableFrameSize);
267     cSize = skippableFrameSize + 8;
268
269     /* Basic compression test using dict */
270     DISPLAYLEVEL(3, "test%3i : skipframe + compress %u bytes : ", testNb++, COMPRESSIBLE_NOISE_LENGTH);
271     CHECK_Z( ZSTD_initCStream_usingDict(zc, CNBuffer, dictSize, 1 /* cLevel */) );
272     outBuff.dst = (char*)(compressedBuffer)+cSize;
273     assert(compressedBufferSize > cSize);
274     outBuff.size = compressedBufferSize - cSize;
275     outBuff.pos = 0;
276     inBuff.src = CNBuffer;
277     inBuff.size = CNBufferSize;
278     inBuff.pos = 0;
279     CHECK_Z( ZSTD_compressStream(zc, &outBuff, &inBuff) );
280     if (inBuff.pos != inBuff.size) goto _output_error;   /* entire input should be consumed */
281     { size_t const r = ZSTD_endStream(zc, &outBuff);
282       if (r != 0) goto _output_error; }  /* error, or some data not flushed */
283     cSize += outBuff.pos;
284     DISPLAYLEVEL(3, "OK (%u bytes : %.2f%%)\n", (U32)cSize, (double)cSize/COMPRESSIBLE_NOISE_LENGTH*100);
285
286     /* context size functions */
287     DISPLAYLEVEL(3, "test%3i : estimate CStream size : ", testNb++);
288     {   ZSTD_compressionParameters const cParams = ZSTD_getCParams(1, CNBufferSize, dictSize);
289         size_t const cstreamSize = ZSTD_estimateCStreamSize_usingCParams(cParams);
290         size_t const cdictSize = ZSTD_estimateCDictSize_advanced(dictSize, cParams, ZSTD_dlm_byCopy); /* uses ZSTD_initCStream_usingDict() */
291         if (ZSTD_isError(cstreamSize)) goto _output_error;
292         if (ZSTD_isError(cdictSize)) goto _output_error;
293         DISPLAYLEVEL(3, "OK (%u bytes) \n", (U32)(cstreamSize + cdictSize));
294     }
295
296     DISPLAYLEVEL(3, "test%3i : check actual CStream size : ", testNb++);
297     {   size_t const s = ZSTD_sizeof_CStream(zc);
298         if (ZSTD_isError(s)) goto _output_error;
299         DISPLAYLEVEL(3, "OK (%u bytes) \n", (U32)s);
300     }
301
302     /* Attempt bad compression parameters */
303     DISPLAYLEVEL(3, "test%3i : use bad compression parameters : ", testNb++);
304     {   size_t r;
305         ZSTD_parameters params = ZSTD_getParams(1, 0, 0);
306         params.cParams.searchLength = 2;
307         r = ZSTD_initCStream_advanced(zc, NULL, 0, params, 0);
308         if (!ZSTD_isError(r)) goto _output_error;
309         DISPLAYLEVEL(3, "init error : %s \n", ZSTD_getErrorName(r));
310     }
311
312     /* skippable frame test */
313     DISPLAYLEVEL(3, "test%3i : decompress skippable frame : ", testNb++);
314     CHECK_Z( ZSTD_initDStream_usingDict(zd, CNBuffer, dictSize) );
315     inBuff.src = compressedBuffer;
316     inBuff.size = cSize;
317     inBuff.pos = 0;
318     outBuff.dst = decodedBuffer;
319     outBuff.size = CNBufferSize;
320     outBuff.pos = 0;
321     {   size_t const r = ZSTD_decompressStream(zd, &outBuff, &inBuff);
322         DISPLAYLEVEL(5, " ( ZSTD_decompressStream => %u ) ", (U32)r);
323         if (r != 0) goto _output_error;
324     }
325     if (outBuff.pos != 0) goto _output_error;   /* skippable frame output len is 0 */
326     DISPLAYLEVEL(3, "OK \n");
327
328     /* Basic decompression test */
329     inBuff2 = inBuff;
330     DISPLAYLEVEL(3, "test%3i : decompress %u bytes : ", testNb++, COMPRESSIBLE_NOISE_LENGTH);
331     ZSTD_initDStream_usingDict(zd, CNBuffer, dictSize);
332     CHECK_Z( ZSTD_setDStreamParameter(zd, DStream_p_maxWindowSize, 1000000000) );  /* large limit */
333     { size_t const remaining = ZSTD_decompressStream(zd, &outBuff, &inBuff);
334       if (remaining != 0) goto _output_error; }  /* should reach end of frame == 0; otherwise, some data left, or an error */
335     if (outBuff.pos != CNBufferSize) goto _output_error;   /* should regenerate the same amount */
336     if (inBuff.pos != inBuff.size) goto _output_error;   /* should have read the entire frame */
337     DISPLAYLEVEL(3, "OK \n");
338
339     /* Re-use without init */
340     DISPLAYLEVEL(3, "test%3i : decompress again without init (re-use previous settings): ", testNb++);
341     outBuff.pos = 0;
342     { size_t const remaining = ZSTD_decompressStream(zd, &outBuff, &inBuff2);
343       if (remaining != 0) goto _output_error; }  /* should reach end of frame == 0; otherwise, some data left, or an error */
344     if (outBuff.pos != CNBufferSize) goto _output_error;   /* should regenerate the same amount */
345     if (inBuff.pos != inBuff.size) goto _output_error;   /* should have read the entire frame */
346     DISPLAYLEVEL(3, "OK \n");
347
348     /* check regenerated data is byte exact */
349     DISPLAYLEVEL(3, "test%3i : check decompressed result : ", testNb++);
350     {   size_t i;
351         for (i=0; i<CNBufferSize; i++) {
352             if (((BYTE*)decodedBuffer)[i] != ((BYTE*)CNBuffer)[i]) goto _output_error;
353     }   }
354     DISPLAYLEVEL(3, "OK \n");
355
356     /* context size functions */
357     DISPLAYLEVEL(3, "test%3i : estimate DStream size : ", testNb++);
358     {   ZSTD_frameHeader fhi;
359         const void* cStart = (char*)compressedBuffer + (skippableFrameSize + 8);
360         size_t const gfhError = ZSTD_getFrameHeader(&fhi, cStart, cSize);
361         if (gfhError!=0) goto _output_error;
362         DISPLAYLEVEL(5, " (windowSize : %u) ", (U32)fhi.windowSize);
363         {   size_t const s = ZSTD_estimateDStreamSize(fhi.windowSize)
364                             /* uses ZSTD_initDStream_usingDict() */
365                            + ZSTD_estimateDDictSize(dictSize, ZSTD_dlm_byCopy);
366             if (ZSTD_isError(s)) goto _output_error;
367             DISPLAYLEVEL(3, "OK (%u bytes) \n", (U32)s);
368     }   }
369
370     DISPLAYLEVEL(3, "test%3i : check actual DStream size : ", testNb++);
371     { size_t const s = ZSTD_sizeof_DStream(zd);
372       if (ZSTD_isError(s)) goto _output_error;
373       DISPLAYLEVEL(3, "OK (%u bytes) \n", (U32)s);
374     }
375
376     /* Decompression by small increment */
377     DISPLAYLEVEL(3, "test%3i : decompress byte-by-byte : ", testNb++);
378     {   /* skippable frame */
379         size_t r = 1;
380         ZSTD_initDStream_usingDict(zd, CNBuffer, dictSize);
381         inBuff.src = compressedBuffer;
382         outBuff.dst = decodedBuffer;
383         inBuff.pos = 0;
384         outBuff.pos = 0;
385         while (r) {   /* skippable frame */
386             size_t const inSize = FUZ_rand(&coreSeed) & 15;
387             size_t const outSize = FUZ_rand(&coreSeed) & 15;
388             inBuff.size = inBuff.pos + inSize;
389             outBuff.size = outBuff.pos + outSize;
390             r = ZSTD_decompressStream(zd, &outBuff, &inBuff);
391             if (ZSTD_isError(r)) goto _output_error;
392         }
393         /* normal frame */
394         ZSTD_initDStream_usingDict(zd, CNBuffer, dictSize);
395         r=1;
396         while (r) {
397             size_t const inSize = FUZ_rand(&coreSeed) & 15;
398             size_t const outSize = FUZ_rand(&coreSeed) & 15;
399             inBuff.size = inBuff.pos + inSize;
400             outBuff.size = outBuff.pos + outSize;
401             r = ZSTD_decompressStream(zd, &outBuff, &inBuff);
402             if (ZSTD_isError(r)) goto _output_error;
403         }
404     }
405     if (outBuff.pos != CNBufferSize) goto _output_error;   /* should regenerate the same amount */
406     if (inBuff.pos != cSize) goto _output_error;   /* should have read the entire frame */
407     DISPLAYLEVEL(3, "OK \n");
408
409     /* check regenerated data is byte exact */
410     DISPLAYLEVEL(3, "test%3i : check decompressed result : ", testNb++);
411     {   size_t i;
412         for (i=0; i<CNBufferSize; i++) {
413             if (((BYTE*)decodedBuffer)[i] != ((BYTE*)CNBuffer)[i]) goto _output_error;;
414     }   }
415     DISPLAYLEVEL(3, "OK \n");
416
417     /* _srcSize compression test */
418     DISPLAYLEVEL(3, "test%3i : compress_srcSize %u bytes : ", testNb++, COMPRESSIBLE_NOISE_LENGTH);
419     ZSTD_initCStream_srcSize(zc, 1, CNBufferSize);
420     outBuff.dst = (char*)(compressedBuffer);
421     outBuff.size = compressedBufferSize;
422     outBuff.pos = 0;
423     inBuff.src = CNBuffer;
424     inBuff.size = CNBufferSize;
425     inBuff.pos = 0;
426     CHECK_Z( ZSTD_compressStream(zc, &outBuff, &inBuff) );
427     if (inBuff.pos != inBuff.size) goto _output_error;   /* entire input should be consumed */
428     { size_t const r = ZSTD_endStream(zc, &outBuff);
429       if (r != 0) goto _output_error; }  /* error, or some data not flushed */
430     { unsigned long long origSize = ZSTD_findDecompressedSize(outBuff.dst, outBuff.pos);
431       if ((size_t)origSize != CNBufferSize) goto _output_error; }  /* exact original size must be present */
432     DISPLAYLEVEL(3, "OK (%u bytes : %.2f%%)\n", (U32)cSize, (double)cSize/COMPRESSIBLE_NOISE_LENGTH*100);
433
434     /* wrong _srcSize compression test */
435     DISPLAYLEVEL(3, "test%3i : too large srcSize : %u bytes : ", testNb++, COMPRESSIBLE_NOISE_LENGTH-1);
436     ZSTD_initCStream_srcSize(zc, 1, CNBufferSize+1);
437     outBuff.dst = (char*)(compressedBuffer);
438     outBuff.size = compressedBufferSize;
439     outBuff.pos = 0;
440     inBuff.src = CNBuffer;
441     inBuff.size = CNBufferSize;
442     inBuff.pos = 0;
443     CHECK_Z( ZSTD_compressStream(zc, &outBuff, &inBuff) );
444     if (inBuff.pos != inBuff.size) goto _output_error;   /* entire input should be consumed */
445     { size_t const r = ZSTD_endStream(zc, &outBuff);
446       if (ZSTD_getErrorCode(r) != ZSTD_error_srcSize_wrong) goto _output_error;    /* must fail : wrong srcSize */
447       DISPLAYLEVEL(3, "OK (error detected : %s) \n", ZSTD_getErrorName(r)); }
448
449     /* wrong _srcSize compression test */
450     DISPLAYLEVEL(3, "test%3i : too small srcSize : %u bytes : ", testNb++, COMPRESSIBLE_NOISE_LENGTH-1);
451     ZSTD_initCStream_srcSize(zc, 1, CNBufferSize-1);
452     outBuff.dst = (char*)(compressedBuffer);
453     outBuff.size = compressedBufferSize;
454     outBuff.pos = 0;
455     inBuff.src = CNBuffer;
456     inBuff.size = CNBufferSize;
457     inBuff.pos = 0;
458     {   size_t const r = ZSTD_compressStream(zc, &outBuff, &inBuff);
459         if (ZSTD_getErrorCode(r) != ZSTD_error_srcSize_wrong) goto _output_error;    /* must fail : wrong srcSize */
460         DISPLAYLEVEL(3, "OK (error detected : %s) \n", ZSTD_getErrorName(r));
461     }
462
463     /* Complex context re-use scenario */
464     DISPLAYLEVEL(3, "test%3i : context re-use : ", testNb++);
465     ZSTD_freeCStream(zc);
466     zc = ZSTD_createCStream();
467     if (zc==NULL) goto _output_error;   /* memory allocation issue */
468     /* use 1 */
469     {   size_t const inSize = 513;
470         DISPLAYLEVEL(5, "use1 ");
471         ZSTD_initCStream_advanced(zc, NULL, 0, ZSTD_getParams(19, inSize, 0), inSize);   /* needs btopt + search3 to trigger hashLog3 */
472         inBuff.src = CNBuffer;
473         inBuff.size = inSize;
474         inBuff.pos = 0;
475         outBuff.dst = (char*)(compressedBuffer)+cSize;
476         outBuff.size = ZSTD_compressBound(inSize);
477         outBuff.pos = 0;
478         DISPLAYLEVEL(5, "compress1 ");
479         CHECK_Z( ZSTD_compressStream(zc, &outBuff, &inBuff) );
480         if (inBuff.pos != inBuff.size) goto _output_error;   /* entire input should be consumed */
481         DISPLAYLEVEL(5, "end1 ");
482         { size_t const r = ZSTD_endStream(zc, &outBuff);
483             if (r != 0) goto _output_error; }  /* error, or some data not flushed */
484     }
485     /* use 2 */
486     {   size_t const inSize = 1025;   /* will not continue, because tables auto-adjust and are therefore different size */
487         DISPLAYLEVEL(5, "use2 ");
488         ZSTD_initCStream_advanced(zc, NULL, 0, ZSTD_getParams(19, inSize, 0), inSize);   /* needs btopt + search3 to trigger hashLog3 */
489         inBuff.src = CNBuffer;
490         inBuff.size = inSize;
491         inBuff.pos = 0;
492         outBuff.dst = (char*)(compressedBuffer)+cSize;
493         outBuff.size = ZSTD_compressBound(inSize);
494         outBuff.pos = 0;
495         DISPLAYLEVEL(5, "compress2 ");
496         CHECK_Z( ZSTD_compressStream(zc, &outBuff, &inBuff) );
497         if (inBuff.pos != inBuff.size) goto _output_error;   /* entire input should be consumed */
498         DISPLAYLEVEL(5, "end2 ");
499         { size_t const r = ZSTD_endStream(zc, &outBuff);
500             if (r != 0) goto _output_error; }  /* error, or some data not flushed */
501     }
502     DISPLAYLEVEL(3, "OK \n");
503
504     /* CDict scenario */
505     DISPLAYLEVEL(3, "test%3i : digested dictionary : ", testNb++);
506     {   ZSTD_CDict* const cdict = ZSTD_createCDict(dictionary.start, dictionary.filled, 1 /*byRef*/ );
507         size_t const initError = ZSTD_initCStream_usingCDict(zc, cdict);
508         DISPLAYLEVEL(5, "ZSTD_initCStream_usingCDict result : %u ", (U32)initError);
509         if (ZSTD_isError(initError)) goto _output_error;
510         cSize = 0;
511         outBuff.dst = compressedBuffer;
512         outBuff.size = compressedBufferSize;
513         outBuff.pos = 0;
514         inBuff.src = CNBuffer;
515         inBuff.size = CNBufferSize;
516         inBuff.pos = 0;
517         DISPLAYLEVEL(5, "- starting ZSTD_compressStream ");
518         CHECK_Z( ZSTD_compressStream(zc, &outBuff, &inBuff) );
519         if (inBuff.pos != inBuff.size) goto _output_error;   /* entire input should be consumed */
520         {   size_t const r = ZSTD_endStream(zc, &outBuff);
521             DISPLAYLEVEL(5, "- ZSTD_endStream result : %u ", (U32)r);
522             if (r != 0) goto _output_error;  /* error, or some data not flushed */
523         }
524         cSize = outBuff.pos;
525         ZSTD_freeCDict(cdict);
526         DISPLAYLEVEL(3, "OK (%u bytes : %.2f%%)\n", (U32)cSize, (double)cSize/CNBufferSize*100);
527     }
528
529     DISPLAYLEVEL(3, "test%3i : check CStream size : ", testNb++);
530     { size_t const s = ZSTD_sizeof_CStream(zc);
531       if (ZSTD_isError(s)) goto _output_error;
532       DISPLAYLEVEL(3, "OK (%u bytes) \n", (U32)s);
533     }
534
535     DISPLAYLEVEL(4, "test%3i : check Dictionary ID : ", testNb++);
536     { unsigned const dID = ZSTD_getDictID_fromFrame(compressedBuffer, cSize);
537       if (dID != dictID) goto _output_error;
538       DISPLAYLEVEL(4, "OK (%u) \n", dID);
539     }
540
541     /* DDict scenario */
542     DISPLAYLEVEL(3, "test%3i : decompress %u bytes with digested dictionary : ", testNb++, (U32)CNBufferSize);
543     {   ZSTD_DDict* const ddict = ZSTD_createDDict(dictionary.start, dictionary.filled);
544         size_t const initError = ZSTD_initDStream_usingDDict(zd, ddict);
545         if (ZSTD_isError(initError)) goto _output_error;
546         outBuff.dst = decodedBuffer;
547         outBuff.size = CNBufferSize;
548         outBuff.pos = 0;
549         inBuff.src = compressedBuffer;
550         inBuff.size = cSize;
551         inBuff.pos = 0;
552         { size_t const r = ZSTD_decompressStream(zd, &outBuff, &inBuff);
553           if (r != 0) goto _output_error; }  /* should reach end of frame == 0; otherwise, some data left, or an error */
554         if (outBuff.pos != CNBufferSize) goto _output_error;   /* should regenerate the same amount */
555         if (inBuff.pos != inBuff.size) goto _output_error;   /* should have read the entire frame */
556         ZSTD_freeDDict(ddict);
557         DISPLAYLEVEL(3, "OK \n");
558     }
559
560     /* test ZSTD_setDStreamParameter() resilience */
561     DISPLAYLEVEL(3, "test%3i : wrong parameter for ZSTD_setDStreamParameter(): ", testNb++);
562     { size_t const r = ZSTD_setDStreamParameter(zd, (ZSTD_DStreamParameter_e)999, 1);  /* large limit */
563       if (!ZSTD_isError(r)) goto _output_error; }
564     DISPLAYLEVEL(3, "OK \n");
565
566     /* Memory restriction */
567     DISPLAYLEVEL(3, "test%3i : maxWindowSize < frame requirement : ", testNb++);
568     ZSTD_initDStream_usingDict(zd, CNBuffer, dictSize);
569     CHECK_Z( ZSTD_setDStreamParameter(zd, DStream_p_maxWindowSize, 1000) );  /* too small limit */
570     outBuff.dst = decodedBuffer;
571     outBuff.size = CNBufferSize;
572     outBuff.pos = 0;
573     inBuff.src = compressedBuffer;
574     inBuff.size = cSize;
575     inBuff.pos = 0;
576     { size_t const r = ZSTD_decompressStream(zd, &outBuff, &inBuff);
577       if (!ZSTD_isError(r)) goto _output_error;  /* must fail : frame requires > 100 bytes */
578       DISPLAYLEVEL(3, "OK (%s)\n", ZSTD_getErrorName(r)); }
579     ZSTD_DCtx_reset(zd);   /* leave zd in good shape for next tests */
580
581     DISPLAYLEVEL(3, "test%3i : dictionary source size and level : ", testNb++);
582     {   ZSTD_DCtx* const dctx = ZSTD_createDCtx();
583         int const maxLevel = 16;   /* first level with zstd_opt */
584         int level;
585         assert(maxLevel < ZSTD_maxCLevel());
586         CHECK_Z( ZSTD_DCtx_loadDictionary_byReference(dctx, dictionary.start, dictionary.filled) );
587         for (level = 1; level <= maxLevel; ++level) {
588             ZSTD_CDict* const cdict = ZSTD_createCDict(dictionary.start, dictionary.filled, level);
589             size_t const maxSize = MIN(1 MB, CNBufferSize);
590             size_t size;
591             for (size = 512; size <= maxSize; size <<= 1) {
592                 U64 const crcOrig = XXH64(CNBuffer, size, 0);
593                 ZSTD_CCtx* const cctx = ZSTD_createCCtx();
594                 outBuff.dst = compressedBuffer;
595                 outBuff.size = compressedBufferSize;
596                 outBuff.pos = 0;
597                 inBuff.src = CNBuffer;
598                 inBuff.size = size;
599                 inBuff.pos = 0;
600                 CHECK_Z(ZSTD_CCtx_refCDict(cctx, cdict));
601                 CHECK_Z(ZSTD_compress_generic(cctx, &outBuff, &inBuff, ZSTD_e_end));
602                 if (inBuff.pos != inBuff.size) goto _output_error;
603                 {   ZSTD_outBuffer decOut = {decodedBuffer, size, 0};
604                     ZSTD_inBuffer decIn = {outBuff.dst, outBuff.pos, 0};
605                     CHECK_Z( ZSTD_decompress_generic(dctx, &decOut, &decIn) );
606                     if (decIn.pos != decIn.size) goto _output_error;
607                     if (decOut.pos != size) goto _output_error;
608                     {   U64 const crcDec = XXH64(decOut.dst, decOut.pos, 0);
609                         if (crcDec != crcOrig) goto _output_error;
610                 }   }
611                 ZSTD_freeCCtx(cctx);
612             }
613             ZSTD_freeCDict(cdict);
614         }
615         ZSTD_freeDCtx(dctx);
616     }
617     DISPLAYLEVEL(3, "OK\n");
618
619     DISPLAYLEVEL(3, "test%3i : ZSTD_initCStream_usingCDict_advanced with masked dictID : ", testNb++);
620     {   ZSTD_compressionParameters const cParams = ZSTD_getCParams(1, CNBufferSize, dictionary.filled);
621         ZSTD_frameParameters const fParams = { 1 /* contentSize */, 1 /* checksum */, 1 /* noDictID */};
622         ZSTD_CDict* const cdict = ZSTD_createCDict_advanced(dictionary.start, dictionary.filled, ZSTD_dlm_byRef, ZSTD_dct_auto, cParams, ZSTD_defaultCMem);
623         size_t const initError = ZSTD_initCStream_usingCDict_advanced(zc, cdict, fParams, CNBufferSize);
624         if (ZSTD_isError(initError)) goto _output_error;
625         cSize = 0;
626         outBuff.dst = compressedBuffer;
627         outBuff.size = compressedBufferSize;
628         outBuff.pos = 0;
629         inBuff.src = CNBuffer;
630         inBuff.size = CNBufferSize;
631         inBuff.pos = 0;
632         CHECK_Z( ZSTD_compressStream(zc, &outBuff, &inBuff) );
633         if (inBuff.pos != inBuff.size) goto _output_error;  /* entire input should be consumed */
634         { size_t const r = ZSTD_endStream(zc, &outBuff);
635           if (r != 0) goto _output_error; }  /* error, or some data not flushed */
636         cSize = outBuff.pos;
637         ZSTD_freeCDict(cdict);
638         DISPLAYLEVEL(3, "OK (%u bytes : %.2f%%)\n", (U32)cSize, (double)cSize/CNBufferSize*100);
639     }
640
641     DISPLAYLEVEL(3, "test%3i : try retrieving dictID from frame : ", testNb++);
642     {   U32 const did = ZSTD_getDictID_fromFrame(compressedBuffer, cSize);
643         if (did != 0) goto _output_error;
644     }
645     DISPLAYLEVEL(3, "OK (not detected) \n");
646
647     DISPLAYLEVEL(3, "test%3i : decompress without dictionary : ", testNb++);
648     {   size_t const r = ZSTD_decompress(decodedBuffer, CNBufferSize, compressedBuffer, cSize);
649         if (!ZSTD_isError(r)) goto _output_error;  /* must fail : dictionary not used */
650         DISPLAYLEVEL(3, "OK (%s)\n", ZSTD_getErrorName(r));
651     }
652
653     DISPLAYLEVEL(3, "test%3i : compress with ZSTD_CCtx_refPrefix : ", testNb++);
654     CHECK_Z( ZSTD_CCtx_refPrefix(zc, dictionary.start, dictionary.filled) );
655     outBuff.dst = compressedBuffer;
656     outBuff.size = compressedBufferSize;
657     outBuff.pos = 0;
658     inBuff.src = CNBuffer;
659     inBuff.size = CNBufferSize;
660     inBuff.pos = 0;
661     CHECK_Z( ZSTD_compress_generic(zc, &outBuff, &inBuff, ZSTD_e_end) );
662     if (inBuff.pos != inBuff.size) goto _output_error;  /* entire input should be consumed */
663     cSize = outBuff.pos;
664     DISPLAYLEVEL(3, "OK (%u bytes : %.2f%%)\n", (U32)cSize, (double)cSize/CNBufferSize*100);
665
666     DISPLAYLEVEL(3, "test%3i : decompress with ZSTD_DCtx_refPrefix : ", testNb++);
667     CHECK_Z( ZSTD_DCtx_refPrefix(zd, dictionary.start, dictionary.filled) );
668     outBuff.dst = decodedBuffer;
669     outBuff.size = CNBufferSize;
670     outBuff.pos = 0;
671     inBuff.src = compressedBuffer;
672     inBuff.size = cSize;
673     inBuff.pos = 0;
674     CHECK_Z( ZSTD_decompress_generic(zd, &outBuff, &inBuff) );
675     if (inBuff.pos != inBuff.size) goto _output_error;  /* entire input should be consumed */
676     if (outBuff.pos != CNBufferSize) goto _output_error;  /* must regenerate whole input */
677     DISPLAYLEVEL(3, "OK \n");
678
679     DISPLAYLEVEL(3, "test%3i : decompress without dictionary (should fail): ", testNb++);
680     {   size_t const r = ZSTD_decompress(decodedBuffer, CNBufferSize, compressedBuffer, cSize);
681         if (!ZSTD_isError(r)) goto _output_error;  /* must fail : dictionary not used */
682         DISPLAYLEVEL(3, "OK (%s)\n", ZSTD_getErrorName(r));
683     }
684
685     DISPLAYLEVEL(3, "test%3i : compress again with ZSTD_compress_generic : ", testNb++);
686     outBuff.dst = compressedBuffer;
687     outBuff.size = compressedBufferSize;
688     outBuff.pos = 0;
689     inBuff.src = CNBuffer;
690     inBuff.size = CNBufferSize;
691     inBuff.pos = 0;
692     CHECK_Z( ZSTD_compress_generic(zc, &outBuff, &inBuff, ZSTD_e_end) );
693     if (inBuff.pos != inBuff.size) goto _output_error;  /* entire input should be consumed */
694     cSize = outBuff.pos;
695     DISPLAYLEVEL(3, "OK (%u bytes : %.2f%%)\n", (U32)cSize, (double)cSize/CNBufferSize*100);
696
697     DISPLAYLEVEL(3, "test%3i : decompress without dictionary (should work): ", testNb++);
698     CHECK_Z( ZSTD_decompress(decodedBuffer, CNBufferSize, compressedBuffer, cSize) );
699     DISPLAYLEVEL(3, "OK \n");
700
701     /* Empty srcSize */
702     DISPLAYLEVEL(3, "test%3i : ZSTD_initCStream_advanced with pledgedSrcSize=0 and dict : ", testNb++);
703     {   ZSTD_parameters params = ZSTD_getParams(5, 0, 0);
704         params.fParams.contentSizeFlag = 1;
705         CHECK_Z( ZSTD_initCStream_advanced(zc, dictionary.start, dictionary.filled, params, 0 /* pledgedSrcSize==0 means "empty" when params.fParams.contentSizeFlag is set */) );
706     } /* cstream advanced shall write content size = 0 */
707     outBuff.dst = compressedBuffer;
708     outBuff.size = compressedBufferSize;
709     outBuff.pos = 0;
710     inBuff.src = CNBuffer;
711     inBuff.size = 0;
712     inBuff.pos = 0;
713     CHECK_Z( ZSTD_compressStream(zc, &outBuff, &inBuff) );
714     if (ZSTD_endStream(zc, &outBuff) != 0) goto _output_error;
715     cSize = outBuff.pos;
716     if (ZSTD_findDecompressedSize(compressedBuffer, cSize) != 0) goto _output_error;
717     DISPLAYLEVEL(3, "OK \n");
718
719     DISPLAYLEVEL(3, "test%3i : pledgedSrcSize == 0 behaves properly : ", testNb++);
720     {   ZSTD_parameters params = ZSTD_getParams(5, 0, 0);
721         params.fParams.contentSizeFlag = 1;
722         CHECK_Z( ZSTD_initCStream_advanced(zc, NULL, 0, params, 0) );
723     } /* cstream advanced shall write content size = 0 */
724     inBuff.src = CNBuffer;
725     inBuff.size = 0;
726     inBuff.pos = 0;
727     outBuff.dst = compressedBuffer;
728     outBuff.size = compressedBufferSize;
729     outBuff.pos = 0;
730     CHECK_Z( ZSTD_compressStream(zc, &outBuff, &inBuff) );
731     if (ZSTD_endStream(zc, &outBuff) != 0) goto _output_error;
732     cSize = outBuff.pos;
733     if (ZSTD_findDecompressedSize(compressedBuffer, cSize) != 0) goto _output_error;
734
735     ZSTD_resetCStream(zc, 0); /* resetCStream should treat 0 as unknown */
736     outBuff.dst = compressedBuffer;
737     outBuff.size = compressedBufferSize;
738     outBuff.pos = 0;
739     inBuff.src = CNBuffer;
740     inBuff.size = 0;
741     inBuff.pos = 0;
742     CHECK_Z( ZSTD_compressStream(zc, &outBuff, &inBuff) );
743     if (ZSTD_endStream(zc, &outBuff) != 0) goto _output_error;
744     cSize = outBuff.pos;
745     if (ZSTD_findDecompressedSize(compressedBuffer, cSize) != ZSTD_CONTENTSIZE_UNKNOWN) goto _output_error;
746     DISPLAYLEVEL(3, "OK \n");
747
748     /* Basic multithreading compression test */
749     DISPLAYLEVEL(3, "test%3i : compress %u bytes with multiple threads : ", testNb++, COMPRESSIBLE_NOISE_LENGTH);
750     {   ZSTD_parameters const params = ZSTD_getParams(1, 0, 0);
751         CHECK_Z( ZSTDMT_initCStream_advanced(mtctx, CNBuffer, dictSize, params, CNBufferSize) );
752     }
753     outBuff.dst = compressedBuffer;
754     outBuff.size = compressedBufferSize;
755     outBuff.pos = 0;
756     inBuff.src = CNBuffer;
757     inBuff.size = CNBufferSize;
758     inBuff.pos = 0;
759     {   size_t const compressResult = ZSTDMT_compressStream_generic(mtctx, &outBuff, &inBuff, ZSTD_e_end);
760         if (compressResult != 0) goto _output_error;  /* compression must be completed in a single round */
761     }
762     if (inBuff.pos != inBuff.size) goto _output_error;   /* entire input should be consumed */
763     {   size_t const compressedSize = ZSTD_findFrameCompressedSize(compressedBuffer, outBuff.pos);
764         if (compressedSize != outBuff.pos) goto _output_error;  /* must be a full valid frame */
765     }
766     DISPLAYLEVEL(3, "OK \n");
767
768     /* Complex multithreading + dictionary test */
769     {   U32 const nbWorkers = 2;
770         size_t const jobSize = 4 * 1 MB;
771         size_t const srcSize = jobSize * nbWorkers;  /* we want each job to have predictable size */
772         size_t const segLength = 2 KB;
773         size_t const offset = 600 KB;   /* must be larger than window defined in cdict */
774         size_t const start = jobSize + (offset-1);
775         const BYTE* const srcToCopy = (const BYTE*)CNBuffer + start;
776         BYTE* const dst = (BYTE*)CNBuffer + start - offset;
777         DISPLAYLEVEL(3, "test%3i : compress %u bytes with multiple threads + dictionary : ", testNb++, (U32)srcSize);
778         CHECK_Z( ZSTD_CCtx_setParameter(zc, ZSTD_p_compressionLevel, 3) );
779         CHECK_Z( ZSTD_CCtx_setParameter(zc, ZSTD_p_nbWorkers, nbWorkers) );
780         CHECK_Z( ZSTD_CCtx_setParameter(zc, ZSTD_p_jobSize, jobSize) );
781         assert(start > offset);
782         assert(start + segLength < COMPRESSIBLE_NOISE_LENGTH);
783         memcpy(dst, srcToCopy, segLength);   /* create a long repetition at long distance for job 2 */
784         outBuff.dst = compressedBuffer;
785         outBuff.size = compressedBufferSize;
786         outBuff.pos = 0;
787         inBuff.src = CNBuffer;
788         inBuff.size = srcSize; assert(srcSize < COMPRESSIBLE_NOISE_LENGTH);
789         inBuff.pos = 0;
790     }
791     {   ZSTD_compressionParameters const cParams = ZSTD_getCParams(1, 4 KB, dictionary.filled);   /* intentionnally lies on estimatedSrcSize, to push cdict into targeting a small window size */
792         ZSTD_CDict* const cdict = ZSTD_createCDict_advanced(dictionary.start, dictionary.filled, ZSTD_dlm_byRef, ZSTD_dct_fullDict, cParams, ZSTD_defaultCMem);
793         DISPLAYLEVEL(5, "cParams.windowLog = %u : ", cParams.windowLog);
794         CHECK_Z( ZSTD_CCtx_refCDict(zc, cdict) );
795         CHECK_Z( ZSTD_compress_generic(zc, &outBuff, &inBuff, ZSTD_e_end) );
796         CHECK_Z( ZSTD_CCtx_refCDict(zc, NULL) );  /* do not keep a reference to cdict, as its lifetime ends */
797         ZSTD_freeCDict(cdict);
798     }
799     if (inBuff.pos != inBuff.size) goto _output_error;   /* entire input should be consumed */
800     cSize = outBuff.pos;
801     DISPLAYLEVEL(3, "OK \n");
802
803     DISPLAYLEVEL(3, "test%3i : decompress large frame created from multiple threads + dictionary : ", testNb++);
804     {   ZSTD_DStream* const dstream = ZSTD_createDCtx();
805         ZSTD_frameHeader zfh;
806         ZSTD_getFrameHeader(&zfh, compressedBuffer, cSize);
807         DISPLAYLEVEL(5, "frame windowsize = %u : ", (U32)zfh.windowSize);
808         outBuff.dst = decodedBuffer;
809         outBuff.size = CNBufferSize;
810         outBuff.pos = 0;
811         inBuff.src = compressedBuffer;
812         inBuff.pos = 0;
813         CHECK_Z( ZSTD_initDStream_usingDict(dstream, dictionary.start, dictionary.filled) );
814         inBuff.size = 1;  /* avoid shortcut to single-pass mode */
815         CHECK_Z( ZSTD_decompressStream(dstream, &outBuff, &inBuff) );
816         inBuff.size = cSize;
817         CHECK_Z( ZSTD_decompressStream(dstream, &outBuff, &inBuff) );
818         if (inBuff.pos != inBuff.size) goto _output_error;   /* entire input should be consumed */
819         ZSTD_freeDStream(dstream);
820     }
821     DISPLAYLEVEL(3, "OK \n");
822
823     DISPLAYLEVEL(3, "test%3i : check dictionary FSE tables can represent every code : ", testNb++);
824     {   unsigned const kMaxWindowLog = 24;
825         unsigned value;
826         ZSTD_compressionParameters cParams = ZSTD_getCParams(3, 1U << kMaxWindowLog, 1024);
827         ZSTD_CDict* cdict;
828         ZSTD_DDict* ddict;
829         SEQ_stream seq = SEQ_initStream(0x87654321);
830         SEQ_gen_type type;
831         XXH64_state_t xxh;
832
833         XXH64_reset(&xxh, 0);
834         cParams.windowLog = kMaxWindowLog;
835         cdict = ZSTD_createCDict_advanced(dictionary.start, dictionary.filled, ZSTD_dlm_byRef, ZSTD_dct_fullDict, cParams, ZSTD_defaultCMem);
836         ddict = ZSTD_createDDict(dictionary.start, dictionary.filled);
837
838         if (!cdict || !ddict) goto _output_error;
839
840         ZSTD_CCtx_reset(zc);
841         ZSTD_resetDStream(zd);
842         CHECK_Z(ZSTD_CCtx_refCDict(zc, cdict));
843         CHECK_Z(ZSTD_initDStream_usingDDict(zd, ddict));
844         CHECK_Z(ZSTD_setDStreamParameter(zd, DStream_p_maxWindowSize, 1U << kMaxWindowLog));
845         /* Test all values < 300 */
846         for (value = 0; value < 300; ++value) {
847             for (type = (SEQ_gen_type)0; type < SEQ_gen_max; ++type) {
848                 CHECK_Z(SEQ_generateRoundTrip(zc, zd, &xxh, &seq, type, value));
849             }
850         }
851         /* Test values 2^8 to 2^17 */
852         for (value = (1 << 8); value < (1 << 17); value <<= 1) {
853             for (type = (SEQ_gen_type)0; type < SEQ_gen_max; ++type) {
854                 CHECK_Z(SEQ_generateRoundTrip(zc, zd, &xxh, &seq, type, value));
855                 CHECK_Z(SEQ_generateRoundTrip(zc, zd, &xxh, &seq, type, value + (value >> 2)));
856             }
857         }
858         /* Test offset values up to the max window log */
859         for (value = 8; value <= kMaxWindowLog; ++value) {
860             CHECK_Z(SEQ_generateRoundTrip(zc, zd, &xxh, &seq, SEQ_gen_of, (1U << value) - 1));
861         }
862
863         CHECK_Z(SEQ_roundTrip(zc, zd, &xxh, NULL, 0, ZSTD_e_end));
864         CHECK(SEQ_digest(&seq) != XXH64_digest(&xxh), "SEQ XXH64 does not match");
865
866         ZSTD_freeCDict(cdict);
867         ZSTD_freeDDict(ddict);
868     }
869     DISPLAYLEVEL(3, "OK \n");
870
871     /* Overlen overwriting window data bug */
872     DISPLAYLEVEL(3, "test%3i : wildcopy doesn't overwrite potential match data : ", testNb++);
873     {   /* This test has a window size of 1024 bytes and consists of 3 blocks:
874             1. 'a' repeated 517 times
875             2. 'b' repeated 516 times
876             3. a compressed block with no literals and 3 sequence commands:
877                 litlength = 0, offset = 24, match length = 24
878                 litlength = 0, offset = 24, match length = 3 (this one creates an overlength write of length 2*WILDCOPY_OVERLENGTH - 3)
879                 litlength = 0, offset = 1021, match length = 3 (this one will try to read from overwritten data if the buffer is too small) */
880
881         const char* testCase =
882             "\x28\xB5\x2F\xFD\x04\x00\x4C\x00\x00\x10\x61\x61\x01\x00\x00\x2A"
883             "\x80\x05\x44\x00\x00\x08\x62\x01\x00\x00\x2A\x20\x04\x5D\x00\x00"
884             "\x00\x03\x40\x00\x00\x64\x60\x27\xB0\xE0\x0C\x67\x62\xCE\xE0";
885         ZSTD_DStream* const zds = ZSTD_createDStream();
886         if (zds==NULL) goto _output_error;
887
888         CHECK_Z( ZSTD_initDStream(zds) );
889         inBuff.src = testCase;
890         inBuff.size = 47;
891         inBuff.pos = 0;
892         outBuff.dst = decodedBuffer;
893         outBuff.size = CNBufferSize;
894         outBuff.pos = 0;
895
896         while (inBuff.pos < inBuff.size) {
897             CHECK_Z( ZSTD_decompressStream(zds, &outBuff, &inBuff) );
898         }
899
900         ZSTD_freeDStream(zds);
901     }
902     DISPLAYLEVEL(3, "OK \n");
903
904 _end:
905     FUZ_freeDictionary(dictionary);
906     ZSTD_freeCStream(zc);
907     ZSTD_freeDStream(zd);
908     ZSTDMT_freeCCtx(mtctx);
909     free(CNBuffer);
910     free(compressedBuffer);
911     free(decodedBuffer);
912     return testResult;
913
914 _output_error:
915     testResult = 1;
916     DISPLAY("Error detected in Unit tests ! \n");
917     goto _end;
918 }
919
920
921 /* ======   Fuzzer tests   ====== */
922
923 static size_t findDiff(const void* buf1, const void* buf2, size_t max)
924 {
925     const BYTE* b1 = (const BYTE*)buf1;
926     const BYTE* b2 = (const BYTE*)buf2;
927     size_t u;
928     for (u=0; u<max; u++) {
929         if (b1[u] != b2[u]) break;
930     }
931     if (u==max) {
932         DISPLAY("=> No difference detected within %u bytes \n", (U32)max);
933         return u;
934     }
935     DISPLAY("Error at position %u / %u \n", (U32)u, (U32)max);
936     if (u>=3)
937         DISPLAY(" %02X %02X %02X ",
938                 b1[u-3], b1[u-2], b1[u-1]);
939     DISPLAY(" :%02X:  %02X %02X %02X %02X %02X \n",
940             b1[u], b1[u+1], b1[u+2], b1[u+3], b1[u+4], b1[u+5]);
941     if (u>=3)
942         DISPLAY(" %02X %02X %02X ",
943                 b2[u-3], b2[u-2], b2[u-1]);
944     DISPLAY(" :%02X:  %02X %02X %02X %02X %02X \n",
945             b2[u], b2[u+1], b2[u+2], b2[u+3], b2[u+4], b2[u+5]);
946     return u;
947 }
948
949 static size_t FUZ_rLogLength(U32* seed, U32 logLength)
950 {
951     size_t const lengthMask = ((size_t)1 << logLength) - 1;
952     return (lengthMask+1) + (FUZ_rand(seed) & lengthMask);
953 }
954
955 static size_t FUZ_randomLength(U32* seed, U32 maxLog)
956 {
957     U32 const logLength = FUZ_rand(seed) % maxLog;
958     return FUZ_rLogLength(seed, logLength);
959 }
960
961 /* Return value in range minVal <= v <= maxVal */
962 static U32 FUZ_randomClampedLength(U32* seed, U32 minVal, U32 maxVal)
963 {
964     U32 const mod = maxVal < minVal ? 1 : (maxVal + 1) - minVal;
965     return (U32)((FUZ_rand(seed) % mod) + minVal);
966 }
967
968 static int fuzzerTests(U32 seed, U32 nbTests, unsigned startTest, double compressibility, int bigTests)
969 {
970     U32 const maxSrcLog = bigTests ? 24 : 22;
971     static const U32 maxSampleLog = 19;
972     size_t const srcBufferSize = (size_t)1<<maxSrcLog;
973     BYTE* cNoiseBuffer[5];
974     size_t const copyBufferSize = srcBufferSize + (1<<maxSampleLog);
975     BYTE*  const copyBuffer = (BYTE*)malloc (copyBufferSize);
976     size_t const cBufferSize = ZSTD_compressBound(srcBufferSize);
977     BYTE*  const cBuffer = (BYTE*)malloc (cBufferSize);
978     size_t const dstBufferSize = srcBufferSize;
979     BYTE*  const dstBuffer = (BYTE*)malloc (dstBufferSize);
980     U32 result = 0;
981     U32 testNb = 0;
982     U32 coreSeed = seed;
983     ZSTD_CStream* zc = ZSTD_createCStream();   /* will be re-created sometimes */
984     ZSTD_DStream* zd = ZSTD_createDStream();   /* will be re-created sometimes */
985     ZSTD_DStream* const zd_noise = ZSTD_createDStream();
986     UTIL_time_t const startClock = UTIL_getTime();
987     const BYTE* dict = NULL;  /* can keep same dict on 2 consecutive tests */
988     size_t dictSize = 0;
989     U32 oldTestLog = 0;
990     U32 const cLevelMax = bigTests ? (U32)ZSTD_maxCLevel() : g_cLevelMax_smallTests;
991
992     /* allocations */
993     cNoiseBuffer[0] = (BYTE*)malloc (srcBufferSize);
994     cNoiseBuffer[1] = (BYTE*)malloc (srcBufferSize);
995     cNoiseBuffer[2] = (BYTE*)malloc (srcBufferSize);
996     cNoiseBuffer[3] = (BYTE*)malloc (srcBufferSize);
997     cNoiseBuffer[4] = (BYTE*)malloc (srcBufferSize);
998     CHECK (!cNoiseBuffer[0] || !cNoiseBuffer[1] || !cNoiseBuffer[2] || !cNoiseBuffer[3] || !cNoiseBuffer[4] ||
999            !copyBuffer || !dstBuffer || !cBuffer || !zc || !zd || !zd_noise ,
1000            "Not enough memory, fuzzer tests cancelled");
1001
1002     /* Create initial samples */
1003     RDG_genBuffer(cNoiseBuffer[0], srcBufferSize, 0.00, 0., coreSeed);    /* pure noise */
1004     RDG_genBuffer(cNoiseBuffer[1], srcBufferSize, 0.05, 0., coreSeed);    /* barely compressible */
1005     RDG_genBuffer(cNoiseBuffer[2], srcBufferSize, compressibility, 0., coreSeed);
1006     RDG_genBuffer(cNoiseBuffer[3], srcBufferSize, 0.95, 0., coreSeed);    /* highly compressible */
1007     RDG_genBuffer(cNoiseBuffer[4], srcBufferSize, 1.00, 0., coreSeed);    /* sparse content */
1008     memset(copyBuffer, 0x65, copyBufferSize);                             /* make copyBuffer considered initialized */
1009     ZSTD_initDStream_usingDict(zd, NULL, 0);  /* ensure at least one init */
1010
1011     /* catch up testNb */
1012     for (testNb=1; testNb < startTest; testNb++)
1013         FUZ_rand(&coreSeed);
1014
1015     /* test loop */
1016     for ( ; (testNb <= nbTests) || (UTIL_clockSpanMicro(startClock) < g_clockTime) ; testNb++ ) {
1017         U32 lseed;
1018         const BYTE* srcBuffer;
1019         size_t totalTestSize, totalGenSize, cSize;
1020         XXH64_state_t xxhState;
1021         U64 crcOrig;
1022         U32 resetAllowed = 1;
1023         size_t maxTestSize;
1024
1025         /* init */
1026         FUZ_rand(&coreSeed);
1027         lseed = coreSeed ^ prime32;
1028         if (nbTests >= testNb) {
1029             DISPLAYUPDATE(2, "\r%6u/%6u    ", testNb, nbTests);
1030         } else {
1031             DISPLAYUPDATE(2, "\r%6u        ", testNb);
1032         }
1033
1034         /* states full reset (deliberately not synchronized) */
1035         /* some issues can only happen when reusing states */
1036         if ((FUZ_rand(&lseed) & 0xFF) == 131) {
1037             ZSTD_freeCStream(zc);
1038             zc = ZSTD_createCStream();
1039             CHECK(zc==NULL, "ZSTD_createCStream : allocation error");
1040             resetAllowed=0;
1041         }
1042         if ((FUZ_rand(&lseed) & 0xFF) == 132) {
1043             ZSTD_freeDStream(zd);
1044             zd = ZSTD_createDStream();
1045             CHECK(zd==NULL, "ZSTD_createDStream : allocation error");
1046             CHECK_Z( ZSTD_initDStream_usingDict(zd, NULL, 0) );  /* ensure at least one init */
1047         }
1048
1049         /* srcBuffer selection [0-4] */
1050         {   U32 buffNb = FUZ_rand(&lseed) & 0x7F;
1051             if (buffNb & 7) buffNb=2;   /* most common : compressible (P) */
1052             else {
1053                 buffNb >>= 3;
1054                 if (buffNb & 7) {
1055                     const U32 tnb[2] = { 1, 3 };   /* barely/highly compressible */
1056                     buffNb = tnb[buffNb >> 3];
1057                 } else {
1058                     const U32 tnb[2] = { 0, 4 };   /* not compressible / sparse */
1059                     buffNb = tnb[buffNb >> 3];
1060             }   }
1061             srcBuffer = cNoiseBuffer[buffNb];
1062         }
1063
1064         /* compression init */
1065         if ((FUZ_rand(&lseed)&1) /* at beginning, to keep same nb of rand */
1066             && oldTestLog /* at least one test happened */ && resetAllowed) {
1067             maxTestSize = FUZ_randomLength(&lseed, oldTestLog+2);
1068             maxTestSize = MIN(maxTestSize, srcBufferSize-16);
1069             {   U64 const pledgedSrcSize = (FUZ_rand(&lseed) & 3) ? 0 : maxTestSize;
1070                 CHECK_Z( ZSTD_resetCStream(zc, pledgedSrcSize) );
1071             }
1072         } else {
1073             U32 const testLog = FUZ_rand(&lseed) % maxSrcLog;
1074             U32 const dictLog = FUZ_rand(&lseed) % maxSrcLog;
1075             U32 const cLevelCandidate = ( FUZ_rand(&lseed) %
1076                                 (ZSTD_maxCLevel() -
1077                                 (MAX(testLog, dictLog) / 3)))
1078                                  + 1;
1079             U32 const cLevel = MIN(cLevelCandidate, cLevelMax);
1080             maxTestSize = FUZ_rLogLength(&lseed, testLog);
1081             oldTestLog = testLog;
1082             /* random dictionary selection */
1083             dictSize  = ((FUZ_rand(&lseed)&7)==1) ? FUZ_rLogLength(&lseed, dictLog) : 0;
1084             {   size_t const dictStart = FUZ_rand(&lseed) % (srcBufferSize - dictSize);
1085                 dict = srcBuffer + dictStart;
1086             }
1087             {   U64 const pledgedSrcSize = (FUZ_rand(&lseed) & 3) ? ZSTD_CONTENTSIZE_UNKNOWN : maxTestSize;
1088                 ZSTD_parameters params = ZSTD_getParams(cLevel, pledgedSrcSize, dictSize);
1089                 params.fParams.checksumFlag = FUZ_rand(&lseed) & 1;
1090                 params.fParams.noDictIDFlag = FUZ_rand(&lseed) & 1;
1091                 params.fParams.contentSizeFlag = FUZ_rand(&lseed) & 1;
1092                 CHECK_Z ( ZSTD_initCStream_advanced(zc, dict, dictSize, params, pledgedSrcSize) );
1093         }   }
1094
1095         /* multi-segments compression test */
1096         XXH64_reset(&xxhState, 0);
1097         {   ZSTD_outBuffer outBuff = { cBuffer, cBufferSize, 0 } ;
1098             U32 n;
1099             for (n=0, cSize=0, totalTestSize=0 ; totalTestSize < maxTestSize ; n++) {
1100                 /* compress random chunks into randomly sized dst buffers */
1101                 {   size_t const randomSrcSize = FUZ_randomLength(&lseed, maxSampleLog);
1102                     size_t const srcSize = MIN(maxTestSize-totalTestSize, randomSrcSize);
1103                     size_t const srcStart = FUZ_rand(&lseed) % (srcBufferSize - srcSize);
1104                     size_t const randomDstSize = FUZ_randomLength(&lseed, maxSampleLog);
1105                     size_t const dstBuffSize = MIN(cBufferSize - cSize, randomDstSize);
1106                     ZSTD_inBuffer inBuff = { srcBuffer+srcStart, srcSize, 0 };
1107                     outBuff.size = outBuff.pos + dstBuffSize;
1108
1109                     CHECK_Z( ZSTD_compressStream(zc, &outBuff, &inBuff) );
1110
1111                     XXH64_update(&xxhState, srcBuffer+srcStart, inBuff.pos);
1112                     memcpy(copyBuffer+totalTestSize, srcBuffer+srcStart, inBuff.pos);
1113                     totalTestSize += inBuff.pos;
1114                 }
1115
1116                 /* random flush operation, to mess around */
1117                 if ((FUZ_rand(&lseed) & 15) == 0) {
1118                     size_t const randomDstSize = FUZ_randomLength(&lseed, maxSampleLog);
1119                     size_t const adjustedDstSize = MIN(cBufferSize - cSize, randomDstSize);
1120                     outBuff.size = outBuff.pos + adjustedDstSize;
1121                     CHECK_Z( ZSTD_flushStream(zc, &outBuff) );
1122             }   }
1123
1124             /* final frame epilogue */
1125             {   size_t remainingToFlush = (size_t)(-1);
1126                 while (remainingToFlush) {
1127                     size_t const randomDstSize = FUZ_randomLength(&lseed, maxSampleLog);
1128                     size_t const adjustedDstSize = MIN(cBufferSize - cSize, randomDstSize);
1129                     outBuff.size = outBuff.pos + adjustedDstSize;
1130                     remainingToFlush = ZSTD_endStream(zc, &outBuff);
1131                     CHECK (ZSTD_isError(remainingToFlush), "end error : %s", ZSTD_getErrorName(remainingToFlush));
1132             }   }
1133             crcOrig = XXH64_digest(&xxhState);
1134             cSize = outBuff.pos;
1135         }
1136
1137         /* multi - fragments decompression test */
1138         if (!dictSize /* don't reset if dictionary : could be different */ && (FUZ_rand(&lseed) & 1)) {
1139             CHECK_Z ( ZSTD_resetDStream(zd) );
1140         } else {
1141             CHECK_Z ( ZSTD_initDStream_usingDict(zd, dict, dictSize) );
1142         }
1143         {   size_t decompressionResult = 1;
1144             ZSTD_inBuffer  inBuff = { cBuffer, cSize, 0 };
1145             ZSTD_outBuffer outBuff= { dstBuffer, dstBufferSize, 0 };
1146             for (totalGenSize = 0 ; decompressionResult ; ) {
1147                 size_t const readCSrcSize = FUZ_randomLength(&lseed, maxSampleLog);
1148                 size_t const randomDstSize = FUZ_randomLength(&lseed, maxSampleLog);
1149                 size_t const dstBuffSize = MIN(dstBufferSize - totalGenSize, randomDstSize);
1150                 inBuff.size = inBuff.pos + readCSrcSize;
1151                 outBuff.size = outBuff.pos + dstBuffSize;
1152                 decompressionResult = ZSTD_decompressStream(zd, &outBuff, &inBuff);
1153                 if (ZSTD_getErrorCode(decompressionResult) == ZSTD_error_checksum_wrong) {
1154                     DISPLAY("checksum error : \n");
1155                     findDiff(copyBuffer, dstBuffer, totalTestSize);
1156                 }
1157                 CHECK( ZSTD_isError(decompressionResult), "decompression error : %s",
1158                        ZSTD_getErrorName(decompressionResult) );
1159             }
1160             CHECK (decompressionResult != 0, "frame not fully decoded");
1161             CHECK (outBuff.pos != totalTestSize, "decompressed data : wrong size (%u != %u)",
1162                     (U32)outBuff.pos, (U32)totalTestSize);
1163             CHECK (inBuff.pos != cSize, "compressed data should be fully read")
1164             {   U64 const crcDest = XXH64(dstBuffer, totalTestSize, 0);
1165                 if (crcDest!=crcOrig) findDiff(copyBuffer, dstBuffer, totalTestSize);
1166                 CHECK (crcDest!=crcOrig, "decompressed data corrupted");
1167         }   }
1168
1169         /*=====   noisy/erroneous src decompression test   =====*/
1170
1171         /* add some noise */
1172         {   U32 const nbNoiseChunks = (FUZ_rand(&lseed) & 7) + 2;
1173             U32 nn; for (nn=0; nn<nbNoiseChunks; nn++) {
1174                 size_t const randomNoiseSize = FUZ_randomLength(&lseed, maxSampleLog);
1175                 size_t const noiseSize  = MIN((cSize/3) , randomNoiseSize);
1176                 size_t const noiseStart = FUZ_rand(&lseed) % (srcBufferSize - noiseSize);
1177                 size_t const cStart = FUZ_rand(&lseed) % (cSize - noiseSize);
1178                 memcpy(cBuffer+cStart, srcBuffer+noiseStart, noiseSize);
1179         }   }
1180
1181         /* try decompression on noisy data */
1182         CHECK_Z( ZSTD_initDStream(zd_noise) );   /* note : no dictionary */
1183         {   ZSTD_inBuffer  inBuff = { cBuffer, cSize, 0 };
1184             ZSTD_outBuffer outBuff= { dstBuffer, dstBufferSize, 0 };
1185             while (outBuff.pos < dstBufferSize) {
1186                 size_t const randomCSrcSize = FUZ_randomLength(&lseed, maxSampleLog);
1187                 size_t const randomDstSize = FUZ_randomLength(&lseed, maxSampleLog);
1188                 size_t const adjustedDstSize = MIN(dstBufferSize - outBuff.pos, randomDstSize);
1189                 size_t const adjustedCSrcSize = MIN(cSize - inBuff.pos, randomCSrcSize);
1190                 outBuff.size = outBuff.pos + adjustedDstSize;
1191                 inBuff.size  = inBuff.pos + adjustedCSrcSize;
1192                 {   size_t const decompressError = ZSTD_decompressStream(zd, &outBuff, &inBuff);
1193                     if (ZSTD_isError(decompressError)) break;   /* error correctly detected */
1194                     /* No forward progress possible */
1195                     if (outBuff.pos < outBuff.size && inBuff.pos == cSize) break;
1196     }   }   }   }
1197     DISPLAY("\r%u fuzzer tests completed   \n", testNb);
1198
1199 _cleanup:
1200     ZSTD_freeCStream(zc);
1201     ZSTD_freeDStream(zd);
1202     ZSTD_freeDStream(zd_noise);
1203     free(cNoiseBuffer[0]);
1204     free(cNoiseBuffer[1]);
1205     free(cNoiseBuffer[2]);
1206     free(cNoiseBuffer[3]);
1207     free(cNoiseBuffer[4]);
1208     free(copyBuffer);
1209     free(cBuffer);
1210     free(dstBuffer);
1211     return result;
1212
1213 _output_error:
1214     result = 1;
1215     goto _cleanup;
1216 }
1217
1218
1219 /* Multi-threading version of fuzzer Tests */
1220 static int fuzzerTests_MT(U32 seed, U32 nbTests, unsigned startTest, double compressibility, int bigTests)
1221 {
1222     const U32 maxSrcLog = bigTests ? 24 : 22;
1223     static const U32 maxSampleLog = 19;
1224     size_t const srcBufferSize = (size_t)1<<maxSrcLog;
1225     BYTE* cNoiseBuffer[5];
1226     size_t const copyBufferSize= srcBufferSize + (1<<maxSampleLog);
1227     BYTE*  const copyBuffer = (BYTE*)malloc (copyBufferSize);
1228     size_t const cBufferSize   = ZSTD_compressBound(srcBufferSize);
1229     BYTE*  const cBuffer = (BYTE*)malloc (cBufferSize);
1230     size_t const dstBufferSize = srcBufferSize;
1231     BYTE*  const dstBuffer = (BYTE*)malloc (dstBufferSize);
1232     U32 result = 0;
1233     U32 testNb = 0;
1234     U32 coreSeed = seed;
1235     U32 nbThreads = 2;
1236     ZSTDMT_CCtx* zc = ZSTDMT_createCCtx(nbThreads);   /* will be reset sometimes */
1237     ZSTD_DStream* zd = ZSTD_createDStream();   /* will be reset sometimes */
1238     ZSTD_DStream* const zd_noise = ZSTD_createDStream();
1239     UTIL_time_t const startClock = UTIL_getTime();
1240     const BYTE* dict=NULL;   /* can keep same dict on 2 consecutive tests */
1241     size_t dictSize = 0;
1242     int const cLevelMax = bigTests ? (U32)ZSTD_maxCLevel()-1 : g_cLevelMax_smallTests;
1243     U32 const nbThreadsMax = bigTests ? 4 : 2;
1244
1245     /* allocations */
1246     cNoiseBuffer[0] = (BYTE*)malloc (srcBufferSize);
1247     cNoiseBuffer[1] = (BYTE*)malloc (srcBufferSize);
1248     cNoiseBuffer[2] = (BYTE*)malloc (srcBufferSize);
1249     cNoiseBuffer[3] = (BYTE*)malloc (srcBufferSize);
1250     cNoiseBuffer[4] = (BYTE*)malloc (srcBufferSize);
1251     CHECK (!cNoiseBuffer[0] || !cNoiseBuffer[1] || !cNoiseBuffer[2] || !cNoiseBuffer[3] || !cNoiseBuffer[4] ||
1252            !copyBuffer || !dstBuffer || !cBuffer || !zc || !zd || !zd_noise ,
1253            "Not enough memory, fuzzer tests cancelled");
1254
1255     /* Create initial samples */
1256     RDG_genBuffer(cNoiseBuffer[0], srcBufferSize, 0.00, 0., coreSeed);    /* pure noise */
1257     RDG_genBuffer(cNoiseBuffer[1], srcBufferSize, 0.05, 0., coreSeed);    /* barely compressible */
1258     RDG_genBuffer(cNoiseBuffer[2], srcBufferSize, compressibility, 0., coreSeed);
1259     RDG_genBuffer(cNoiseBuffer[3], srcBufferSize, 0.95, 0., coreSeed);    /* highly compressible */
1260     RDG_genBuffer(cNoiseBuffer[4], srcBufferSize, 1.00, 0., coreSeed);    /* sparse content */
1261     memset(copyBuffer, 0x65, copyBufferSize);                             /* make copyBuffer considered initialized */
1262     ZSTD_initDStream_usingDict(zd, NULL, 0);  /* ensure at least one init */
1263     DISPLAYLEVEL(6, "Creating initial context with %u threads \n", nbThreads);
1264
1265     /* catch up testNb */
1266     for (testNb=1; testNb < startTest; testNb++)
1267         FUZ_rand(&coreSeed);
1268
1269     /* test loop */
1270     for ( ; (testNb <= nbTests) || (UTIL_clockSpanMicro(startClock) < g_clockTime) ; testNb++ ) {
1271         U32 lseed;
1272         const BYTE* srcBuffer;
1273         size_t totalTestSize, totalGenSize, cSize;
1274         XXH64_state_t xxhState;
1275         U64 crcOrig;
1276         size_t maxTestSize;
1277
1278         FUZ_rand(&coreSeed);
1279         if (nbTests >= testNb) {
1280             DISPLAYUPDATE(2, "\r%6u/%6u    ", testNb, nbTests);
1281         } else {
1282             DISPLAYUPDATE(2, "\r%6u         ", testNb);
1283         }
1284         lseed = coreSeed ^ prime32;
1285
1286         /* states full reset (deliberately not synchronized) */
1287         /* some issues can only happen when reusing states */
1288         if ((FUZ_rand(&lseed) & 0xFF) == 131) {
1289             nbThreads = (FUZ_rand(&lseed) % nbThreadsMax) + 1;
1290             DISPLAYLEVEL(5, "Creating new context with %u threads \n", nbThreads);
1291             ZSTDMT_freeCCtx(zc);
1292             zc = ZSTDMT_createCCtx(nbThreads);
1293             CHECK(zc==NULL, "ZSTDMT_createCCtx allocation error")
1294         }
1295         if ((FUZ_rand(&lseed) & 0xFF) == 132) {
1296             ZSTD_freeDStream(zd);
1297             zd = ZSTD_createDStream();
1298             CHECK(zd==NULL, "ZSTDMT_createCCtx allocation error")
1299             ZSTD_initDStream_usingDict(zd, NULL, 0);  /* ensure at least one init */
1300         }
1301
1302         /* srcBuffer selection [0-4] */
1303         {   U32 buffNb = FUZ_rand(&lseed) & 0x7F;
1304             if (buffNb & 7) buffNb=2;   /* most common : compressible (P) */
1305             else {
1306                 buffNb >>= 3;
1307                 if (buffNb & 7) {
1308                     const U32 tnb[2] = { 1, 3 };   /* barely/highly compressible */
1309                     buffNb = tnb[buffNb >> 3];
1310                 } else {
1311                     const U32 tnb[2] = { 0, 4 };   /* not compressible / sparse */
1312                     buffNb = tnb[buffNb >> 3];
1313             }   }
1314             srcBuffer = cNoiseBuffer[buffNb];
1315         }
1316
1317         /* compression init */
1318         {   U32 const testLog = FUZ_rand(&lseed) % maxSrcLog;
1319             U32 const dictLog = FUZ_rand(&lseed) % maxSrcLog;
1320             int const cLevelCandidate = ( FUZ_rand(&lseed)
1321                             % (ZSTD_maxCLevel() - (MAX(testLog, dictLog) / 2)) )
1322                             + 1;
1323             int const cLevelThreadAdjusted = cLevelCandidate - (nbThreads * 2) + 2;  /* reduce cLevel when multiple threads to reduce memory consumption */
1324             int const cLevelMin = MAX(cLevelThreadAdjusted, 1);  /* no negative cLevel yet */
1325             int const cLevel = MIN(cLevelMin, cLevelMax);
1326             maxTestSize = FUZ_rLogLength(&lseed, testLog);
1327
1328             if (FUZ_rand(&lseed)&1) {   /* simple init */
1329                 int const compressionLevel = (FUZ_rand(&lseed) % 5) + 1;
1330                 DISPLAYLEVEL(5, "Init with compression level = %i \n", compressionLevel);
1331                 CHECK_Z( ZSTDMT_initCStream(zc, compressionLevel) );
1332             } else {   /* advanced init */
1333                 /* random dictionary selection */
1334                 dictSize  = ((FUZ_rand(&lseed)&63)==1) ? FUZ_rLogLength(&lseed, dictLog) : 0;
1335                 {   size_t const dictStart = FUZ_rand(&lseed) % (srcBufferSize - dictSize);
1336                     dict = srcBuffer + dictStart;
1337                 }
1338                 {   U64 const pledgedSrcSize = (FUZ_rand(&lseed) & 3) ? ZSTD_CONTENTSIZE_UNKNOWN : maxTestSize;
1339                     ZSTD_parameters params = ZSTD_getParams(cLevel, pledgedSrcSize, dictSize);
1340                     DISPLAYLEVEL(5, "Init with windowLog = %u, pledgedSrcSize = %u, dictSize = %u \n",
1341                         params.cParams.windowLog, (U32)pledgedSrcSize, (U32)dictSize);
1342                     params.fParams.checksumFlag = FUZ_rand(&lseed) & 1;
1343                     params.fParams.noDictIDFlag = FUZ_rand(&lseed) & 1;
1344                     params.fParams.contentSizeFlag = FUZ_rand(&lseed) & 1;
1345                     DISPLAYLEVEL(5, "checksumFlag : %u \n", params.fParams.checksumFlag);
1346                     CHECK_Z( ZSTDMT_setMTCtxParameter(zc, ZSTDMT_p_overlapSectionLog, FUZ_rand(&lseed) % 12) );
1347                     CHECK_Z( ZSTDMT_setMTCtxParameter(zc, ZSTDMT_p_jobSize, FUZ_rand(&lseed) % (2*maxTestSize+1)) );   /* custome job size */
1348                     CHECK_Z( ZSTDMT_initCStream_advanced(zc, dict, dictSize, params, pledgedSrcSize) );
1349         }   }   }
1350
1351         /* multi-segments compression test */
1352         XXH64_reset(&xxhState, 0);
1353         {   ZSTD_outBuffer outBuff = { cBuffer, cBufferSize, 0 } ;
1354             U32 n;
1355             for (n=0, cSize=0, totalTestSize=0 ; totalTestSize < maxTestSize ; n++) {
1356                 /* compress random chunks into randomly sized dst buffers */
1357                 {   size_t const randomSrcSize = FUZ_randomLength(&lseed, maxSampleLog);
1358                     size_t const srcSize = MIN (maxTestSize-totalTestSize, randomSrcSize);
1359                     size_t const srcStart = FUZ_rand(&lseed) % (srcBufferSize - srcSize);
1360                     size_t const randomDstSize = FUZ_randomLength(&lseed, maxSampleLog);
1361                     size_t const dstBuffSize = MIN(cBufferSize - cSize, randomDstSize);
1362                     ZSTD_inBuffer inBuff = { srcBuffer+srcStart, srcSize, 0 };
1363                     outBuff.size = outBuff.pos + dstBuffSize;
1364
1365                     DISPLAYLEVEL(6, "Sending %u bytes to compress \n", (U32)srcSize);
1366                     CHECK_Z( ZSTDMT_compressStream(zc, &outBuff, &inBuff) );
1367                     DISPLAYLEVEL(6, "%u bytes read by ZSTDMT_compressStream \n", (U32)inBuff.pos);
1368
1369                     XXH64_update(&xxhState, srcBuffer+srcStart, inBuff.pos);
1370                     memcpy(copyBuffer+totalTestSize, srcBuffer+srcStart, inBuff.pos);
1371                     totalTestSize += inBuff.pos;
1372                 }
1373
1374                 /* random flush operation, to mess around */
1375                 if ((FUZ_rand(&lseed) & 15) == 0) {
1376                     size_t const randomDstSize = FUZ_randomLength(&lseed, maxSampleLog);
1377                     size_t const adjustedDstSize = MIN(cBufferSize - cSize, randomDstSize);
1378                     size_t const previousPos = outBuff.pos;
1379                     outBuff.size = outBuff.pos + adjustedDstSize;
1380                     DISPLAYLEVEL(5, "Flushing into dst buffer of size %u \n", (U32)adjustedDstSize);
1381                     CHECK_Z( ZSTDMT_flushStream(zc, &outBuff) );
1382                     assert(outBuff.pos >= previousPos);
1383                     DISPLAYLEVEL(6, "%u bytes flushed by ZSTDMT_flushStream \n", (U32)(outBuff.pos-previousPos));
1384             }   }
1385
1386             /* final frame epilogue */
1387             {   size_t remainingToFlush = (size_t)(-1);
1388                 while (remainingToFlush) {
1389                     size_t const randomDstSize = FUZ_randomLength(&lseed, maxSampleLog);
1390                     size_t const adjustedDstSize = MIN(cBufferSize - cSize, randomDstSize);
1391                     size_t const previousPos = outBuff.pos;
1392                     outBuff.size = outBuff.pos + adjustedDstSize;
1393                     DISPLAYLEVEL(5, "Ending into dst buffer of size %u \n", (U32)adjustedDstSize);
1394                     remainingToFlush = ZSTDMT_endStream(zc, &outBuff);
1395                     CHECK (ZSTD_isError(remainingToFlush), "ZSTDMT_endStream error : %s", ZSTD_getErrorName(remainingToFlush));
1396                     assert(outBuff.pos >= previousPos);
1397                     DISPLAYLEVEL(6, "%u bytes flushed by ZSTDMT_endStream \n", (U32)(outBuff.pos-previousPos));
1398                     DISPLAYLEVEL(5, "endStream : remainingToFlush : %u \n", (U32)remainingToFlush);
1399             }   }
1400             crcOrig = XXH64_digest(&xxhState);
1401             cSize = outBuff.pos;
1402             DISPLAYLEVEL(5, "Frame completed : %u bytes compressed into %u bytes \n",
1403                             (U32)totalTestSize, (U32)cSize);
1404         }
1405
1406         /* multi - fragments decompression test */
1407         assert(totalTestSize < dstBufferSize);
1408         memset(dstBuffer, 170, totalTestSize);   /* init dest area */
1409         if (!dictSize /* don't reset if dictionary : could be different */ && (FUZ_rand(&lseed) & 1)) {
1410             CHECK_Z( ZSTD_resetDStream(zd) );
1411         } else {
1412             CHECK_Z( ZSTD_initDStream_usingDict(zd, dict, dictSize) );
1413         }
1414         {   size_t decompressionResult = 1;
1415             ZSTD_inBuffer  inBuff = { cBuffer, cSize, 0 };
1416             ZSTD_outBuffer outBuff= { dstBuffer, dstBufferSize, 0 };
1417             for (totalGenSize = 0 ; decompressionResult ; ) {
1418                 size_t const readCSrcSize = FUZ_randomLength(&lseed, maxSampleLog);
1419                 size_t const randomDstSize = FUZ_randomLength(&lseed, maxSampleLog);
1420                 size_t const dstBuffSize = MIN(dstBufferSize - totalGenSize, randomDstSize);
1421                 inBuff.size = inBuff.pos + readCSrcSize;
1422                 outBuff.size = outBuff.pos + dstBuffSize;
1423                 DISPLAYLEVEL(6, "ZSTD_decompressStream input %u bytes into outBuff %u bytes \n",
1424                                 (U32)readCSrcSize, (U32)dstBuffSize);
1425                 decompressionResult = ZSTD_decompressStream(zd, &outBuff, &inBuff);
1426                 if (ZSTD_isError(decompressionResult)) {
1427                     DISPLAY("ZSTD_decompressStream error : %s \n", ZSTD_getErrorName(decompressionResult));
1428                     findDiff(copyBuffer, dstBuffer, totalTestSize);
1429                 }
1430                 CHECK (ZSTD_isError(decompressionResult), "decompression error : %s", ZSTD_getErrorName(decompressionResult));
1431                 DISPLAYLEVEL(6, "total ingested (inBuff.pos) = %u and produced (outBuff.pos) = %u \n",
1432                                 (U32)inBuff.pos, (U32)outBuff.pos);
1433             }
1434             CHECK (outBuff.pos != totalTestSize, "decompressed data : wrong size (%u != %u)", (U32)outBuff.pos, (U32)totalTestSize);
1435             CHECK (inBuff.pos != cSize, "compressed data should be fully read (%u != %u)", (U32)inBuff.pos, (U32)cSize);
1436             {   U64 const crcDest = XXH64(dstBuffer, totalTestSize, 0);
1437                 if (crcDest!=crcOrig) findDiff(copyBuffer, dstBuffer, totalTestSize);
1438                 CHECK (crcDest!=crcOrig, "decompressed data corrupted");
1439         }   }
1440
1441         /*=====   noisy/erroneous src decompression test   =====*/
1442
1443         /* add some noise */
1444         {   U32 const nbNoiseChunks = (FUZ_rand(&lseed) & 7) + 2;
1445             U32 nn; for (nn=0; nn<nbNoiseChunks; nn++) {
1446                 size_t const randomNoiseSize = FUZ_randomLength(&lseed, maxSampleLog);
1447                 size_t const noiseSize  = MIN((cSize/3) , randomNoiseSize);
1448                 size_t const noiseStart = FUZ_rand(&lseed) % (srcBufferSize - noiseSize);
1449                 size_t const cStart = FUZ_rand(&lseed) % (cSize - noiseSize);
1450                 memcpy(cBuffer+cStart, srcBuffer+noiseStart, noiseSize);
1451         }   }
1452
1453         /* try decompression on noisy data */
1454         CHECK_Z( ZSTD_initDStream(zd_noise) );   /* note : no dictionary */
1455         {   ZSTD_inBuffer  inBuff = { cBuffer, cSize, 0 };
1456             ZSTD_outBuffer outBuff= { dstBuffer, dstBufferSize, 0 };
1457             while (outBuff.pos < dstBufferSize) {
1458                 size_t const randomCSrcSize = FUZ_randomLength(&lseed, maxSampleLog);
1459                 size_t const randomDstSize = FUZ_randomLength(&lseed, maxSampleLog);
1460                 size_t const adjustedDstSize = MIN(dstBufferSize - outBuff.pos, randomDstSize);
1461                 size_t const adjustedCSrcSize = MIN(cSize - inBuff.pos, randomCSrcSize);
1462                 outBuff.size = outBuff.pos + adjustedDstSize;
1463                 inBuff.size  = inBuff.pos + adjustedCSrcSize;
1464                 {   size_t const decompressError = ZSTD_decompressStream(zd, &outBuff, &inBuff);
1465                     if (ZSTD_isError(decompressError)) break;   /* error correctly detected */
1466                     /* No forward progress possible */
1467                     if (outBuff.pos < outBuff.size && inBuff.pos == cSize) break;
1468     }   }   }   }
1469     DISPLAY("\r%u fuzzer tests completed   \n", testNb);
1470
1471 _cleanup:
1472     ZSTDMT_freeCCtx(zc);
1473     ZSTD_freeDStream(zd);
1474     ZSTD_freeDStream(zd_noise);
1475     free(cNoiseBuffer[0]);
1476     free(cNoiseBuffer[1]);
1477     free(cNoiseBuffer[2]);
1478     free(cNoiseBuffer[3]);
1479     free(cNoiseBuffer[4]);
1480     free(copyBuffer);
1481     free(cBuffer);
1482     free(dstBuffer);
1483     return result;
1484
1485 _output_error:
1486     result = 1;
1487     goto _cleanup;
1488 }
1489
1490 /** If useOpaqueAPI, sets param in cctxParams.
1491  *  Otherwise, sets the param in zc. */
1492 static size_t setCCtxParameter(ZSTD_CCtx* zc, ZSTD_CCtx_params* cctxParams,
1493                                ZSTD_cParameter param, unsigned value,
1494                                U32 useOpaqueAPI)
1495 {
1496     if (useOpaqueAPI) {
1497         return ZSTD_CCtxParam_setParameter(cctxParams, param, value);
1498     } else {
1499         return ZSTD_CCtx_setParameter(zc, param, value);
1500     }
1501 }
1502
1503 /* Tests for ZSTD_compress_generic() API */
1504 static int fuzzerTests_newAPI(U32 seed, U32 nbTests, unsigned startTest, double compressibility, int bigTests, U32 const useOpaqueAPI)
1505 {
1506     U32 const maxSrcLog = bigTests ? 24 : 22;
1507     static const U32 maxSampleLog = 19;
1508     size_t const srcBufferSize = (size_t)1<<maxSrcLog;
1509     BYTE* cNoiseBuffer[5];
1510     size_t const copyBufferSize= srcBufferSize + (1<<maxSampleLog);
1511     BYTE*  const copyBuffer = (BYTE*)malloc (copyBufferSize);
1512     size_t const cBufferSize   = ZSTD_compressBound(srcBufferSize);
1513     BYTE*  const cBuffer = (BYTE*)malloc (cBufferSize);
1514     size_t const dstBufferSize = srcBufferSize;
1515     BYTE*  const dstBuffer = (BYTE*)malloc (dstBufferSize);
1516     U32 result = 0;
1517     U32 testNb = 0;
1518     U32 coreSeed = seed;
1519     ZSTD_CCtx* zc = ZSTD_createCCtx();   /* will be reset sometimes */
1520     ZSTD_DStream* zd = ZSTD_createDStream();   /* will be reset sometimes */
1521     ZSTD_DStream* const zd_noise = ZSTD_createDStream();
1522     UTIL_time_t const startClock = UTIL_getTime();
1523     const BYTE* dict = NULL;   /* can keep same dict on 2 consecutive tests */
1524     size_t dictSize = 0;
1525     U32 oldTestLog = 0;
1526     U32 windowLogMalus = 0;   /* can survive between 2 loops */
1527     U32 const cLevelMax = bigTests ? (U32)ZSTD_maxCLevel()-1 : g_cLevelMax_smallTests;
1528     U32 const nbThreadsMax = bigTests ? 4 : 2;
1529     ZSTD_CCtx_params* cctxParams = ZSTD_createCCtxParams();
1530
1531     /* allocations */
1532     cNoiseBuffer[0] = (BYTE*)malloc (srcBufferSize);
1533     cNoiseBuffer[1] = (BYTE*)malloc (srcBufferSize);
1534     cNoiseBuffer[2] = (BYTE*)malloc (srcBufferSize);
1535     cNoiseBuffer[3] = (BYTE*)malloc (srcBufferSize);
1536     cNoiseBuffer[4] = (BYTE*)malloc (srcBufferSize);
1537     CHECK (!cNoiseBuffer[0] || !cNoiseBuffer[1] || !cNoiseBuffer[2] || !cNoiseBuffer[3] || !cNoiseBuffer[4] ||
1538            !copyBuffer || !dstBuffer || !cBuffer || !zc || !zd || !zd_noise ,
1539            "Not enough memory, fuzzer tests cancelled");
1540
1541     /* Create initial samples */
1542     RDG_genBuffer(cNoiseBuffer[0], srcBufferSize, 0.00, 0., coreSeed);    /* pure noise */
1543     RDG_genBuffer(cNoiseBuffer[1], srcBufferSize, 0.05, 0., coreSeed);    /* barely compressible */
1544     RDG_genBuffer(cNoiseBuffer[2], srcBufferSize, compressibility, 0., coreSeed);
1545     RDG_genBuffer(cNoiseBuffer[3], srcBufferSize, 0.95, 0., coreSeed);    /* highly compressible */
1546     RDG_genBuffer(cNoiseBuffer[4], srcBufferSize, 1.00, 0., coreSeed);    /* sparse content */
1547     memset(copyBuffer, 0x65, copyBufferSize);                             /* make copyBuffer considered initialized */
1548     CHECK_Z( ZSTD_initDStream_usingDict(zd, NULL, 0) );   /* ensure at least one init */
1549
1550     /* catch up testNb */
1551     for (testNb=1; testNb < startTest; testNb++)
1552         FUZ_rand(&coreSeed);
1553
1554     /* test loop */
1555     for ( ; (testNb <= nbTests) || (UTIL_clockSpanMicro(startClock) < g_clockTime) ; testNb++ ) {
1556         U32 lseed;
1557         const BYTE* srcBuffer;
1558         size_t totalTestSize, totalGenSize, cSize;
1559         XXH64_state_t xxhState;
1560         U64 crcOrig;
1561         U32 resetAllowed = 1;
1562         size_t maxTestSize;
1563
1564         /* init */
1565         if (nbTests >= testNb) { DISPLAYUPDATE(2, "\r%6u/%6u    ", testNb, nbTests); }
1566         else { DISPLAYUPDATE(2, "\r%6u          ", testNb); }
1567         FUZ_rand(&coreSeed);
1568         lseed = coreSeed ^ prime32;
1569         DISPLAYLEVEL(5, " ***  Test %u  *** \n", testNb);
1570
1571         /* states full reset (deliberately not synchronized) */
1572         /* some issues can only happen when reusing states */
1573         if ((FUZ_rand(&lseed) & 0xFF) == 131) {
1574             DISPLAYLEVEL(5, "Creating new context \n");
1575             ZSTD_freeCCtx(zc);
1576             zc = ZSTD_createCCtx();
1577             CHECK(zc==NULL, "ZSTD_createCCtx allocation error");
1578             resetAllowed=0;
1579         }
1580         if ((FUZ_rand(&lseed) & 0xFF) == 132) {
1581             ZSTD_freeDStream(zd);
1582             zd = ZSTD_createDStream();
1583             CHECK(zd==NULL, "ZSTD_createDStream allocation error");
1584             ZSTD_initDStream_usingDict(zd, NULL, 0);  /* ensure at least one init */
1585         }
1586
1587         /* srcBuffer selection [0-4] */
1588         {   U32 buffNb = FUZ_rand(&lseed) & 0x7F;
1589             if (buffNb & 7) buffNb=2;   /* most common : compressible (P) */
1590             else {
1591                 buffNb >>= 3;
1592                 if (buffNb & 7) {
1593                     const U32 tnb[2] = { 1, 3 };   /* barely/highly compressible */
1594                     buffNb = tnb[buffNb >> 3];
1595                 } else {
1596                     const U32 tnb[2] = { 0, 4 };   /* not compressible / sparse */
1597                     buffNb = tnb[buffNb >> 3];
1598             }   }
1599             srcBuffer = cNoiseBuffer[buffNb];
1600         }
1601
1602         /* compression init */
1603         CHECK_Z( ZSTD_CCtx_loadDictionary(zc, NULL, 0) );   /* cancel previous dict /*/
1604         if ((FUZ_rand(&lseed)&1) /* at beginning, to keep same nb of rand */
1605             && oldTestLog /* at least one test happened */ && resetAllowed) {
1606             maxTestSize = FUZ_randomLength(&lseed, oldTestLog+2);
1607             if (maxTestSize >= srcBufferSize) maxTestSize = srcBufferSize-1;
1608             {   int const compressionLevel = (FUZ_rand(&lseed) % 5) + 1;
1609                 CHECK_Z (setCCtxParameter(zc, cctxParams, ZSTD_p_compressionLevel, compressionLevel, useOpaqueAPI) );
1610             }
1611         } else {
1612             U32 const testLog = FUZ_rand(&lseed) % maxSrcLog;
1613             U32 const dictLog = FUZ_rand(&lseed) % maxSrcLog;
1614             U32 const cLevelCandidate = (FUZ_rand(&lseed) %
1615                                (ZSTD_maxCLevel() -
1616                                (MAX(testLog, dictLog) / 2))) +
1617                                1;
1618             U32 const cLevel = MIN(cLevelCandidate, cLevelMax);
1619             DISPLAYLEVEL(5, "t%u: base cLevel : %u \n", testNb, cLevel);
1620             maxTestSize = FUZ_rLogLength(&lseed, testLog);
1621             DISPLAYLEVEL(5, "t%u: maxTestSize : %u \n", testNb, (U32)maxTestSize);
1622             oldTestLog = testLog;
1623             /* random dictionary selection */
1624             dictSize  = ((FUZ_rand(&lseed)&63)==1) ? FUZ_rLogLength(&lseed, dictLog) : 0;
1625             {   size_t const dictStart = FUZ_rand(&lseed) % (srcBufferSize - dictSize);
1626                 dict = srcBuffer + dictStart;
1627                 if (!dictSize) dict=NULL;
1628             }
1629             {   U64 const pledgedSrcSize = (FUZ_rand(&lseed) & 3) ? ZSTD_CONTENTSIZE_UNKNOWN : maxTestSize;
1630                 ZSTD_compressionParameters cParams = ZSTD_getCParams(cLevel, pledgedSrcSize, dictSize);
1631                 static const U32 windowLogMax = 24;
1632
1633                 /* mess with compression parameters */
1634                 cParams.windowLog += (FUZ_rand(&lseed) & 3) - 1;
1635                 cParams.windowLog = MIN(windowLogMax, cParams.windowLog);
1636                 cParams.hashLog += (FUZ_rand(&lseed) & 3) - 1;
1637                 cParams.chainLog += (FUZ_rand(&lseed) & 3) - 1;
1638                 cParams.searchLog += (FUZ_rand(&lseed) & 3) - 1;
1639                 cParams.searchLength += (FUZ_rand(&lseed) & 3) - 1;
1640                 cParams.targetLength = (U32)((cParams.targetLength + 1 ) * (0.5 + ((double)(FUZ_rand(&lseed) & 127) / 128)));
1641                 cParams = ZSTD_adjustCParams(cParams, 0, 0);
1642
1643                 if (FUZ_rand(&lseed) & 1) {
1644                     DISPLAYLEVEL(5, "t%u: windowLog : %u \n", testNb, cParams.windowLog);
1645                     CHECK_Z( setCCtxParameter(zc, cctxParams, ZSTD_p_windowLog, cParams.windowLog, useOpaqueAPI) );
1646                     assert(cParams.windowLog >= ZSTD_WINDOWLOG_MIN);   /* guaranteed by ZSTD_adjustCParams() */
1647                     windowLogMalus = (cParams.windowLog - ZSTD_WINDOWLOG_MIN) / 5;
1648                 }
1649                 if (FUZ_rand(&lseed) & 1) {
1650                     DISPLAYLEVEL(5, "t%u: hashLog : %u \n", testNb, cParams.hashLog);
1651                     CHECK_Z( setCCtxParameter(zc, cctxParams, ZSTD_p_hashLog, cParams.hashLog, useOpaqueAPI) );
1652                 }
1653                 if (FUZ_rand(&lseed) & 1) {
1654                     DISPLAYLEVEL(5, "t%u: chainLog : %u \n", testNb, cParams.chainLog);
1655                     CHECK_Z( setCCtxParameter(zc, cctxParams, ZSTD_p_chainLog, cParams.chainLog, useOpaqueAPI) );
1656                 }
1657                 if (FUZ_rand(&lseed) & 1) CHECK_Z( setCCtxParameter(zc, cctxParams, ZSTD_p_searchLog, cParams.searchLog, useOpaqueAPI) );
1658                 if (FUZ_rand(&lseed) & 1) CHECK_Z( setCCtxParameter(zc, cctxParams, ZSTD_p_minMatch, cParams.searchLength, useOpaqueAPI) );
1659                 if (FUZ_rand(&lseed) & 1) CHECK_Z( setCCtxParameter(zc, cctxParams, ZSTD_p_targetLength, cParams.targetLength, useOpaqueAPI) );
1660
1661                 /* mess with long distance matching parameters */
1662                 if (bigTests) {
1663                     if (FUZ_rand(&lseed) & 1) CHECK_Z( setCCtxParameter(zc, cctxParams, ZSTD_p_enableLongDistanceMatching, FUZ_rand(&lseed) & 63, useOpaqueAPI) );
1664                     if (FUZ_rand(&lseed) & 3) CHECK_Z( setCCtxParameter(zc, cctxParams, ZSTD_p_ldmHashLog, FUZ_randomClampedLength(&lseed, ZSTD_HASHLOG_MIN, 23), useOpaqueAPI) );
1665                     if (FUZ_rand(&lseed) & 3) CHECK_Z( setCCtxParameter(zc, cctxParams, ZSTD_p_ldmMinMatch, FUZ_randomClampedLength(&lseed, ZSTD_LDM_MINMATCH_MIN, ZSTD_LDM_MINMATCH_MAX), useOpaqueAPI) );
1666                     if (FUZ_rand(&lseed) & 3) CHECK_Z( setCCtxParameter(zc, cctxParams, ZSTD_p_ldmBucketSizeLog, FUZ_randomClampedLength(&lseed, 0, ZSTD_LDM_BUCKETSIZELOG_MAX), useOpaqueAPI) );
1667                     if (FUZ_rand(&lseed) & 3) CHECK_Z( setCCtxParameter(zc, cctxParams, ZSTD_p_ldmHashEveryLog, FUZ_randomClampedLength(&lseed, 0, ZSTD_WINDOWLOG_MAX - ZSTD_HASHLOG_MIN), useOpaqueAPI) );
1668                 }
1669
1670                 /* mess with frame parameters */
1671                 if (FUZ_rand(&lseed) & 1) {
1672                     U32 const checksumFlag = FUZ_rand(&lseed) & 1;
1673                     DISPLAYLEVEL(5, "t%u: frame checksum : %u \n", testNb, checksumFlag);
1674                     CHECK_Z( setCCtxParameter(zc, cctxParams, ZSTD_p_checksumFlag, checksumFlag, useOpaqueAPI) );
1675                 }
1676                 if (FUZ_rand(&lseed) & 1) CHECK_Z( setCCtxParameter(zc, cctxParams, ZSTD_p_dictIDFlag, FUZ_rand(&lseed) & 1, useOpaqueAPI) );
1677                 if (FUZ_rand(&lseed) & 1) CHECK_Z( setCCtxParameter(zc, cctxParams, ZSTD_p_contentSizeFlag, FUZ_rand(&lseed) & 1, useOpaqueAPI) );
1678                 if (FUZ_rand(&lseed) & 1) {
1679                     DISPLAYLEVEL(5, "t%u: pledgedSrcSize : %u \n", testNb, (U32)pledgedSrcSize);
1680                     CHECK_Z( ZSTD_CCtx_setPledgedSrcSize(zc, pledgedSrcSize) );
1681                 }
1682
1683                 /* multi-threading parameters */
1684                 {   U32 const nbThreadsCandidate = (FUZ_rand(&lseed) & 4) + 1;
1685                     U32 const nbThreadsAdjusted = (windowLogMalus < nbThreadsCandidate) ? nbThreadsCandidate - windowLogMalus : 1;
1686                     U32 const nbThreads = MIN(nbThreadsAdjusted, nbThreadsMax);
1687                     DISPLAYLEVEL(5, "t%u: nbThreads : %u \n", testNb, nbThreads);
1688                     CHECK_Z( setCCtxParameter(zc, cctxParams, ZSTD_p_nbWorkers, nbThreads, useOpaqueAPI) );
1689                     if (nbThreads > 1) {
1690                         U32 const jobLog = FUZ_rand(&lseed) % (testLog+1);
1691                         CHECK_Z( setCCtxParameter(zc, cctxParams, ZSTD_p_overlapSizeLog, FUZ_rand(&lseed) % 10, useOpaqueAPI) );
1692                         CHECK_Z( setCCtxParameter(zc, cctxParams, ZSTD_p_jobSize, (U32)FUZ_rLogLength(&lseed, jobLog), useOpaqueAPI) );
1693                     }
1694                 }
1695
1696                 if (FUZ_rand(&lseed) & 1) CHECK_Z( setCCtxParameter(zc, cctxParams, ZSTD_p_forceMaxWindow, FUZ_rand(&lseed) & 1, useOpaqueAPI) );
1697
1698                 /* Apply parameters */
1699                 if (useOpaqueAPI) {
1700                     DISPLAYLEVEL(6," t%u: applying CCtxParams \n", testNb);
1701                     CHECK_Z (ZSTD_CCtx_setParametersUsingCCtxParams(zc, cctxParams) );
1702                 }
1703
1704                 if (FUZ_rand(&lseed) & 1) {
1705                     if (FUZ_rand(&lseed) & 1) {
1706                         CHECK_Z( ZSTD_CCtx_loadDictionary(zc, dict, dictSize) );
1707                     } else {
1708                         CHECK_Z( ZSTD_CCtx_loadDictionary_byReference(zc, dict, dictSize) );
1709                     }
1710                     if (dict && dictSize) {
1711                         /* test that compression parameters are rejected (correctly) after loading a non-NULL dictionary */
1712                         if (useOpaqueAPI) {
1713                             size_t const setError = ZSTD_CCtx_setParametersUsingCCtxParams(zc, cctxParams);
1714                             CHECK(!ZSTD_isError(setError), "ZSTD_CCtx_setParametersUsingCCtxParams should have failed");
1715                         } else {
1716                             size_t const setError = ZSTD_CCtx_setParameter(zc, ZSTD_p_windowLog, cParams.windowLog-1);
1717                             CHECK(!ZSTD_isError(setError), "ZSTD_CCtx_setParameter should have failed");
1718                         }
1719                     }
1720                 } else {
1721                     CHECK_Z( ZSTD_CCtx_refPrefix(zc, dict, dictSize) );
1722                 }
1723         }   }
1724
1725         /* multi-segments compression test */
1726         XXH64_reset(&xxhState, 0);
1727         {   ZSTD_outBuffer outBuff = { cBuffer, cBufferSize, 0 } ;
1728             for (cSize=0, totalTestSize=0 ; (totalTestSize < maxTestSize) ; ) {
1729                 /* compress random chunks into randomly sized dst buffers */
1730                 size_t const randomSrcSize = FUZ_randomLength(&lseed, maxSampleLog);
1731                 size_t const srcSize = MIN(maxTestSize-totalTestSize, randomSrcSize);
1732                 size_t const srcStart = FUZ_rand(&lseed) % (srcBufferSize - srcSize);
1733                 size_t const randomDstSize = FUZ_randomLength(&lseed, maxSampleLog+1);
1734                 size_t const dstBuffSize = MIN(cBufferSize - cSize, randomDstSize);
1735                 ZSTD_EndDirective const flush = (FUZ_rand(&lseed) & 15) ? ZSTD_e_continue : ZSTD_e_flush;
1736                 ZSTD_inBuffer inBuff = { srcBuffer+srcStart, srcSize, 0 };
1737                 outBuff.size = outBuff.pos + dstBuffSize;
1738
1739                 CHECK_Z( ZSTD_compress_generic(zc, &outBuff, &inBuff, flush) );
1740                 DISPLAYLEVEL(6, "t%u: compress consumed %u bytes (total : %u) ; flush: %u (total : %u) \n",
1741                     testNb, (U32)inBuff.pos, (U32)(totalTestSize + inBuff.pos), (U32)flush, (U32)outBuff.pos);
1742
1743                 XXH64_update(&xxhState, srcBuffer+srcStart, inBuff.pos);
1744                 memcpy(copyBuffer+totalTestSize, srcBuffer+srcStart, inBuff.pos);
1745                 totalTestSize += inBuff.pos;
1746             }
1747
1748             /* final frame epilogue */
1749             {   size_t remainingToFlush = 1;
1750                 while (remainingToFlush) {
1751                     ZSTD_inBuffer inBuff = { NULL, 0, 0 };
1752                     size_t const randomDstSize = FUZ_randomLength(&lseed, maxSampleLog+1);
1753                     size_t const adjustedDstSize = MIN(cBufferSize - cSize, randomDstSize);
1754                     outBuff.size = outBuff.pos + adjustedDstSize;
1755                     DISPLAYLEVEL(6, "t%u: End-flush into dst buffer of size %u \n", testNb, (U32)adjustedDstSize);
1756                     remainingToFlush = ZSTD_compress_generic(zc, &outBuff, &inBuff, ZSTD_e_end);
1757                     DISPLAYLEVEL(6, "t%u: Total flushed so far : %u bytes \n", testNb, (U32)outBuff.pos);
1758                     CHECK( ZSTD_isError(remainingToFlush),
1759                           "ZSTD_compress_generic w/ ZSTD_e_end error : %s",
1760                            ZSTD_getErrorName(remainingToFlush) );
1761             }   }
1762             crcOrig = XXH64_digest(&xxhState);
1763             cSize = outBuff.pos;
1764             DISPLAYLEVEL(5, "Frame completed : %u bytes \n", (U32)cSize);
1765         }
1766
1767         /* multi - fragments decompression test */
1768         if (!dictSize /* don't reset if dictionary : could be different */ && (FUZ_rand(&lseed) & 1)) {
1769             DISPLAYLEVEL(5, "resetting DCtx (dict:%08X) \n", (U32)(size_t)dict);
1770             CHECK_Z( ZSTD_resetDStream(zd) );
1771         } else {
1772             DISPLAYLEVEL(5, "using dict of size %u \n", (U32)dictSize);
1773             CHECK_Z( ZSTD_initDStream_usingDict(zd, dict, dictSize) );
1774         }
1775         {   size_t decompressionResult = 1;
1776             ZSTD_inBuffer  inBuff = { cBuffer, cSize, 0 };
1777             ZSTD_outBuffer outBuff= { dstBuffer, dstBufferSize, 0 };
1778             for (totalGenSize = 0 ; decompressionResult ; ) {
1779                 size_t const readCSrcSize = FUZ_randomLength(&lseed, maxSampleLog);
1780                 size_t const randomDstSize = FUZ_randomLength(&lseed, maxSampleLog);
1781                 size_t const dstBuffSize = MIN(dstBufferSize - totalGenSize, randomDstSize);
1782                 inBuff.size = inBuff.pos + readCSrcSize;
1783                 outBuff.size = outBuff.pos + dstBuffSize;
1784                 DISPLAYLEVEL(6, "decompression presented %u new bytes (pos:%u/%u)\n",
1785                                 (U32)readCSrcSize, (U32)inBuff.pos, (U32)cSize);
1786                 decompressionResult = ZSTD_decompressStream(zd, &outBuff, &inBuff);
1787                 DISPLAYLEVEL(6, "so far: consumed = %u, produced = %u \n",
1788                                 (U32)inBuff.pos, (U32)outBuff.pos);
1789                 if (ZSTD_isError(decompressionResult)) {
1790                     DISPLAY("ZSTD_decompressStream error : %s \n", ZSTD_getErrorName(decompressionResult));
1791                     findDiff(copyBuffer, dstBuffer, totalTestSize);
1792                 }
1793                 CHECK (ZSTD_isError(decompressionResult), "decompression error : %s", ZSTD_getErrorName(decompressionResult));
1794                 CHECK (inBuff.pos > cSize, "ZSTD_decompressStream consumes too much input : %u > %u ", (U32)inBuff.pos, (U32)cSize);
1795             }
1796             CHECK (inBuff.pos != cSize, "compressed data should be fully read (%u != %u)", (U32)inBuff.pos, (U32)cSize);
1797             CHECK (outBuff.pos != totalTestSize, "decompressed data : wrong size (%u != %u)", (U32)outBuff.pos, (U32)totalTestSize);
1798             {   U64 const crcDest = XXH64(dstBuffer, totalTestSize, 0);
1799                 if (crcDest!=crcOrig) findDiff(copyBuffer, dstBuffer, totalTestSize);
1800                 CHECK (crcDest!=crcOrig, "decompressed data corrupted");
1801         }   }
1802
1803         /*=====   noisy/erroneous src decompression test   =====*/
1804
1805         /* add some noise */
1806         {   U32 const nbNoiseChunks = (FUZ_rand(&lseed) & 7) + 2;
1807             U32 nn; for (nn=0; nn<nbNoiseChunks; nn++) {
1808                 size_t const randomNoiseSize = FUZ_randomLength(&lseed, maxSampleLog);
1809                 size_t const noiseSize  = MIN((cSize/3) , randomNoiseSize);
1810                 size_t const noiseStart = FUZ_rand(&lseed) % (srcBufferSize - noiseSize);
1811                 size_t const cStart = FUZ_rand(&lseed) % (cSize - noiseSize);
1812                 memcpy(cBuffer+cStart, srcBuffer+noiseStart, noiseSize);
1813         }   }
1814
1815         /* try decompression on noisy data */
1816         CHECK_Z( ZSTD_initDStream(zd_noise) );   /* note : no dictionary */
1817         {   ZSTD_inBuffer  inBuff = { cBuffer, cSize, 0 };
1818             ZSTD_outBuffer outBuff= { dstBuffer, dstBufferSize, 0 };
1819             while (outBuff.pos < dstBufferSize) {
1820                 size_t const randomCSrcSize = FUZ_randomLength(&lseed, maxSampleLog);
1821                 size_t const randomDstSize = FUZ_randomLength(&lseed, maxSampleLog);
1822                 size_t const adjustedDstSize = MIN(dstBufferSize - outBuff.pos, randomDstSize);
1823                 size_t const adjustedCSrcSize = MIN(cSize - inBuff.pos, randomCSrcSize);
1824                 outBuff.size = outBuff.pos + adjustedDstSize;
1825                 inBuff.size  = inBuff.pos + adjustedCSrcSize;
1826                 {   size_t const decompressError = ZSTD_decompressStream(zd, &outBuff, &inBuff);
1827                     if (ZSTD_isError(decompressError)) break;   /* error correctly detected */
1828                     /* Good so far, but no more progress possible */
1829                     if (outBuff.pos < outBuff.size && inBuff.pos == cSize) break;
1830     }   }   }   }
1831     DISPLAY("\r%u fuzzer tests completed   \n", testNb-1);
1832
1833 _cleanup:
1834     ZSTD_freeCCtx(zc);
1835     ZSTD_freeDStream(zd);
1836     ZSTD_freeDStream(zd_noise);
1837     ZSTD_freeCCtxParams(cctxParams);
1838     free(cNoiseBuffer[0]);
1839     free(cNoiseBuffer[1]);
1840     free(cNoiseBuffer[2]);
1841     free(cNoiseBuffer[3]);
1842     free(cNoiseBuffer[4]);
1843     free(copyBuffer);
1844     free(cBuffer);
1845     free(dstBuffer);
1846     return result;
1847
1848 _output_error:
1849     result = 1;
1850     goto _cleanup;
1851 }
1852
1853 /*-*******************************************************
1854 *  Command line
1855 *********************************************************/
1856 int FUZ_usage(const char* programName)
1857 {
1858     DISPLAY( "Usage :\n");
1859     DISPLAY( "      %s [args]\n", programName);
1860     DISPLAY( "\n");
1861     DISPLAY( "Arguments :\n");
1862     DISPLAY( " -i#    : Nb of tests (default:%u) \n", nbTestsDefault);
1863     DISPLAY( " -s#    : Select seed (default:prompt user)\n");
1864     DISPLAY( " -t#    : Select starting test number (default:0)\n");
1865     DISPLAY( " -P#    : Select compressibility in %% (default:%i%%)\n", FUZ_COMPRESSIBILITY_DEFAULT);
1866     DISPLAY( " -v     : verbose\n");
1867     DISPLAY( " -p     : pause at the end\n");
1868     DISPLAY( " -h     : display help and exit\n");
1869     return 0;
1870 }
1871
1872 typedef enum { simple_api, mt_api, advanced_api } e_api;
1873
1874 int main(int argc, const char** argv)
1875 {
1876     U32 seed = 0;
1877     int seedset = 0;
1878     int nbTests = nbTestsDefault;
1879     int testNb = 0;
1880     int proba = FUZ_COMPRESSIBILITY_DEFAULT;
1881     int result = 0;
1882     int mainPause = 0;
1883     int bigTests = (sizeof(size_t) == 8);
1884     e_api selected_api = simple_api;
1885     const char* const programName = argv[0];
1886     U32 useOpaqueAPI = 0;
1887     int argNb;
1888
1889     /* Check command line */
1890     for(argNb=1; argNb<argc; argNb++) {
1891         const char* argument = argv[argNb];
1892         assert(argument != NULL);
1893
1894         /* Parsing commands. Aggregated commands are allowed */
1895         if (argument[0]=='-') {
1896
1897             if (!strcmp(argument, "--mt")) { selected_api=mt_api; testNb += !testNb; continue; }
1898             if (!strcmp(argument, "--newapi")) { selected_api=advanced_api; testNb += !testNb; continue; }
1899             if (!strcmp(argument, "--opaqueapi")) { selected_api=advanced_api; testNb += !testNb; useOpaqueAPI = 1; continue; }
1900             if (!strcmp(argument, "--no-big-tests")) { bigTests=0; continue; }
1901
1902             argument++;
1903             while (*argument!=0) {
1904                 switch(*argument)
1905                 {
1906                 case 'h':
1907                     return FUZ_usage(programName);
1908
1909                 case 'v':
1910                     argument++;
1911                     g_displayLevel++;
1912                     break;
1913
1914                 case 'q':
1915                     argument++;
1916                     g_displayLevel--;
1917                     break;
1918
1919                 case 'p': /* pause at the end */
1920                     argument++;
1921                     mainPause = 1;
1922                     break;
1923
1924                 case 'i':   /* limit tests by nb of iterations (default) */
1925                     argument++;
1926                     nbTests=0; g_clockTime=0;
1927                     while ((*argument>='0') && (*argument<='9')) {
1928                         nbTests *= 10;
1929                         nbTests += *argument - '0';
1930                         argument++;
1931                     }
1932                     break;
1933
1934                 case 'T':   /* limit tests by time */
1935                     argument++;
1936                     nbTests=0; g_clockTime=0;
1937                     while ((*argument>='0') && (*argument<='9')) {
1938                         g_clockTime *= 10;
1939                         g_clockTime += *argument - '0';
1940                         argument++;
1941                     }
1942                     if (*argument=='m') {    /* -T1m == -T60 */
1943                         g_clockTime *=60, argument++;
1944                         if (*argument=='n') argument++; /* -T1mn == -T60 */
1945                     } else if (*argument=='s') argument++; /* -T10s == -T10 */
1946                     g_clockTime *= SEC_TO_MICRO;
1947                     break;
1948
1949                 case 's':   /* manually select seed */
1950                     argument++;
1951                     seedset=1;
1952                     seed=0;
1953                     while ((*argument>='0') && (*argument<='9')) {
1954                         seed *= 10;
1955                         seed += *argument - '0';
1956                         argument++;
1957                     }
1958                     break;
1959
1960                 case 't':   /* select starting test number */
1961                     argument++;
1962                     testNb=0;
1963                     while ((*argument>='0') && (*argument<='9')) {
1964                         testNb *= 10;
1965                         testNb += *argument - '0';
1966                         argument++;
1967                     }
1968                     break;
1969
1970                 case 'P':   /* compressibility % */
1971                     argument++;
1972                     proba=0;
1973                     while ((*argument>='0') && (*argument<='9')) {
1974                         proba *= 10;
1975                         proba += *argument - '0';
1976                         argument++;
1977                     }
1978                     if (proba<0) proba=0;
1979                     if (proba>100) proba=100;
1980                     break;
1981
1982                 default:
1983                     return FUZ_usage(programName);
1984                 }
1985     }   }   }   /* for(argNb=1; argNb<argc; argNb++) */
1986
1987     /* Get Seed */
1988     DISPLAY("Starting zstream tester (%i-bits, %s)\n", (int)(sizeof(size_t)*8), ZSTD_VERSION_STRING);
1989
1990     if (!seedset) {
1991         time_t const t = time(NULL);
1992         U32 const h = XXH32(&t, sizeof(t), 1);
1993         seed = h % 10000;
1994     }
1995
1996     DISPLAY("Seed = %u\n", seed);
1997     if (proba!=FUZ_COMPRESSIBILITY_DEFAULT) DISPLAY("Compressibility : %i%%\n", proba);
1998
1999     if (nbTests<=0) nbTests=1;
2000
2001     if (testNb==0) {
2002         result = basicUnitTests(0, ((double)proba) / 100);  /* constant seed for predictability */
2003     }
2004
2005     if (!result) {
2006         switch(selected_api)
2007         {
2008         case simple_api :
2009             result = fuzzerTests(seed, nbTests, testNb, ((double)proba) / 100, bigTests);
2010             break;
2011         case mt_api :
2012             result = fuzzerTests_MT(seed, nbTests, testNb, ((double)proba) / 100, bigTests);
2013             break;
2014         case advanced_api :
2015             result = fuzzerTests_newAPI(seed, nbTests, testNb, ((double)proba) / 100, bigTests, useOpaqueAPI);
2016             break;
2017         default :
2018             assert(0);   /* impossible */
2019         }
2020     }
2021
2022     if (mainPause) {
2023         int unused;
2024         DISPLAY("Press Enter \n");
2025         unused = getchar();
2026         (void)unused;
2027     }
2028     return result;
2029 }