blob: d2c4036acec7826e004bf46fff88d1c2e9759187 [file] [log] [blame]
Yann Collet32fb4072017-08-18 16:52:05 -07001/*
Yann Collet4ded9e52016-08-30 10:04:33 -07002 * Copyright (c) 2016-present, Yann Collet, Facebook, Inc.
3 * All rights reserved.
4 *
Yann Collet32fb4072017-08-18 16:52:05 -07005 * 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).
Yann Collet3128e032017-09-08 00:09:23 -07008 * You may select, at your option, one of the above-listed licenses.
Yann Collet4ded9e52016-08-30 10:04:33 -07009 */
Yann Colletd7883a22016-08-12 16:48:02 +020010
Yann Colletd7883a22016-08-12 16:48:02 +020011
12/*-************************************
Yann Colletc9e8ee92018-06-18 19:20:37 -070013 * Compiler specific
14 **************************************/
Yann Colletd7883a22016-08-12 16:48:02 +020015#ifdef _MSC_VER /* Visual Studio */
Yann Colleta5ffe3d2017-05-12 16:29:19 -070016# 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 */
Yann Colletd7883a22016-08-12 16:48:02 +020019#endif
20
21
22/*-************************************
Yann Colletc9e8ee92018-06-18 19:20:37 -070023 * Includes
24 **************************************/
Yann Colletd7883a22016-08-12 16:48:02 +020025#include <stdlib.h> /* free */
26#include <stdio.h> /* fgets, sscanf */
Yann Colletd7883a22016-08-12 16:48:02 +020027#include <string.h> /* strcmp */
Yann Collet01743a32017-06-16 17:56:41 -070028#include <assert.h> /* assert */
Lzu Taofb6901b2019-04-12 21:28:17 +070029#include "timefn.h" /* UTIL_time_t, UTIL_getTime */
Yann Colletd7883a22016-08-12 16:48:02 +020030#include "mem.h"
Yann Colleta5ffe3d2017-05-12 16:29:19 -070031#define ZSTD_STATIC_LINKING_ONLY /* ZSTD_maxCLevel, ZSTD_customMem, ZSTD_getDictID_fromFrame */
Yann Colletd7883a22016-08-12 16:48:02 +020032#include "zstd.h" /* ZSTD_compressBound */
Yann Collete795c8a2016-12-13 16:39:36 +010033#include "zstd_errors.h" /* ZSTD_error_srcSize_wrong */
Yann Collet736788f2017-01-19 12:12:50 -080034#include "zstdmt_compress.h"
Yann Collet33fce032017-01-16 19:46:22 -080035#include "zdict.h" /* ZDICT_trainFromBuffer */
Yann Colletd7883a22016-08-12 16:48:02 +020036#include "datagen.h" /* RDG_genBuffer */
Yann Colletef9999f2016-09-01 16:44:48 -070037#define XXH_STATIC_LINKING_ONLY /* XXH64_state_t */
Yann Colletd7883a22016-08-12 16:48:02 +020038#include "xxhash.h" /* XXH64_* */
Nick Terrelle600b5d2017-10-16 17:18:43 -070039#include "seqgen.h"
Nick Terrell9a2f6f42017-11-29 19:11:12 -080040#include "util.h"
Yann Collet59a71162019-04-10 12:37:03 -070041#include "timefn.h" /* UTIL_time_t, UTIL_clockSpanMicro, UTIL_getTime */
Yann Colletd7883a22016-08-12 16:48:02 +020042
43
44/*-************************************
Yann Colletc9e8ee92018-06-18 19:20:37 -070045 * Constants
46 **************************************/
Yann Colletd7883a22016-08-12 16:48:02 +020047#define KB *(1U<<10)
48#define MB *(1U<<20)
49#define GB *(1U<<30)
50
Yann Colletededcfc2018-12-21 16:19:44 -080051static const int nbTestsDefault = 10000;
Yann Colletf99c2c12017-06-21 23:35:58 -070052static const U32 g_cLevelMax_smallTests = 10;
Yann Colletd7883a22016-08-12 16:48:02 +020053#define COMPRESSIBLE_NOISE_LENGTH (10 MB)
54#define FUZ_COMPRESSIBILITY_DEFAULT 50
Yann Collet33fce032017-01-16 19:46:22 -080055static const U32 prime32 = 2654435761U;
Yann Colletd7883a22016-08-12 16:48:02 +020056
57
Yann Colletd7883a22016-08-12 16:48:02 +020058/*-************************************
Yann Colletc9e8ee92018-06-18 19:20:37 -070059 * Display Macros
60 **************************************/
Yann Colletd7883a22016-08-12 16:48:02 +020061#define DISPLAY(...) fprintf(stderr, __VA_ARGS__)
Yann Collet0be6fd32017-05-08 16:08:01 -070062#define DISPLAYLEVEL(l, ...) if (g_displayLevel>=l) { \
63 DISPLAY(__VA_ARGS__); \
64 if (g_displayLevel>=4) fflush(stderr); }
Yann Colletd7883a22016-08-12 16:48:02 +020065static U32 g_displayLevel = 2;
66
Nick Terrell9a2f6f42017-11-29 19:11:12 -080067static const U64 g_refreshRate = SEC_TO_MICRO / 6;
68static UTIL_time_t g_displayClock = UTIL_TIME_INITIALIZER;
Yann Colletd7883a22016-08-12 16:48:02 +020069
Nick Terrell9a2f6f42017-11-29 19:11:12 -080070#define DISPLAYUPDATE(l, ...) if (g_displayLevel>=l) { \
71 if ((UTIL_clockSpanMicro(g_displayClock) > g_refreshRate) || (g_displayLevel>=4)) \
72 { g_displayClock = UTIL_getTime(); DISPLAY(__VA_ARGS__); \
73 if (g_displayLevel>=4) fflush(stderr); } }
74
75static U64 g_clockTime = 0;
Yann Colletd7883a22016-08-12 16:48:02 +020076
77
78/*-*******************************************************
Yann Colletc9e8ee92018-06-18 19:20:37 -070079 * Check macros
80 *********************************************************/
Nick Terrell9a2f6f42017-11-29 19:11:12 -080081#undef MIN
82#undef MAX
83#define MIN(a,b) ((a)<(b)?(a):(b))
Yann Colletd7883a22016-08-12 16:48:02 +020084#define MAX(a,b) ((a)>(b)?(a):(b))
Yann Colletd7883a22016-08-12 16:48:02 +020085/*! FUZ_rand() :
86 @return : a 27 bits random value, from a 32-bits `seed`.
87 `seed` is also modified */
Yann Collet95162342016-10-25 16:19:52 -070088#define FUZ_rotl32(x,r) ((x << r) | (x >> (32 - r)))
Yann Colletededcfc2018-12-21 16:19:44 -080089static U32 FUZ_rand(U32* seedPtr)
Yann Colletd7883a22016-08-12 16:48:02 +020090{
Yann Collet33fce032017-01-16 19:46:22 -080091 static const U32 prime2 = 2246822519U;
Yann Colletd7883a22016-08-12 16:48:02 +020092 U32 rand32 = *seedPtr;
Yann Collet33fce032017-01-16 19:46:22 -080093 rand32 *= prime32;
Yann Colletd7883a22016-08-12 16:48:02 +020094 rand32 += prime2;
95 rand32 = FUZ_rotl32(rand32, 13);
96 *seedPtr = rand32;
97 return rand32 >> 5;
98}
99
Nick Terrelle600b5d2017-10-16 17:18:43 -0700100#define CHECK(cond, ...) { \
101 if (cond) { \
102 DISPLAY("Error => "); \
103 DISPLAY(__VA_ARGS__); \
Yann Colletebd955e2018-01-23 13:12:40 -0800104 DISPLAY(" (seed %u, test nb %u, line %u) \n", \
Yann Colletededcfc2018-12-21 16:19:44 -0800105 (unsigned)seed, testNb, __LINE__); \
Yann Colletd6770f82017-09-28 02:14:48 -0700106 goto _output_error; \
107} }
108
Nick Terrelle600b5d2017-10-16 17:18:43 -0700109#define CHECK_Z(f) { \
110 size_t const err = f; \
111 CHECK(ZSTD_isError(err), "%s : %s ", \
112 #f, ZSTD_getErrorName(err)); \
113}
114
Nick Terrellca778222018-04-25 16:32:29 -0700115#define CHECK_RET(ret, cond, ...) { \
116 if (cond) { \
117 DISPLAY("Error %llu => ", (unsigned long long)ret); \
118 DISPLAY(__VA_ARGS__); \
119 DISPLAY(" (line %u)\n", __LINE__); \
120 return ret; \
121} }
122
123#define CHECK_RET_Z(f) { \
124 size_t const err = f; \
125 CHECK_RET(err, ZSTD_isError(err), "%s : %s ", \
126 #f, ZSTD_getErrorName(err)); \
127}
128
Yann Colletcb327632016-08-23 00:30:31 +0200129
130/*======================================================
Yann Colletc9e8ee92018-06-18 19:20:37 -0700131 * Basic Unit tests
132 *======================================================*/
Yann Colletcb327632016-08-23 00:30:31 +0200133
Yann Collet33fce032017-01-16 19:46:22 -0800134typedef struct {
135 void* start;
136 size_t size;
137 size_t filled;
138} buffer_t;
139
Yann Colletd195eec2018-09-13 12:29:52 -0700140static const buffer_t kBuffNull = { NULL, 0 , 0 };
141
142static void FUZ_freeDictionary(buffer_t dict)
143{
144 free(dict.start);
145}
Yann Collet33fce032017-01-16 19:46:22 -0800146
147static buffer_t FUZ_createDictionary(const void* src, size_t srcSize, size_t blockSize, size_t requestedDictSize)
148{
Yann Colletd195eec2018-09-13 12:29:52 -0700149 buffer_t dict = kBuffNull;
Yann Collet33fce032017-01-16 19:46:22 -0800150 size_t const nbBlocks = (srcSize + (blockSize-1)) / blockSize;
Yann Colletd195eec2018-09-13 12:29:52 -0700151 size_t* const blockSizes = (size_t*)malloc(nbBlocks * sizeof(size_t));
152 if (!blockSizes) return kBuffNull;
Yann Collet33fce032017-01-16 19:46:22 -0800153 dict.start = malloc(requestedDictSize);
Yann Colletd195eec2018-09-13 12:29:52 -0700154 if (!dict.start) { free(blockSizes); return kBuffNull; }
Yann Collet33fce032017-01-16 19:46:22 -0800155 { size_t nb;
156 for (nb=0; nb<nbBlocks-1; nb++) blockSizes[nb] = blockSize;
157 blockSizes[nbBlocks-1] = srcSize - (blockSize * (nbBlocks-1));
158 }
159 { size_t const dictSize = ZDICT_trainFromBuffer(dict.start, requestedDictSize, src, blockSizes, (unsigned)nbBlocks);
160 free(blockSizes);
Yann Colletd195eec2018-09-13 12:29:52 -0700161 if (ZDICT_isError(dictSize)) { FUZ_freeDictionary(dict); return kBuffNull; }
Yann Collet33fce032017-01-16 19:46:22 -0800162 dict.size = requestedDictSize;
163 dict.filled = dictSize;
Yann Colletd195eec2018-09-13 12:29:52 -0700164 return dict;
Yann Collet33fce032017-01-16 19:46:22 -0800165 }
166}
167
Nick Terrelle600b5d2017-10-16 17:18:43 -0700168/* Round trips data and updates xxh with the decompressed data produced */
169static size_t SEQ_roundTrip(ZSTD_CCtx* cctx, ZSTD_DCtx* dctx,
170 XXH64_state_t* xxh, void* data, size_t size,
171 ZSTD_EndDirective endOp)
172{
173 static BYTE compressed[1024];
174 static BYTE uncompressed[1024];
175
176 ZSTD_inBuffer cin = {data, size, 0};
177 size_t cret;
178
179 do {
Yann Colletd8e215c2018-11-30 11:16:26 -0800180 ZSTD_outBuffer cout = { compressed, sizeof(compressed), 0 };
181 ZSTD_inBuffer din = { compressed, 0, 0 };
182 ZSTD_outBuffer dout = { uncompressed, 0, 0 };
Nick Terrelle600b5d2017-10-16 17:18:43 -0700183
Yann Colletd8e215c2018-11-30 11:16:26 -0800184 cret = ZSTD_compressStream2(cctx, &cout, &cin, endOp);
Nick Terrelle600b5d2017-10-16 17:18:43 -0700185 if (ZSTD_isError(cret))
186 return cret;
187
188 din.size = cout.pos;
189 while (din.pos < din.size || (endOp == ZSTD_e_end && cret == 0)) {
190 size_t dret;
191
192 dout.pos = 0;
193 dout.size = sizeof(uncompressed);
194 dret = ZSTD_decompressStream(dctx, &dout, &din);
195 if (ZSTD_isError(dret))
196 return dret;
197 XXH64_update(xxh, dout.dst, dout.pos);
198 if (dret == 0)
199 break;
200 }
201 } while (cin.pos < cin.size || (endOp != ZSTD_e_continue && cret != 0));
202 return 0;
203}
204
205/* Generates some data and round trips it */
206static size_t SEQ_generateRoundTrip(ZSTD_CCtx* cctx, ZSTD_DCtx* dctx,
207 XXH64_state_t* xxh, SEQ_stream* seq,
208 SEQ_gen_type type, unsigned value)
209{
210 static BYTE data[1024];
211 size_t gen;
212
213 do {
214 SEQ_outBuffer sout = {data, sizeof(data), 0};
215 size_t ret;
216 gen = SEQ_gen(seq, type, value, &sout);
217
218 ret = SEQ_roundTrip(cctx, dctx, xxh, sout.dst, sout.pos, ZSTD_e_continue);
219 if (ZSTD_isError(ret))
220 return ret;
221 } while (gen != 0);
222
223 return 0;
224}
Yann Collet33fce032017-01-16 19:46:22 -0800225
Nick Terrellca778222018-04-25 16:32:29 -0700226static size_t getCCtxParams(ZSTD_CCtx* zc, ZSTD_parameters* savedParams)
227{
Yann Colletd4d4e102018-11-21 15:37:26 -0800228 int value;
Yann Collet3583d192018-12-05 17:26:02 -0800229 CHECK_RET_Z(ZSTD_CCtx_getParameter(zc, ZSTD_c_windowLog, (int*)&savedParams->cParams.windowLog));
230 CHECK_RET_Z(ZSTD_CCtx_getParameter(zc, ZSTD_c_hashLog, (int*)&savedParams->cParams.hashLog));
231 CHECK_RET_Z(ZSTD_CCtx_getParameter(zc, ZSTD_c_chainLog, (int*)&savedParams->cParams.chainLog));
232 CHECK_RET_Z(ZSTD_CCtx_getParameter(zc, ZSTD_c_searchLog, (int*)&savedParams->cParams.searchLog));
233 CHECK_RET_Z(ZSTD_CCtx_getParameter(zc, ZSTD_c_minMatch, (int*)&savedParams->cParams.minMatch));
234 CHECK_RET_Z(ZSTD_CCtx_getParameter(zc, ZSTD_c_targetLength, (int*)&savedParams->cParams.targetLength));
Yann Colletbe9e5612018-12-06 15:00:52 -0800235 CHECK_RET_Z(ZSTD_CCtx_getParameter(zc, ZSTD_c_strategy, &value));
Nick Terrellca778222018-04-25 16:32:29 -0700236 savedParams->cParams.strategy = value;
237
Yann Collet3583d192018-12-05 17:26:02 -0800238 CHECK_RET_Z(ZSTD_CCtx_getParameter(zc, ZSTD_c_checksumFlag, &savedParams->fParams.checksumFlag));
239 CHECK_RET_Z(ZSTD_CCtx_getParameter(zc, ZSTD_c_contentSizeFlag, &savedParams->fParams.contentSizeFlag));
240 CHECK_RET_Z(ZSTD_CCtx_getParameter(zc, ZSTD_c_dictIDFlag, &value));
Nick Terrellca778222018-04-25 16:32:29 -0700241 savedParams->fParams.noDictIDFlag = !value;
242 return 0;
243}
244
245static U32 badParameters(ZSTD_CCtx* zc, ZSTD_parameters const savedParams)
246{
247 ZSTD_parameters params;
248 if (ZSTD_isError(getCCtxParams(zc, &params))) return 10;
249 CHECK_RET(1, params.cParams.windowLog != savedParams.cParams.windowLog, "windowLog");
250 CHECK_RET(2, params.cParams.hashLog != savedParams.cParams.hashLog, "hashLog");
251 CHECK_RET(3, params.cParams.chainLog != savedParams.cParams.chainLog, "chainLog");
252 CHECK_RET(4, params.cParams.searchLog != savedParams.cParams.searchLog, "searchLog");
Yann Collete874dac2018-11-20 14:56:07 -0800253 CHECK_RET(5, params.cParams.minMatch != savedParams.cParams.minMatch, "minMatch");
Nick Terrellca778222018-04-25 16:32:29 -0700254 CHECK_RET(6, params.cParams.targetLength != savedParams.cParams.targetLength, "targetLength");
255
256 CHECK_RET(7, params.fParams.checksumFlag != savedParams.fParams.checksumFlag, "checksumFlag");
257 CHECK_RET(8, params.fParams.contentSizeFlag != savedParams.fParams.contentSizeFlag, "contentSizeFlag");
258 CHECK_RET(9, params.fParams.noDictIDFlag != savedParams.fParams.noDictIDFlag, "noDictIDFlag");
259 return 0;
260}
261
Yann Colletbd88f632017-11-27 12:15:23 -0800262static int basicUnitTests(U32 seed, double compressibility)
Yann Colletd7883a22016-08-12 16:48:02 +0200263{
Yann Colletb3060f72016-09-09 16:44:16 +0200264 size_t const CNBufferSize = COMPRESSIBLE_NOISE_LENGTH;
Yann Colletd7883a22016-08-12 16:48:02 +0200265 void* CNBuffer = malloc(CNBufferSize);
Nick Terrelle19b0822017-11-01 13:10:03 -0700266 size_t const skippableFrameSize = 200 KB;
Yann Colletd7883a22016-08-12 16:48:02 +0200267 size_t const compressedBufferSize = (8 + skippableFrameSize) + ZSTD_compressBound(COMPRESSIBLE_NOISE_LENGTH);
268 void* compressedBuffer = malloc(compressedBufferSize);
269 size_t const decodedBufferSize = CNBufferSize;
270 void* decodedBuffer = malloc(decodedBufferSize);
271 size_t cSize;
Yann Colletb3060f72016-09-09 16:44:16 +0200272 int testResult = 0;
Yann Colletededcfc2018-12-21 16:19:44 -0800273 int testNb = 1;
Yann Collet67113962018-01-19 22:11:11 -0800274 U32 coreSeed = 0; /* this name to conform with CHECK_Z macro display */
Yann Colletbd88f632017-11-27 12:15:23 -0800275 ZSTD_CStream* zc = ZSTD_createCStream();
276 ZSTD_DStream* zd = ZSTD_createDStream();
Stella Lau90a31bf2017-08-30 14:36:54 -0700277 ZSTDMT_CCtx* mtctx = ZSTDMT_createCCtx(2);
278
Yann Collet9ffbeea2016-12-02 18:37:38 -0800279 ZSTD_inBuffer inBuff, inBuff2;
Yann Collet53e17fb2016-08-17 01:39:22 +0200280 ZSTD_outBuffer outBuff;
Yann Colletd195eec2018-09-13 12:29:52 -0700281 buffer_t dictionary = kBuffNull;
Yann Collet30ab64e2017-05-10 11:30:19 -0700282 size_t const dictSize = 128 KB;
Yann Collet33fce032017-01-16 19:46:22 -0800283 unsigned dictID = 0;
Yann Colletd7883a22016-08-12 16:48:02 +0200284
285 /* Create compressible test buffer */
286 if (!CNBuffer || !compressedBuffer || !decodedBuffer || !zc || !zd) {
Yann Collet33fce032017-01-16 19:46:22 -0800287 DISPLAY("Not enough memory, aborting \n");
Yann Colletd7883a22016-08-12 16:48:02 +0200288 goto _output_error;
289 }
290 RDG_genBuffer(CNBuffer, CNBufferSize, compressibility, 0., seed);
291
Yann Collet33fce032017-01-16 19:46:22 -0800292 /* Create dictionary */
Yann Collete0065cf2017-09-28 18:34:38 -0700293 DISPLAYLEVEL(3, "creating dictionary for unit tests \n");
Yann Colletb18cb7e2018-03-20 16:18:48 -0700294 dictionary = FUZ_createDictionary(CNBuffer, CNBufferSize / 3, 16 KB, 48 KB);
Yann Collet33fce032017-01-16 19:46:22 -0800295 if (!dictionary.start) {
296 DISPLAY("Error creating dictionary, aborting \n");
297 goto _output_error;
298 }
299 dictID = ZDICT_getDictID(dictionary.start, dictionary.filled);
300
Yann Collet21f76722017-12-07 03:06:01 -0500301 /* Basic compression test */
302 DISPLAYLEVEL(3, "test%3i : compress %u bytes : ", testNb++, COMPRESSIBLE_NOISE_LENGTH);
303 CHECK_Z( ZSTD_initCStream(zc, 1 /* cLevel */) );
304 outBuff.dst = (char*)(compressedBuffer);
305 outBuff.size = compressedBufferSize;
306 outBuff.pos = 0;
307 inBuff.src = CNBuffer;
308 inBuff.size = CNBufferSize;
309 inBuff.pos = 0;
310 CHECK_Z( ZSTD_compressStream(zc, &outBuff, &inBuff) );
311 if (inBuff.pos != inBuff.size) goto _output_error; /* entire input should be consumed */
312 { size_t const r = ZSTD_endStream(zc, &outBuff);
313 if (r != 0) goto _output_error; } /* error, or some data not flushed */
Yann Colletededcfc2018-12-21 16:19:44 -0800314 DISPLAYLEVEL(3, "OK (%u bytes)\n", (unsigned)outBuff.pos);
Yann Collet21f76722017-12-07 03:06:01 -0500315
Yann Colletd7883a22016-08-12 16:48:02 +0200316 /* generate skippable frame */
317 MEM_writeLE32(compressedBuffer, ZSTD_MAGIC_SKIPPABLE_START);
318 MEM_writeLE32(((char*)compressedBuffer)+4, (U32)skippableFrameSize);
319 cSize = skippableFrameSize + 8;
320
Yann Collet21f76722017-12-07 03:06:01 -0500321 /* Basic compression test using dict */
322 DISPLAYLEVEL(3, "test%3i : skipframe + compress %u bytes : ", testNb++, COMPRESSIBLE_NOISE_LENGTH);
Yann Collet3c1e3f82017-10-13 18:32:06 -0700323 CHECK_Z( ZSTD_initCStream_usingDict(zc, CNBuffer, dictSize, 1 /* cLevel */) );
Yann Collet53e17fb2016-08-17 01:39:22 +0200324 outBuff.dst = (char*)(compressedBuffer)+cSize;
Yann Collet3c1e3f82017-10-13 18:32:06 -0700325 assert(compressedBufferSize > cSize);
326 outBuff.size = compressedBufferSize - cSize;
Yann Collet53e17fb2016-08-17 01:39:22 +0200327 outBuff.pos = 0;
328 inBuff.src = CNBuffer;
329 inBuff.size = CNBufferSize;
330 inBuff.pos = 0;
Yann Colletd6770f82017-09-28 02:14:48 -0700331 CHECK_Z( ZSTD_compressStream(zc, &outBuff, &inBuff) );
Yann Collet53e17fb2016-08-17 01:39:22 +0200332 if (inBuff.pos != inBuff.size) goto _output_error; /* entire input should be consumed */
333 { size_t const r = ZSTD_endStream(zc, &outBuff);
Yann Collet9a021c12016-08-26 09:05:06 +0200334 if (r != 0) goto _output_error; } /* error, or some data not flushed */
Yann Collet53e17fb2016-08-17 01:39:22 +0200335 cSize += outBuff.pos;
Yann Colletededcfc2018-12-21 16:19:44 -0800336 DISPLAYLEVEL(3, "OK (%u bytes : %.2f%%)\n",
337 (unsigned)cSize, (double)cSize/COMPRESSIBLE_NOISE_LENGTH*100);
Yann Colletd7883a22016-08-12 16:48:02 +0200338
Yann Collet30ab64e2017-05-10 11:30:19 -0700339 /* context size functions */
340 DISPLAYLEVEL(3, "test%3i : estimate CStream size : ", testNb++);
341 { ZSTD_compressionParameters const cParams = ZSTD_getCParams(1, CNBufferSize, dictSize);
Yann Collet96f0cde2017-09-24 16:47:02 -0700342 size_t const cstreamSize = ZSTD_estimateCStreamSize_usingCParams(cParams);
343 size_t const cdictSize = ZSTD_estimateCDictSize_advanced(dictSize, cParams, ZSTD_dlm_byCopy); /* uses ZSTD_initCStream_usingDict() */
344 if (ZSTD_isError(cstreamSize)) goto _output_error;
345 if (ZSTD_isError(cdictSize)) goto _output_error;
Yann Colletededcfc2018-12-21 16:19:44 -0800346 DISPLAYLEVEL(3, "OK (%u bytes) \n", (unsigned)(cstreamSize + cdictSize));
Yann Collet30ab64e2017-05-10 11:30:19 -0700347 }
348
Nick Terrell56682a72019-04-01 17:51:28 -0700349 /* context size functions */
350 DISPLAYLEVEL(3, "test%3i : estimate CStream size using CCtxParams : ", testNb++);
351 { ZSTD_CCtx_params* const params = ZSTD_createCCtxParams();
352 size_t cstreamSize, cctxSize;
353 CHECK_Z( ZSTD_CCtxParams_setParameter(params, ZSTD_c_compressionLevel, 19) );
354 cstreamSize = ZSTD_estimateCStreamSize_usingCCtxParams(params);
355 CHECK_Z(cstreamSize);
356 cctxSize = ZSTD_estimateCCtxSize_usingCCtxParams(params);
357 CHECK_Z(cctxSize);
358 if (cstreamSize <= cctxSize + 2 * ZSTD_BLOCKSIZE_MAX) goto _output_error;
359 ZSTD_freeCCtxParams(params);
360 DISPLAYLEVEL(3, "OK \n");
361 }
362
Yann Collet30ab64e2017-05-10 11:30:19 -0700363 DISPLAYLEVEL(3, "test%3i : check actual CStream size : ", testNb++);
Yann Colletdce78922017-06-21 15:53:42 -0700364 { size_t const s = ZSTD_sizeof_CStream(zc);
365 if (ZSTD_isError(s)) goto _output_error;
Yann Colletededcfc2018-12-21 16:19:44 -0800366 DISPLAYLEVEL(3, "OK (%u bytes) \n", (unsigned)s);
Yann Colletcb327632016-08-23 00:30:31 +0200367 }
368
Yann Collet4b987ad2017-04-10 17:50:44 -0700369 /* Attempt bad compression parameters */
370 DISPLAYLEVEL(3, "test%3i : use bad compression parameters : ", testNb++);
371 { size_t r;
372 ZSTD_parameters params = ZSTD_getParams(1, 0, 0);
Yann Collete874dac2018-11-20 14:56:07 -0800373 params.cParams.minMatch = 2;
Yann Collet4b987ad2017-04-10 17:50:44 -0700374 r = ZSTD_initCStream_advanced(zc, NULL, 0, params, 0);
375 if (!ZSTD_isError(r)) goto _output_error;
376 DISPLAYLEVEL(3, "init error : %s \n", ZSTD_getErrorName(r));
377 }
378
Yann Colletd7883a22016-08-12 16:48:02 +0200379 /* skippable frame test */
Yann Collet736788f2017-01-19 12:12:50 -0800380 DISPLAYLEVEL(3, "test%3i : decompress skippable frame : ", testNb++);
Yann Colletd6770f82017-09-28 02:14:48 -0700381 CHECK_Z( ZSTD_initDStream_usingDict(zd, CNBuffer, dictSize) );
Yann Collet53e17fb2016-08-17 01:39:22 +0200382 inBuff.src = compressedBuffer;
383 inBuff.size = cSize;
384 inBuff.pos = 0;
385 outBuff.dst = decodedBuffer;
386 outBuff.size = CNBufferSize;
387 outBuff.pos = 0;
Yann Colletdce78922017-06-21 15:53:42 -0700388 { size_t const r = ZSTD_decompressStream(zd, &outBuff, &inBuff);
Yann Colletededcfc2018-12-21 16:19:44 -0800389 DISPLAYLEVEL(5, " ( ZSTD_decompressStream => %u ) ", (unsigned)r);
Yann Colletdce78922017-06-21 15:53:42 -0700390 if (r != 0) goto _output_error;
391 }
Yann Colleta33ae642017-02-28 01:15:28 -0800392 if (outBuff.pos != 0) goto _output_error; /* skippable frame output len is 0 */
Yann Collet736788f2017-01-19 12:12:50 -0800393 DISPLAYLEVEL(3, "OK \n");
Yann Colletd7883a22016-08-12 16:48:02 +0200394
395 /* Basic decompression test */
Yann Collet9ffbeea2016-12-02 18:37:38 -0800396 inBuff2 = inBuff;
Yann Collet736788f2017-01-19 12:12:50 -0800397 DISPLAYLEVEL(3, "test%3i : decompress %u bytes : ", testNb++, COMPRESSIBLE_NOISE_LENGTH);
Yann Collet30ab64e2017-05-10 11:30:19 -0700398 ZSTD_initDStream_usingDict(zd, CNBuffer, dictSize);
Yann Collet3e042d52018-12-04 17:30:58 -0800399 CHECK_Z( ZSTD_DCtx_setParameter(zd, ZSTD_d_windowLogMax, ZSTD_WINDOWLOG_LIMIT_DEFAULT+1) ); /* large limit */
Yann Collet9ffbeea2016-12-02 18:37:38 -0800400 { size_t const remaining = ZSTD_decompressStream(zd, &outBuff, &inBuff);
401 if (remaining != 0) goto _output_error; } /* should reach end of frame == 0; otherwise, some data left, or an error */
402 if (outBuff.pos != CNBufferSize) goto _output_error; /* should regenerate the same amount */
403 if (inBuff.pos != inBuff.size) goto _output_error; /* should have read the entire frame */
Yann Collet736788f2017-01-19 12:12:50 -0800404 DISPLAYLEVEL(3, "OK \n");
Yann Collet9ffbeea2016-12-02 18:37:38 -0800405
406 /* Re-use without init */
Yann Collet736788f2017-01-19 12:12:50 -0800407 DISPLAYLEVEL(3, "test%3i : decompress again without init (re-use previous settings): ", testNb++);
Yann Collet9ffbeea2016-12-02 18:37:38 -0800408 outBuff.pos = 0;
409 { size_t const remaining = ZSTD_decompressStream(zd, &outBuff, &inBuff2);
410 if (remaining != 0) goto _output_error; } /* should reach end of frame == 0; otherwise, some data left, or an error */
Yann Collet53e17fb2016-08-17 01:39:22 +0200411 if (outBuff.pos != CNBufferSize) goto _output_error; /* should regenerate the same amount */
412 if (inBuff.pos != inBuff.size) goto _output_error; /* should have read the entire frame */
Yann Collet736788f2017-01-19 12:12:50 -0800413 DISPLAYLEVEL(3, "OK \n");
Yann Colletd7883a22016-08-12 16:48:02 +0200414
415 /* check regenerated data is byte exact */
Yann Collet736788f2017-01-19 12:12:50 -0800416 DISPLAYLEVEL(3, "test%3i : check decompressed result : ", testNb++);
Yann Colletd7883a22016-08-12 16:48:02 +0200417 { size_t i;
418 for (i=0; i<CNBufferSize; i++) {
419 if (((BYTE*)decodedBuffer)[i] != ((BYTE*)CNBuffer)[i]) goto _output_error;
420 } }
Yann Collet736788f2017-01-19 12:12:50 -0800421 DISPLAYLEVEL(3, "OK \n");
Yann Colletd7883a22016-08-12 16:48:02 +0200422
Yann Colletf16f4492017-05-09 16:18:17 -0700423 /* context size functions */
424 DISPLAYLEVEL(3, "test%3i : estimate DStream size : ", testNb++);
425 { ZSTD_frameHeader fhi;
426 const void* cStart = (char*)compressedBuffer + (skippableFrameSize + 8);
427 size_t const gfhError = ZSTD_getFrameHeader(&fhi, cStart, cSize);
428 if (gfhError!=0) goto _output_error;
Yann Colletededcfc2018-12-21 16:19:44 -0800429 DISPLAYLEVEL(5, " (windowSize : %u) ", (unsigned)fhi.windowSize);
Yann Colletdde10b22017-06-26 17:44:26 -0700430 { size_t const s = ZSTD_estimateDStreamSize(fhi.windowSize)
Yann Collet25989e32017-05-25 15:07:37 -0700431 /* uses ZSTD_initDStream_usingDict() */
Stella Lauc88fb922017-08-29 11:55:02 -0700432 + ZSTD_estimateDDictSize(dictSize, ZSTD_dlm_byCopy);
Yann Colletf16f4492017-05-09 16:18:17 -0700433 if (ZSTD_isError(s)) goto _output_error;
Yann Colletededcfc2018-12-21 16:19:44 -0800434 DISPLAYLEVEL(3, "OK (%u bytes) \n", (unsigned)s);
Yann Colletf16f4492017-05-09 16:18:17 -0700435 } }
436
437 DISPLAYLEVEL(3, "test%3i : check actual DStream size : ", testNb++);
Yann Collet70e3b312016-08-23 01:18:06 +0200438 { size_t const s = ZSTD_sizeof_DStream(zd);
Yann Colletcb327632016-08-23 00:30:31 +0200439 if (ZSTD_isError(s)) goto _output_error;
Yann Colletededcfc2018-12-21 16:19:44 -0800440 DISPLAYLEVEL(3, "OK (%u bytes) \n", (unsigned)s);
Yann Colletcb327632016-08-23 00:30:31 +0200441 }
442
Yann Collet67113962018-01-19 22:11:11 -0800443 /* Decompression by small increment */
Yann Collet736788f2017-01-19 12:12:50 -0800444 DISPLAYLEVEL(3, "test%3i : decompress byte-by-byte : ", testNb++);
Yann Collet3ecbe6a2016-09-14 17:26:59 +0200445 { /* skippable frame */
446 size_t r = 1;
Yann Collet30ab64e2017-05-10 11:30:19 -0700447 ZSTD_initDStream_usingDict(zd, CNBuffer, dictSize);
Yann Collet53e17fb2016-08-17 01:39:22 +0200448 inBuff.src = compressedBuffer;
449 outBuff.dst = decodedBuffer;
450 inBuff.pos = 0;
451 outBuff.pos = 0;
Yann Colletd7883a22016-08-12 16:48:02 +0200452 while (r) { /* skippable frame */
Yann Collet31769ce2018-06-22 17:58:21 -0700453 size_t const inSize = (FUZ_rand(&coreSeed) & 15) + 1;
454 size_t const outSize = (FUZ_rand(&coreSeed) & 15) + 1;
Yann Collet67113962018-01-19 22:11:11 -0800455 inBuff.size = inBuff.pos + inSize;
456 outBuff.size = outBuff.pos + outSize;
Yann Collet53e17fb2016-08-17 01:39:22 +0200457 r = ZSTD_decompressStream(zd, &outBuff, &inBuff);
Yann Collet31769ce2018-06-22 17:58:21 -0700458 if (ZSTD_isError(r)) DISPLAYLEVEL(4, "ZSTD_decompressStream on skippable frame error : %s \n", ZSTD_getErrorName(r));
Yann Colletd7883a22016-08-12 16:48:02 +0200459 if (ZSTD_isError(r)) goto _output_error;
460 }
Yann Collet3ecbe6a2016-09-14 17:26:59 +0200461 /* normal frame */
Yann Collet30ab64e2017-05-10 11:30:19 -0700462 ZSTD_initDStream_usingDict(zd, CNBuffer, dictSize);
Yann Colletd7883a22016-08-12 16:48:02 +0200463 r=1;
Yann Collet3ecbe6a2016-09-14 17:26:59 +0200464 while (r) {
Yann Collet67113962018-01-19 22:11:11 -0800465 size_t const inSize = FUZ_rand(&coreSeed) & 15;
Yann Collet31769ce2018-06-22 17:58:21 -0700466 size_t const outSize = (FUZ_rand(&coreSeed) & 15) + (!inSize); /* avoid having both sizes at 0 => would trigger a no_forward_progress error */
Yann Collet67113962018-01-19 22:11:11 -0800467 inBuff.size = inBuff.pos + inSize;
468 outBuff.size = outBuff.pos + outSize;
Yann Collet53e17fb2016-08-17 01:39:22 +0200469 r = ZSTD_decompressStream(zd, &outBuff, &inBuff);
Yann Collet31769ce2018-06-22 17:58:21 -0700470 if (ZSTD_isError(r)) DISPLAYLEVEL(4, "ZSTD_decompressStream error : %s \n", ZSTD_getErrorName(r));
Yann Colletd7883a22016-08-12 16:48:02 +0200471 if (ZSTD_isError(r)) goto _output_error;
472 }
473 }
Yann Collet31769ce2018-06-22 17:58:21 -0700474 if (outBuff.pos != CNBufferSize) DISPLAYLEVEL(4, "outBuff.pos != CNBufferSize : should have regenerated same amount ! \n");
Yann Collet53e17fb2016-08-17 01:39:22 +0200475 if (outBuff.pos != CNBufferSize) goto _output_error; /* should regenerate the same amount */
Yann Collet31769ce2018-06-22 17:58:21 -0700476 if (inBuff.pos != cSize) DISPLAYLEVEL(4, "inBuff.pos != cSize : should have real all input ! \n");
Yann Collet53e17fb2016-08-17 01:39:22 +0200477 if (inBuff.pos != cSize) goto _output_error; /* should have read the entire frame */
Yann Collet736788f2017-01-19 12:12:50 -0800478 DISPLAYLEVEL(3, "OK \n");
Yann Colletd7883a22016-08-12 16:48:02 +0200479
480 /* check regenerated data is byte exact */
Yann Collet736788f2017-01-19 12:12:50 -0800481 DISPLAYLEVEL(3, "test%3i : check decompressed result : ", testNb++);
Yann Colletd7883a22016-08-12 16:48:02 +0200482 { size_t i;
483 for (i=0; i<CNBufferSize; i++) {
484 if (((BYTE*)decodedBuffer)[i] != ((BYTE*)CNBuffer)[i]) goto _output_error;;
485 } }
Yann Collet736788f2017-01-19 12:12:50 -0800486 DISPLAYLEVEL(3, "OK \n");
Yann Colletd7883a22016-08-12 16:48:02 +0200487
Yann Collet31769ce2018-06-22 17:58:21 -0700488 /* Decompression forward progress */
489 DISPLAYLEVEL(3, "test%3i : generate error when ZSTD_decompressStream() doesn't progress : ", testNb++);
490 { /* skippable frame */
491 size_t r = 0;
492 int decNb = 0;
493 int const maxDec = 100;
494 inBuff.src = compressedBuffer;
495 inBuff.size = cSize;
496 inBuff.pos = 0;
497
498 outBuff.dst = decodedBuffer;
499 outBuff.pos = 0;
500 outBuff.size = CNBufferSize-1; /* 1 byte missing */
501
502 for (decNb=0; decNb<maxDec; decNb++) {
503 if (r==0) ZSTD_initDStream_usingDict(zd, CNBuffer, dictSize);
504 r = ZSTD_decompressStream(zd, &outBuff, &inBuff);
505 if (ZSTD_isError(r)) break;
506 }
507 if (!ZSTD_isError(r)) DISPLAYLEVEL(4, "ZSTD_decompressStream should have triggered a no_forward_progress error \n");
508 if (!ZSTD_isError(r)) goto _output_error; /* should have triggered no_forward_progress error */
509 }
510 DISPLAYLEVEL(3, "OK \n");
511
Yann Collete795c8a2016-12-13 16:39:36 +0100512 /* _srcSize compression test */
Yann Collet736788f2017-01-19 12:12:50 -0800513 DISPLAYLEVEL(3, "test%3i : compress_srcSize %u bytes : ", testNb++, COMPRESSIBLE_NOISE_LENGTH);
Nick Terrelle55da9e2019-03-13 14:05:18 -0700514 CHECK_Z( ZSTD_initCStream_srcSize(zc, 1, CNBufferSize) );
Yann Colletd564faa2016-12-18 21:39:15 +0100515 outBuff.dst = (char*)(compressedBuffer);
Yann Collete795c8a2016-12-13 16:39:36 +0100516 outBuff.size = compressedBufferSize;
517 outBuff.pos = 0;
518 inBuff.src = CNBuffer;
519 inBuff.size = CNBufferSize;
520 inBuff.pos = 0;
Yann Colletd6770f82017-09-28 02:14:48 -0700521 CHECK_Z( ZSTD_compressStream(zc, &outBuff, &inBuff) );
Nick Terrelle55da9e2019-03-13 14:05:18 -0700522 CHECK(inBuff.pos != inBuff.size, "Entire input should be consumed");
523 { size_t const r = ZSTD_endStream(zc, &outBuff);
524 CHECK(r != 0, "Error or some data not flushed (ret=%zu)", r);
525 }
526 { unsigned long long origSize = ZSTD_findDecompressedSize(outBuff.dst, outBuff.pos);
527 CHECK(origSize == ZSTD_CONTENTSIZE_UNKNOWN, "Unknown!");
528 CHECK((size_t)origSize != CNBufferSize, "Exact original size must be present (got %llu)", origSize);
529 }
Yann Colletededcfc2018-12-21 16:19:44 -0800530 DISPLAYLEVEL(3, "OK (%u bytes : %.2f%%)\n", (unsigned)cSize, (double)cSize/COMPRESSIBLE_NOISE_LENGTH*100);
Yann Collete795c8a2016-12-13 16:39:36 +0100531
532 /* wrong _srcSize compression test */
Nick Terrell48acadd2018-02-01 12:04:05 -0800533 DISPLAYLEVEL(3, "test%3i : too large srcSize : %u bytes : ", testNb++, COMPRESSIBLE_NOISE_LENGTH-1);
534 ZSTD_initCStream_srcSize(zc, 1, CNBufferSize+1);
Yann Colletd564faa2016-12-18 21:39:15 +0100535 outBuff.dst = (char*)(compressedBuffer);
Yann Collete795c8a2016-12-13 16:39:36 +0100536 outBuff.size = compressedBufferSize;
537 outBuff.pos = 0;
538 inBuff.src = CNBuffer;
539 inBuff.size = CNBufferSize;
540 inBuff.pos = 0;
Yann Colletd6770f82017-09-28 02:14:48 -0700541 CHECK_Z( ZSTD_compressStream(zc, &outBuff, &inBuff) );
Yann Collete795c8a2016-12-13 16:39:36 +0100542 if (inBuff.pos != inBuff.size) goto _output_error; /* entire input should be consumed */
543 { size_t const r = ZSTD_endStream(zc, &outBuff);
544 if (ZSTD_getErrorCode(r) != ZSTD_error_srcSize_wrong) goto _output_error; /* must fail : wrong srcSize */
Yann Collet736788f2017-01-19 12:12:50 -0800545 DISPLAYLEVEL(3, "OK (error detected : %s) \n", ZSTD_getErrorName(r)); }
Yann Collete795c8a2016-12-13 16:39:36 +0100546
Nick Terrell48acadd2018-02-01 12:04:05 -0800547 /* wrong _srcSize compression test */
548 DISPLAYLEVEL(3, "test%3i : too small srcSize : %u bytes : ", testNb++, COMPRESSIBLE_NOISE_LENGTH-1);
549 ZSTD_initCStream_srcSize(zc, 1, CNBufferSize-1);
550 outBuff.dst = (char*)(compressedBuffer);
551 outBuff.size = compressedBufferSize;
552 outBuff.pos = 0;
553 inBuff.src = CNBuffer;
554 inBuff.size = CNBufferSize;
555 inBuff.pos = 0;
556 { size_t const r = ZSTD_compressStream(zc, &outBuff, &inBuff);
557 if (ZSTD_getErrorCode(r) != ZSTD_error_srcSize_wrong) goto _output_error; /* must fail : wrong srcSize */
558 DISPLAYLEVEL(3, "OK (error detected : %s) \n", ZSTD_getErrorName(r));
559 }
560
Nick Terrell3c3f59e2018-04-12 16:02:03 -0700561 DISPLAYLEVEL(3, "test%3i : wrong srcSize !contentSizeFlag : %u bytes : ", testNb++, COMPRESSIBLE_NOISE_LENGTH-1);
562 { ZSTD_parameters params = ZSTD_getParams(1, CNBufferSize, 0);
563 params.fParams.contentSizeFlag = 0;
564 CHECK_Z(ZSTD_initCStream_advanced(zc, NULL, 0, params, CNBufferSize - MIN(CNBufferSize, 200 KB)));
565 outBuff.dst = (char*)compressedBuffer;
566 outBuff.size = compressedBufferSize;
567 outBuff.pos = 0;
568 inBuff.src = CNBuffer;
569 inBuff.size = CNBufferSize;
570 inBuff.pos = 0;
571 { size_t const r = ZSTD_compressStream(zc, &outBuff, &inBuff);
572 if (ZSTD_getErrorCode(r) != ZSTD_error_srcSize_wrong) goto _output_error; /* must fail : wrong srcSize */
573 DISPLAYLEVEL(3, "OK (error detected : %s) \n", ZSTD_getErrorName(r));
574 } }
575
Yann Collet12083a42016-09-06 15:01:51 +0200576 /* Complex context re-use scenario */
Yann Collet736788f2017-01-19 12:12:50 -0800577 DISPLAYLEVEL(3, "test%3i : context re-use : ", testNb++);
Yann Collet12083a42016-09-06 15:01:51 +0200578 ZSTD_freeCStream(zc);
Yann Colletbd88f632017-11-27 12:15:23 -0800579 zc = ZSTD_createCStream();
Yann Collet12083a42016-09-06 15:01:51 +0200580 if (zc==NULL) goto _output_error; /* memory allocation issue */
581 /* use 1 */
582 { size_t const inSize = 513;
Yann Collet0be6fd32017-05-08 16:08:01 -0700583 DISPLAYLEVEL(5, "use1 ");
Yann Collet12083a42016-09-06 15:01:51 +0200584 ZSTD_initCStream_advanced(zc, NULL, 0, ZSTD_getParams(19, inSize, 0), inSize); /* needs btopt + search3 to trigger hashLog3 */
585 inBuff.src = CNBuffer;
586 inBuff.size = inSize;
587 inBuff.pos = 0;
588 outBuff.dst = (char*)(compressedBuffer)+cSize;
589 outBuff.size = ZSTD_compressBound(inSize);
590 outBuff.pos = 0;
Yann Collet0be6fd32017-05-08 16:08:01 -0700591 DISPLAYLEVEL(5, "compress1 ");
Yann Colletd6770f82017-09-28 02:14:48 -0700592 CHECK_Z( ZSTD_compressStream(zc, &outBuff, &inBuff) );
Yann Collet12083a42016-09-06 15:01:51 +0200593 if (inBuff.pos != inBuff.size) goto _output_error; /* entire input should be consumed */
Yann Collet0be6fd32017-05-08 16:08:01 -0700594 DISPLAYLEVEL(5, "end1 ");
Yann Collet12083a42016-09-06 15:01:51 +0200595 { size_t const r = ZSTD_endStream(zc, &outBuff);
596 if (r != 0) goto _output_error; } /* error, or some data not flushed */
597 }
598 /* use 2 */
599 { size_t const inSize = 1025; /* will not continue, because tables auto-adjust and are therefore different size */
Yann Collet0be6fd32017-05-08 16:08:01 -0700600 DISPLAYLEVEL(5, "use2 ");
Yann Collet12083a42016-09-06 15:01:51 +0200601 ZSTD_initCStream_advanced(zc, NULL, 0, ZSTD_getParams(19, inSize, 0), inSize); /* needs btopt + search3 to trigger hashLog3 */
602 inBuff.src = CNBuffer;
603 inBuff.size = inSize;
604 inBuff.pos = 0;
605 outBuff.dst = (char*)(compressedBuffer)+cSize;
606 outBuff.size = ZSTD_compressBound(inSize);
607 outBuff.pos = 0;
Yann Collet0be6fd32017-05-08 16:08:01 -0700608 DISPLAYLEVEL(5, "compress2 ");
Yann Colletd6770f82017-09-28 02:14:48 -0700609 CHECK_Z( ZSTD_compressStream(zc, &outBuff, &inBuff) );
Yann Collet12083a42016-09-06 15:01:51 +0200610 if (inBuff.pos != inBuff.size) goto _output_error; /* entire input should be consumed */
Yann Collet0be6fd32017-05-08 16:08:01 -0700611 DISPLAYLEVEL(5, "end2 ");
Yann Collet12083a42016-09-06 15:01:51 +0200612 { size_t const r = ZSTD_endStream(zc, &outBuff);
613 if (r != 0) goto _output_error; } /* error, or some data not flushed */
614 }
Yann Collet736788f2017-01-19 12:12:50 -0800615 DISPLAYLEVEL(3, "OK \n");
Yann Collet12083a42016-09-06 15:01:51 +0200616
Yann Collet95162342016-10-25 16:19:52 -0700617 /* CDict scenario */
Yann Collet736788f2017-01-19 12:12:50 -0800618 DISPLAYLEVEL(3, "test%3i : digested dictionary : ", testNb++);
Yann Collet2e427422017-06-27 17:09:12 -0700619 { ZSTD_CDict* const cdict = ZSTD_createCDict(dictionary.start, dictionary.filled, 1 /*byRef*/ );
Yann Collet95162342016-10-25 16:19:52 -0700620 size_t const initError = ZSTD_initCStream_usingCDict(zc, cdict);
Yann Colletededcfc2018-12-21 16:19:44 -0800621 DISPLAYLEVEL(5, "ZSTD_initCStream_usingCDict result : %u ", (unsigned)initError);
Yann Collet95162342016-10-25 16:19:52 -0700622 if (ZSTD_isError(initError)) goto _output_error;
Yann Collet95162342016-10-25 16:19:52 -0700623 outBuff.dst = compressedBuffer;
624 outBuff.size = compressedBufferSize;
625 outBuff.pos = 0;
626 inBuff.src = CNBuffer;
627 inBuff.size = CNBufferSize;
628 inBuff.pos = 0;
Yann Collet15768ca2017-11-16 15:02:28 -0800629 DISPLAYLEVEL(5, "- starting ZSTD_compressStream ");
Yann Colletd6770f82017-09-28 02:14:48 -0700630 CHECK_Z( ZSTD_compressStream(zc, &outBuff, &inBuff) );
Yann Collet95162342016-10-25 16:19:52 -0700631 if (inBuff.pos != inBuff.size) goto _output_error; /* entire input should be consumed */
Yann Collet15768ca2017-11-16 15:02:28 -0800632 { size_t const r = ZSTD_endStream(zc, &outBuff);
Yann Colletededcfc2018-12-21 16:19:44 -0800633 DISPLAYLEVEL(5, "- ZSTD_endStream result : %u ", (unsigned)r);
Yann Collet15768ca2017-11-16 15:02:28 -0800634 if (r != 0) goto _output_error; /* error, or some data not flushed */
635 }
Yann Collet95162342016-10-25 16:19:52 -0700636 cSize = outBuff.pos;
637 ZSTD_freeCDict(cdict);
Yann Colletededcfc2018-12-21 16:19:44 -0800638 DISPLAYLEVEL(3, "OK (%u bytes : %.2f%%)\n", (unsigned)cSize, (double)cSize/CNBufferSize*100);
Yann Collet95162342016-10-25 16:19:52 -0700639 }
640
Yann Collet736788f2017-01-19 12:12:50 -0800641 DISPLAYLEVEL(3, "test%3i : check CStream size : ", testNb++);
Yann Collet12083a42016-09-06 15:01:51 +0200642 { size_t const s = ZSTD_sizeof_CStream(zc);
643 if (ZSTD_isError(s)) goto _output_error;
Yann Colletededcfc2018-12-21 16:19:44 -0800644 DISPLAYLEVEL(3, "OK (%u bytes) \n", (unsigned)s);
Yann Collet12083a42016-09-06 15:01:51 +0200645 }
646
Yann Collet33fce032017-01-16 19:46:22 -0800647 DISPLAYLEVEL(4, "test%3i : check Dictionary ID : ", testNb++);
648 { unsigned const dID = ZSTD_getDictID_fromFrame(compressedBuffer, cSize);
649 if (dID != dictID) goto _output_error;
650 DISPLAYLEVEL(4, "OK (%u) \n", dID);
651 }
652
Yann Collet335ad5d2016-10-25 17:47:02 -0700653 /* DDict scenario */
Yann Colletededcfc2018-12-21 16:19:44 -0800654 DISPLAYLEVEL(3, "test%3i : decompress %u bytes with digested dictionary : ", testNb++, (unsigned)CNBufferSize);
Yann Collet33fce032017-01-16 19:46:22 -0800655 { ZSTD_DDict* const ddict = ZSTD_createDDict(dictionary.start, dictionary.filled);
Yann Collet335ad5d2016-10-25 17:47:02 -0700656 size_t const initError = ZSTD_initDStream_usingDDict(zd, ddict);
657 if (ZSTD_isError(initError)) goto _output_error;
Yann Collet8a104fd2017-12-12 12:51:49 -0800658 outBuff.dst = decodedBuffer;
659 outBuff.size = CNBufferSize;
660 outBuff.pos = 0;
Yann Collet03832b72017-12-12 14:01:54 -0800661 inBuff.src = compressedBuffer;
662 inBuff.size = cSize;
663 inBuff.pos = 0;
Yann Collet335ad5d2016-10-25 17:47:02 -0700664 { size_t const r = ZSTD_decompressStream(zd, &outBuff, &inBuff);
665 if (r != 0) goto _output_error; } /* should reach end of frame == 0; otherwise, some data left, or an error */
666 if (outBuff.pos != CNBufferSize) goto _output_error; /* should regenerate the same amount */
667 if (inBuff.pos != inBuff.size) goto _output_error; /* should have read the entire frame */
668 ZSTD_freeDDict(ddict);
Yann Collet736788f2017-01-19 12:12:50 -0800669 DISPLAYLEVEL(3, "OK \n");
Yann Collet335ad5d2016-10-25 17:47:02 -0700670 }
671
Yann Collet17e482e2016-08-23 16:58:10 +0200672 /* Memory restriction */
Yann Collet736788f2017-01-19 12:12:50 -0800673 DISPLAYLEVEL(3, "test%3i : maxWindowSize < frame requirement : ", testNb++);
Yann Collet30ab64e2017-05-10 11:30:19 -0700674 ZSTD_initDStream_usingDict(zd, CNBuffer, dictSize);
Yann Collet3e042d52018-12-04 17:30:58 -0800675 CHECK_Z( ZSTD_DCtx_setParameter(zd, ZSTD_d_windowLogMax, 10) ); /* too small limit */
Yann Collet8a104fd2017-12-12 12:51:49 -0800676 outBuff.dst = decodedBuffer;
677 outBuff.size = CNBufferSize;
678 outBuff.pos = 0;
Yann Collet03832b72017-12-12 14:01:54 -0800679 inBuff.src = compressedBuffer;
680 inBuff.size = cSize;
681 inBuff.pos = 0;
Yann Collet17e482e2016-08-23 16:58:10 +0200682 { size_t const r = ZSTD_decompressStream(zd, &outBuff, &inBuff);
683 if (!ZSTD_isError(r)) goto _output_error; /* must fail : frame requires > 100 bytes */
Yann Collet736788f2017-01-19 12:12:50 -0800684 DISPLAYLEVEL(3, "OK (%s)\n", ZSTD_getErrorName(r)); }
Yann Collet5c686392018-11-15 16:12:39 -0800685 ZSTD_DCtx_reset(zd, ZSTD_reset_session_and_parameters); /* leave zd in good shape for next tests */
Yann Collet17e482e2016-08-23 16:58:10 +0200686
Nick Terrellab3346a2018-01-30 13:30:30 -0800687 DISPLAYLEVEL(3, "test%3i : dictionary source size and level : ", testNb++);
688 { ZSTD_DCtx* const dctx = ZSTD_createDCtx();
Yann Collet6cda8c92018-03-20 16:16:13 -0700689 int const maxLevel = 16; /* first level with zstd_opt */
Nick Terrellab3346a2018-01-30 13:30:30 -0800690 int level;
Yann Collet2af41592018-03-20 15:59:25 -0700691 assert(maxLevel < ZSTD_maxCLevel());
692 CHECK_Z( ZSTD_DCtx_loadDictionary_byReference(dctx, dictionary.start, dictionary.filled) );
Nick Terrellab3346a2018-01-30 13:30:30 -0800693 for (level = 1; level <= maxLevel; ++level) {
694 ZSTD_CDict* const cdict = ZSTD_createCDict(dictionary.start, dictionary.filled, level);
Yann Collet2af41592018-03-20 15:59:25 -0700695 size_t const maxSize = MIN(1 MB, CNBufferSize);
696 size_t size;
Nick Terrellab3346a2018-01-30 13:30:30 -0800697 for (size = 512; size <= maxSize; size <<= 1) {
Yann Collet2af41592018-03-20 15:59:25 -0700698 U64 const crcOrig = XXH64(CNBuffer, size, 0);
Nick Terrellab3346a2018-01-30 13:30:30 -0800699 ZSTD_CCtx* const cctx = ZSTD_createCCtx();
Nick Terrellca778222018-04-25 16:32:29 -0700700 ZSTD_parameters savedParams;
701 getCCtxParams(cctx, &savedParams);
Nick Terrellab3346a2018-01-30 13:30:30 -0800702 outBuff.dst = compressedBuffer;
703 outBuff.size = compressedBufferSize;
704 outBuff.pos = 0;
705 inBuff.src = CNBuffer;
706 inBuff.size = size;
707 inBuff.pos = 0;
708 CHECK_Z(ZSTD_CCtx_refCDict(cctx, cdict));
Yann Colletd8e215c2018-11-30 11:16:26 -0800709 CHECK_Z(ZSTD_compressStream2(cctx, &outBuff, &inBuff, ZSTD_e_end));
Nick Terrellca778222018-04-25 16:32:29 -0700710 CHECK(badParameters(cctx, savedParams), "Bad CCtx params");
Nick Terrellab3346a2018-01-30 13:30:30 -0800711 if (inBuff.pos != inBuff.size) goto _output_error;
Yann Collet2af41592018-03-20 15:59:25 -0700712 { ZSTD_outBuffer decOut = {decodedBuffer, size, 0};
713 ZSTD_inBuffer decIn = {outBuff.dst, outBuff.pos, 0};
Yann Collet34e146f2018-12-04 10:28:36 -0800714 CHECK_Z( ZSTD_decompressStream(dctx, &decOut, &decIn) );
Yann Collet2af41592018-03-20 15:59:25 -0700715 if (decIn.pos != decIn.size) goto _output_error;
716 if (decOut.pos != size) goto _output_error;
717 { U64 const crcDec = XXH64(decOut.dst, decOut.pos, 0);
718 if (crcDec != crcOrig) goto _output_error;
719 } }
Nick Terrellab3346a2018-01-30 13:30:30 -0800720 ZSTD_freeCCtx(cctx);
721 }
722 ZSTD_freeCDict(cdict);
723 }
Nick Terrellab3346a2018-01-30 13:30:30 -0800724 ZSTD_freeDCtx(dctx);
725 }
726 DISPLAYLEVEL(3, "OK\n");
727
Nick Terrell50b9c412019-04-10 12:34:21 -0700728 ZSTD_CCtx_reset(zc, ZSTD_reset_session_and_parameters);
729 CHECK_Z( ZSTD_CCtx_loadDictionary(zc, dictionary.start, dictionary.filled) );
730 cSize = ZSTD_compress2(zc, compressedBuffer, compressedBufferSize, CNBuffer, MIN(CNBufferSize, 100 KB));
731 CHECK_Z(cSize);
732 DISPLAYLEVEL(3, "test%3i : ZSTD_decompressStream() with dictionary : ", testNb++);
733 {
734 ZSTD_DCtx* dctx = ZSTD_createDCtx();
735 /* We should fail to decompress without a dictionary. */
736 ZSTD_DCtx_reset(dctx, ZSTD_reset_session_and_parameters);
737 { ZSTD_outBuffer out = {decodedBuffer, decodedBufferSize, 0};
738 ZSTD_inBuffer in = {compressedBuffer, cSize, 0};
739 size_t const ret = ZSTD_decompressStream(dctx, &out, &in);
740 if (!ZSTD_isError(ret)) goto _output_error;
741 }
742 /* We should succeed to decompress with the dictionary. */
743 ZSTD_DCtx_reset(dctx, ZSTD_reset_session_and_parameters);
744 CHECK_Z( ZSTD_DCtx_loadDictionary(dctx, dictionary.start, dictionary.filled) );
745 { ZSTD_outBuffer out = {decodedBuffer, decodedBufferSize, 0};
746 ZSTD_inBuffer in = {compressedBuffer, cSize, 0};
747 if (ZSTD_decompressStream(dctx, &out, &in) != 0) goto _output_error;
748 if (in.pos != in.size) goto _output_error;
749 }
750 /* The dictionary should presist across calls. */
751 { ZSTD_outBuffer out = {decodedBuffer, decodedBufferSize, 0};
752 ZSTD_inBuffer in = {compressedBuffer, cSize, 0};
753 if (ZSTD_decompressStream(dctx, &out, &in) != 0) goto _output_error;
754 if (in.pos != in.size) goto _output_error;
755 }
756 /* The dictionary should not be cleared by ZSTD_reset_session_only. */
757 ZSTD_DCtx_reset(dctx, ZSTD_reset_session_only);
758 { ZSTD_outBuffer out = {decodedBuffer, decodedBufferSize, 0};
759 ZSTD_inBuffer in = {compressedBuffer, cSize, 0};
760 if (ZSTD_decompressStream(dctx, &out, &in) != 0) goto _output_error;
761 if (in.pos != in.size) goto _output_error;
762 }
763 /* When we reset the context the dictionary is cleared. */
764 ZSTD_DCtx_reset(dctx, ZSTD_reset_session_and_parameters);
765 { ZSTD_outBuffer out = {decodedBuffer, decodedBufferSize, 0};
766 ZSTD_inBuffer in = {compressedBuffer, cSize, 0};
767 size_t const ret = ZSTD_decompressStream(dctx, &out, &in);
768 if (!ZSTD_isError(ret)) goto _output_error;
769 }
770 ZSTD_freeDCtx(dctx);
771 }
772 DISPLAYLEVEL(3, "OK \n");
773
Josh Sorefa880ca22019-04-12 14:18:11 -0400774 DISPLAYLEVEL(3, "test%3i : ZSTD_resetDStream() with dictionary : ", testNb++);
Nick Terrell50b9c412019-04-10 12:34:21 -0700775 {
776 ZSTD_DCtx* dctx = ZSTD_createDCtx();
777 /* We should succeed to decompress with the dictionary. */
778 ZSTD_resetDStream(dctx);
779 CHECK_Z( ZSTD_DCtx_loadDictionary(dctx, dictionary.start, dictionary.filled) );
780 { ZSTD_outBuffer out = {decodedBuffer, decodedBufferSize, 0};
781 ZSTD_inBuffer in = {compressedBuffer, cSize, 0};
782 if (ZSTD_decompressStream(dctx, &out, &in) != 0) goto _output_error;
783 if (in.pos != in.size) goto _output_error;
784 }
785 /* The dictionary should not be cleared by ZSTD_resetDStream(). */
786 ZSTD_resetDStream(dctx);
787 { ZSTD_outBuffer out = {decodedBuffer, decodedBufferSize, 0};
788 ZSTD_inBuffer in = {compressedBuffer, cSize, 0};
789 if (ZSTD_decompressStream(dctx, &out, &in) != 0) goto _output_error;
790 if (in.pos != in.size) goto _output_error;
791 }
792 /* The dictionary should be cleared by ZSTD_initDStream(). */
793 CHECK_Z( ZSTD_initDStream(dctx) );
794 { ZSTD_outBuffer out = {decodedBuffer, decodedBufferSize, 0};
795 ZSTD_inBuffer in = {compressedBuffer, cSize, 0};
796 size_t const ret = ZSTD_decompressStream(dctx, &out, &in);
797 if (!ZSTD_isError(ret)) goto _output_error;
798 }
799 ZSTD_freeDCtx(dctx);
800 }
801 DISPLAYLEVEL(3, "OK \n");
802
803 DISPLAYLEVEL(3, "test%3i : ZSTD_decompressStream() with ddict : ", testNb++);
804 {
805 ZSTD_DCtx* dctx = ZSTD_createDCtx();
806 ZSTD_DDict* ddict = ZSTD_createDDict(dictionary.start, dictionary.filled);
807 /* We should succeed to decompress with the ddict. */
808 ZSTD_DCtx_reset(dctx, ZSTD_reset_session_and_parameters);
809 CHECK_Z( ZSTD_DCtx_refDDict(dctx, ddict) );
810 { ZSTD_outBuffer out = {decodedBuffer, decodedBufferSize, 0};
811 ZSTD_inBuffer in = {compressedBuffer, cSize, 0};
812 if (ZSTD_decompressStream(dctx, &out, &in) != 0) goto _output_error;
813 if (in.pos != in.size) goto _output_error;
814 }
815 /* The ddict should presist across calls. */
816 { ZSTD_outBuffer out = {decodedBuffer, decodedBufferSize, 0};
817 ZSTD_inBuffer in = {compressedBuffer, cSize, 0};
818 if (ZSTD_decompressStream(dctx, &out, &in) != 0) goto _output_error;
819 if (in.pos != in.size) goto _output_error;
820 }
821 /* When we reset the context the ddict is cleared. */
822 ZSTD_DCtx_reset(dctx, ZSTD_reset_session_and_parameters);
823 { ZSTD_outBuffer out = {decodedBuffer, decodedBufferSize, 0};
824 ZSTD_inBuffer in = {compressedBuffer, cSize, 0};
825 size_t const ret = ZSTD_decompressStream(dctx, &out, &in);
826 if (!ZSTD_isError(ret)) goto _output_error;
827 }
828 ZSTD_freeDCtx(dctx);
829 ZSTD_freeDDict(ddict);
830 }
831 DISPLAYLEVEL(3, "OK \n");
832
833 DISPLAYLEVEL(3, "test%3i : ZSTD_decompressDCtx() with prefix : ", testNb++);
834 {
835 ZSTD_DCtx* dctx = ZSTD_createDCtx();
836 /* We should succeed to decompress with the prefix. */
837 ZSTD_DCtx_reset(dctx, ZSTD_reset_session_and_parameters);
838 CHECK_Z( ZSTD_DCtx_refPrefix_advanced(dctx, dictionary.start, dictionary.filled, ZSTD_dct_auto) );
839 { ZSTD_outBuffer out = {decodedBuffer, decodedBufferSize, 0};
840 ZSTD_inBuffer in = {compressedBuffer, cSize, 0};
841 if (ZSTD_decompressStream(dctx, &out, &in) != 0) goto _output_error;
842 if (in.pos != in.size) goto _output_error;
843 }
844 /* The prefix should be cleared after the first compression. */
845 { ZSTD_outBuffer out = {decodedBuffer, decodedBufferSize, 0};
846 ZSTD_inBuffer in = {compressedBuffer, cSize, 0};
847 size_t const ret = ZSTD_decompressStream(dctx, &out, &in);
848 if (!ZSTD_isError(ret)) goto _output_error;
849 }
850 ZSTD_freeDCtx(dctx);
851 }
852 DISPLAYLEVEL(3, "OK \n");
853
854 DISPLAYLEVEL(3, "test%3i : ZSTD_initDStream*() with dictionary : ", testNb++);
855 {
856 ZSTD_DCtx* dctx = ZSTD_createDCtx();
857 ZSTD_DDict* ddict = ZSTD_createDDict(dictionary.start, dictionary.filled);
858 size_t ret;
859 /* We should succeed to decompress with the dictionary. */
860 CHECK_Z( ZSTD_initDStream_usingDict(dctx, dictionary.start, dictionary.filled) );
861 CHECK_Z( ZSTD_decompressDCtx(dctx, decodedBuffer, decodedBufferSize, compressedBuffer, cSize) );
862 /* The dictionary should presist across calls. */
863 CHECK_Z( ZSTD_decompressDCtx(dctx, decodedBuffer, decodedBufferSize, compressedBuffer, cSize) );
864 /* We should succeed to decompress with the ddict. */
865 CHECK_Z( ZSTD_initDStream_usingDDict(dctx, ddict) );
866 CHECK_Z( ZSTD_decompressDCtx(dctx, decodedBuffer, decodedBufferSize, compressedBuffer, cSize) );
867 /* The ddict should presist across calls. */
868 CHECK_Z( ZSTD_decompressDCtx(dctx, decodedBuffer, decodedBufferSize, compressedBuffer, cSize) );
869 /* When we reset the context the ddict is cleared. */
870 CHECK_Z( ZSTD_initDStream(dctx) );
871 ret = ZSTD_decompressDCtx(dctx, decodedBuffer, decodedBufferSize, compressedBuffer, cSize);
872 if (!ZSTD_isError(ret)) goto _output_error;
873 ZSTD_freeDCtx(dctx);
874 ZSTD_freeDDict(ddict);
875 }
876 DISPLAYLEVEL(3, "OK \n");
877
Yann Collet7d283cd2017-04-27 14:48:34 -0700878 DISPLAYLEVEL(3, "test%3i : ZSTD_initCStream_usingCDict_advanced with masked dictID : ", testNb++);
879 { ZSTD_compressionParameters const cParams = ZSTD_getCParams(1, CNBufferSize, dictionary.filled);
880 ZSTD_frameParameters const fParams = { 1 /* contentSize */, 1 /* checksum */, 1 /* noDictID */};
Yann Collet6873fec2018-03-20 15:13:14 -0700881 ZSTD_CDict* const cdict = ZSTD_createCDict_advanced(dictionary.start, dictionary.filled, ZSTD_dlm_byRef, ZSTD_dct_auto, cParams, ZSTD_defaultCMem);
Yann Collet8c910d22017-06-03 01:15:02 -0700882 size_t const initError = ZSTD_initCStream_usingCDict_advanced(zc, cdict, fParams, CNBufferSize);
Yann Collet7d283cd2017-04-27 14:48:34 -0700883 if (ZSTD_isError(initError)) goto _output_error;
Nick Terrell62ecad32017-04-03 20:56:39 -0700884 outBuff.dst = compressedBuffer;
885 outBuff.size = compressedBufferSize;
886 outBuff.pos = 0;
887 inBuff.src = CNBuffer;
888 inBuff.size = CNBufferSize;
889 inBuff.pos = 0;
Yann Colletd6770f82017-09-28 02:14:48 -0700890 CHECK_Z( ZSTD_compressStream(zc, &outBuff, &inBuff) );
Yann Collet8c910d22017-06-03 01:15:02 -0700891 if (inBuff.pos != inBuff.size) goto _output_error; /* entire input should be consumed */
Nick Terrell62ecad32017-04-03 20:56:39 -0700892 { size_t const r = ZSTD_endStream(zc, &outBuff);
893 if (r != 0) goto _output_error; } /* error, or some data not flushed */
894 cSize = outBuff.pos;
895 ZSTD_freeCDict(cdict);
Yann Colletededcfc2018-12-21 16:19:44 -0800896 DISPLAYLEVEL(3, "OK (%u bytes : %.2f%%)\n", (unsigned)cSize, (double)cSize/CNBufferSize*100);
Yann Collet4ee6b152017-04-11 11:59:44 -0700897 }
Nick Terrell62ecad32017-04-03 20:56:39 -0700898
Yann Colleta92cbb72017-04-27 15:08:56 -0700899 DISPLAYLEVEL(3, "test%3i : try retrieving dictID from frame : ", testNb++);
900 { U32 const did = ZSTD_getDictID_fromFrame(compressedBuffer, cSize);
901 if (did != 0) goto _output_error;
902 }
903 DISPLAYLEVEL(3, "OK (not detected) \n");
904
Yann Collet4ee6b152017-04-11 11:59:44 -0700905 DISPLAYLEVEL(3, "test%3i : decompress without dictionary : ", testNb++);
906 { size_t const r = ZSTD_decompress(decodedBuffer, CNBufferSize, compressedBuffer, cSize);
907 if (!ZSTD_isError(r)) goto _output_error; /* must fail : dictionary not used */
908 DISPLAYLEVEL(3, "OK (%s)\n", ZSTD_getErrorName(r));
Nick Terrell62ecad32017-04-03 20:56:39 -0700909 }
910
Yann Collet62f7efc2017-06-28 16:25:13 -0700911 DISPLAYLEVEL(3, "test%3i : compress with ZSTD_CCtx_refPrefix : ", testNb++);
Yann Colletd6770f82017-09-28 02:14:48 -0700912 CHECK_Z( ZSTD_CCtx_refPrefix(zc, dictionary.start, dictionary.filled) );
Yann Collet62f7efc2017-06-28 16:25:13 -0700913 outBuff.dst = compressedBuffer;
914 outBuff.size = compressedBufferSize;
915 outBuff.pos = 0;
916 inBuff.src = CNBuffer;
917 inBuff.size = CNBufferSize;
918 inBuff.pos = 0;
Yann Colletd8e215c2018-11-30 11:16:26 -0800919 CHECK_Z( ZSTD_compressStream2(zc, &outBuff, &inBuff, ZSTD_e_end) );
Yann Collet62f7efc2017-06-28 16:25:13 -0700920 if (inBuff.pos != inBuff.size) goto _output_error; /* entire input should be consumed */
921 cSize = outBuff.pos;
Yann Colletededcfc2018-12-21 16:19:44 -0800922 DISPLAYLEVEL(3, "OK (%u bytes : %.2f%%)\n", (unsigned)cSize, (double)cSize/CNBufferSize*100);
Yann Collet62f7efc2017-06-28 16:25:13 -0700923
Yann Collet6cda8c92018-03-20 16:16:13 -0700924 DISPLAYLEVEL(3, "test%3i : decompress with ZSTD_DCtx_refPrefix : ", testNb++);
925 CHECK_Z( ZSTD_DCtx_refPrefix(zd, dictionary.start, dictionary.filled) );
926 outBuff.dst = decodedBuffer;
927 outBuff.size = CNBufferSize;
928 outBuff.pos = 0;
929 inBuff.src = compressedBuffer;
930 inBuff.size = cSize;
931 inBuff.pos = 0;
Yann Collet34e146f2018-12-04 10:28:36 -0800932 CHECK_Z( ZSTD_decompressStream(zd, &outBuff, &inBuff) );
Yann Collet6cda8c92018-03-20 16:16:13 -0700933 if (inBuff.pos != inBuff.size) goto _output_error; /* entire input should be consumed */
934 if (outBuff.pos != CNBufferSize) goto _output_error; /* must regenerate whole input */
935 DISPLAYLEVEL(3, "OK \n");
Yann Collet62f7efc2017-06-28 16:25:13 -0700936
937 DISPLAYLEVEL(3, "test%3i : decompress without dictionary (should fail): ", testNb++);
938 { size_t const r = ZSTD_decompress(decodedBuffer, CNBufferSize, compressedBuffer, cSize);
939 if (!ZSTD_isError(r)) goto _output_error; /* must fail : dictionary not used */
940 DISPLAYLEVEL(3, "OK (%s)\n", ZSTD_getErrorName(r));
941 }
942
Yann Colletd8e215c2018-11-30 11:16:26 -0800943 DISPLAYLEVEL(3, "test%3i : compress again with ZSTD_compressStream2 : ", testNb++);
Yann Collet62f7efc2017-06-28 16:25:13 -0700944 outBuff.dst = compressedBuffer;
945 outBuff.size = compressedBufferSize;
946 outBuff.pos = 0;
947 inBuff.src = CNBuffer;
948 inBuff.size = CNBufferSize;
949 inBuff.pos = 0;
Yann Colletd8e215c2018-11-30 11:16:26 -0800950 CHECK_Z( ZSTD_compressStream2(zc, &outBuff, &inBuff, ZSTD_e_end) );
Yann Collet62f7efc2017-06-28 16:25:13 -0700951 if (inBuff.pos != inBuff.size) goto _output_error; /* entire input should be consumed */
952 cSize = outBuff.pos;
Yann Colletededcfc2018-12-21 16:19:44 -0800953 DISPLAYLEVEL(3, "OK (%u bytes : %.2f%%)\n", (unsigned)cSize, (double)cSize/CNBufferSize*100);
Yann Collet62f7efc2017-06-28 16:25:13 -0700954
955 DISPLAYLEVEL(3, "test%3i : decompress without dictionary (should work): ", testNb++);
Yann Colletd6770f82017-09-28 02:14:48 -0700956 CHECK_Z( ZSTD_decompress(decodedBuffer, CNBufferSize, compressedBuffer, cSize) );
957 DISPLAYLEVEL(3, "OK \n");
Yann Collet62f7efc2017-06-28 16:25:13 -0700958
Yann Collet0bb381d2017-04-18 15:08:52 -0700959 /* Empty srcSize */
960 DISPLAYLEVEL(3, "test%3i : ZSTD_initCStream_advanced with pledgedSrcSize=0 and dict : ", testNb++);
961 { ZSTD_parameters params = ZSTD_getParams(5, 0, 0);
962 params.fParams.contentSizeFlag = 1;
Yann Collet213ef3b2017-10-13 19:01:58 -0700963 CHECK_Z( ZSTD_initCStream_advanced(zc, dictionary.start, dictionary.filled, params, 0 /* pledgedSrcSize==0 means "empty" when params.fParams.contentSizeFlag is set */) );
Yann Collet0bb381d2017-04-18 15:08:52 -0700964 } /* cstream advanced shall write content size = 0 */
Yann Collet8a104fd2017-12-12 12:51:49 -0800965 outBuff.dst = compressedBuffer;
966 outBuff.size = compressedBufferSize;
967 outBuff.pos = 0;
Yann Collet03832b72017-12-12 14:01:54 -0800968 inBuff.src = CNBuffer;
969 inBuff.size = 0;
970 inBuff.pos = 0;
Yann Colletd6770f82017-09-28 02:14:48 -0700971 CHECK_Z( ZSTD_compressStream(zc, &outBuff, &inBuff) );
Yann Collet0bb381d2017-04-18 15:08:52 -0700972 if (ZSTD_endStream(zc, &outBuff) != 0) goto _output_error;
973 cSize = outBuff.pos;
974 if (ZSTD_findDecompressedSize(compressedBuffer, cSize) != 0) goto _output_error;
975 DISPLAYLEVEL(3, "OK \n");
976
Sean Purcell2db72492017-02-09 10:50:43 -0800977 DISPLAYLEVEL(3, "test%3i : pledgedSrcSize == 0 behaves properly : ", testNb++);
978 { ZSTD_parameters params = ZSTD_getParams(5, 0, 0);
979 params.fParams.contentSizeFlag = 1;
Yann Colletd6770f82017-09-28 02:14:48 -0700980 CHECK_Z( ZSTD_initCStream_advanced(zc, NULL, 0, params, 0) );
Yann Collet4ee6b152017-04-11 11:59:44 -0700981 } /* cstream advanced shall write content size = 0 */
Sean Purcell2db72492017-02-09 10:50:43 -0800982 inBuff.src = CNBuffer;
983 inBuff.size = 0;
984 inBuff.pos = 0;
985 outBuff.dst = compressedBuffer;
986 outBuff.size = compressedBufferSize;
987 outBuff.pos = 0;
Yann Colletd6770f82017-09-28 02:14:48 -0700988 CHECK_Z( ZSTD_compressStream(zc, &outBuff, &inBuff) );
Sean Purcell2db72492017-02-09 10:50:43 -0800989 if (ZSTD_endStream(zc, &outBuff) != 0) goto _output_error;
990 cSize = outBuff.pos;
991 if (ZSTD_findDecompressedSize(compressedBuffer, cSize) != 0) goto _output_error;
992
993 ZSTD_resetCStream(zc, 0); /* resetCStream should treat 0 as unknown */
Yann Collet8a104fd2017-12-12 12:51:49 -0800994 outBuff.dst = compressedBuffer;
995 outBuff.size = compressedBufferSize;
996 outBuff.pos = 0;
Yann Collet03832b72017-12-12 14:01:54 -0800997 inBuff.src = CNBuffer;
998 inBuff.size = 0;
999 inBuff.pos = 0;
Yann Colletd6770f82017-09-28 02:14:48 -07001000 CHECK_Z( ZSTD_compressStream(zc, &outBuff, &inBuff) );
Sean Purcell2db72492017-02-09 10:50:43 -08001001 if (ZSTD_endStream(zc, &outBuff) != 0) goto _output_error;
1002 cSize = outBuff.pos;
1003 if (ZSTD_findDecompressedSize(compressedBuffer, cSize) != ZSTD_CONTENTSIZE_UNKNOWN) goto _output_error;
1004 DISPLAYLEVEL(3, "OK \n");
Yann Collet17e482e2016-08-23 16:58:10 +02001005
Stella Lau90a31bf2017-08-30 14:36:54 -07001006 /* Basic multithreading compression test */
1007 DISPLAYLEVEL(3, "test%3i : compress %u bytes with multiple threads : ", testNb++, COMPRESSIBLE_NOISE_LENGTH);
Yann Colletd6770f82017-09-28 02:14:48 -07001008 { ZSTD_parameters const params = ZSTD_getParams(1, 0, 0);
Yann Collet96adc842018-12-13 16:50:19 -08001009 int jobSize;
Nick Terrellb426bcc2018-06-25 15:21:08 -07001010 CHECK_Z( ZSTDMT_getMTCtxParameter(mtctx, ZSTDMT_p_jobSize, &jobSize));
1011 CHECK(jobSize != 0, "job size non-zero");
Yann Colletd6770f82017-09-28 02:14:48 -07001012 CHECK_Z( ZSTDMT_initCStream_advanced(mtctx, CNBuffer, dictSize, params, CNBufferSize) );
Nick Terrellb426bcc2018-06-25 15:21:08 -07001013 CHECK_Z( ZSTDMT_getMTCtxParameter(mtctx, ZSTDMT_p_jobSize, &jobSize));
1014 CHECK(jobSize != 0, "job size non-zero");
Yann Colletd6770f82017-09-28 02:14:48 -07001015 }
Yann Collet03832b72017-12-12 14:01:54 -08001016 outBuff.dst = compressedBuffer;
Stella Lau90a31bf2017-08-30 14:36:54 -07001017 outBuff.size = compressedBufferSize;
1018 outBuff.pos = 0;
1019 inBuff.src = CNBuffer;
1020 inBuff.size = CNBufferSize;
1021 inBuff.pos = 0;
Yann Collet67113962018-01-19 22:11:11 -08001022 { size_t const compressResult = ZSTDMT_compressStream_generic(mtctx, &outBuff, &inBuff, ZSTD_e_end);
1023 if (compressResult != 0) goto _output_error; /* compression must be completed in a single round */
1024 }
Stella Lau90a31bf2017-08-30 14:36:54 -07001025 if (inBuff.pos != inBuff.size) goto _output_error; /* entire input should be consumed */
Yann Collet67113962018-01-19 22:11:11 -08001026 { size_t const compressedSize = ZSTD_findFrameCompressedSize(compressedBuffer, outBuff.pos);
1027 if (compressedSize != outBuff.pos) goto _output_error; /* must be a full valid frame */
1028 }
Stella Lau90a31bf2017-08-30 14:36:54 -07001029 DISPLAYLEVEL(3, "OK \n");
1030
Yann Collet03832b72017-12-12 14:01:54 -08001031 /* Complex multithreading + dictionary test */
Yann Collet209df522018-02-01 19:29:30 -08001032 { U32 const nbWorkers = 2;
Yann Collet03832b72017-12-12 14:01:54 -08001033 size_t const jobSize = 4 * 1 MB;
Yann Collet209df522018-02-01 19:29:30 -08001034 size_t const srcSize = jobSize * nbWorkers; /* we want each job to have predictable size */
Yann Collet03832b72017-12-12 14:01:54 -08001035 size_t const segLength = 2 KB;
1036 size_t const offset = 600 KB; /* must be larger than window defined in cdict */
1037 size_t const start = jobSize + (offset-1);
1038 const BYTE* const srcToCopy = (const BYTE*)CNBuffer + start;
1039 BYTE* const dst = (BYTE*)CNBuffer + start - offset;
Yann Colletededcfc2018-12-21 16:19:44 -08001040 DISPLAYLEVEL(3, "test%3i : compress %u bytes with multiple threads + dictionary : ", testNb++, (unsigned)srcSize);
Yann Collet3583d192018-12-05 17:26:02 -08001041 CHECK_Z( ZSTD_CCtx_setParameter(zc, ZSTD_c_compressionLevel, 3) );
1042 CHECK_Z( ZSTD_CCtx_setParameter(zc, ZSTD_c_nbWorkers, nbWorkers) );
1043 CHECK_Z( ZSTD_CCtx_setParameter(zc, ZSTD_c_jobSize, jobSize) );
Yann Collet03832b72017-12-12 14:01:54 -08001044 assert(start > offset);
1045 assert(start + segLength < COMPRESSIBLE_NOISE_LENGTH);
1046 memcpy(dst, srcToCopy, segLength); /* create a long repetition at long distance for job 2 */
1047 outBuff.dst = compressedBuffer;
1048 outBuff.size = compressedBufferSize;
1049 outBuff.pos = 0;
1050 inBuff.src = CNBuffer;
1051 inBuff.size = srcSize; assert(srcSize < COMPRESSIBLE_NOISE_LENGTH);
1052 inBuff.pos = 0;
1053 }
Josh Sorefa880ca22019-04-12 14:18:11 -04001054 { ZSTD_compressionParameters const cParams = ZSTD_getCParams(1, 4 KB, dictionary.filled); /* intentionally lies on estimatedSrcSize, to push cdict into targeting a small window size */
Yann Collet6873fec2018-03-20 15:13:14 -07001055 ZSTD_CDict* const cdict = ZSTD_createCDict_advanced(dictionary.start, dictionary.filled, ZSTD_dlm_byRef, ZSTD_dct_fullDict, cParams, ZSTD_defaultCMem);
Yann Collet03832b72017-12-12 14:01:54 -08001056 DISPLAYLEVEL(5, "cParams.windowLog = %u : ", cParams.windowLog);
Yann Colletd23eb9a2017-12-13 15:35:49 -08001057 CHECK_Z( ZSTD_CCtx_refCDict(zc, cdict) );
Yann Colletd8e215c2018-11-30 11:16:26 -08001058 CHECK_Z( ZSTD_compressStream2(zc, &outBuff, &inBuff, ZSTD_e_end) );
Yann Colletd23eb9a2017-12-13 15:35:49 -08001059 CHECK_Z( ZSTD_CCtx_refCDict(zc, NULL) ); /* do not keep a reference to cdict, as its lifetime ends */
Yann Collet03832b72017-12-12 14:01:54 -08001060 ZSTD_freeCDict(cdict);
1061 }
1062 if (inBuff.pos != inBuff.size) goto _output_error; /* entire input should be consumed */
1063 cSize = outBuff.pos;
1064 DISPLAYLEVEL(3, "OK \n");
1065
1066 DISPLAYLEVEL(3, "test%3i : decompress large frame created from multiple threads + dictionary : ", testNb++);
1067 { ZSTD_DStream* const dstream = ZSTD_createDCtx();
1068 ZSTD_frameHeader zfh;
1069 ZSTD_getFrameHeader(&zfh, compressedBuffer, cSize);
Yann Colletededcfc2018-12-21 16:19:44 -08001070 DISPLAYLEVEL(5, "frame windowsize = %u : ", (unsigned)zfh.windowSize);
Yann Collet03832b72017-12-12 14:01:54 -08001071 outBuff.dst = decodedBuffer;
1072 outBuff.size = CNBufferSize;
1073 outBuff.pos = 0;
1074 inBuff.src = compressedBuffer;
1075 inBuff.pos = 0;
1076 CHECK_Z( ZSTD_initDStream_usingDict(dstream, dictionary.start, dictionary.filled) );
1077 inBuff.size = 1; /* avoid shortcut to single-pass mode */
1078 CHECK_Z( ZSTD_decompressStream(dstream, &outBuff, &inBuff) );
1079 inBuff.size = cSize;
1080 CHECK_Z( ZSTD_decompressStream(dstream, &outBuff, &inBuff) );
1081 if (inBuff.pos != inBuff.size) goto _output_error; /* entire input should be consumed */
1082 ZSTD_freeDStream(dstream);
1083 }
1084 DISPLAYLEVEL(3, "OK \n");
1085
Nick Terrelle600b5d2017-10-16 17:18:43 -07001086 DISPLAYLEVEL(3, "test%3i : check dictionary FSE tables can represent every code : ", testNb++);
1087 { unsigned const kMaxWindowLog = 24;
1088 unsigned value;
1089 ZSTD_compressionParameters cParams = ZSTD_getCParams(3, 1U << kMaxWindowLog, 1024);
1090 ZSTD_CDict* cdict;
1091 ZSTD_DDict* ddict;
1092 SEQ_stream seq = SEQ_initStream(0x87654321);
1093 SEQ_gen_type type;
1094 XXH64_state_t xxh;
1095
1096 XXH64_reset(&xxh, 0);
1097 cParams.windowLog = kMaxWindowLog;
Yann Collet6873fec2018-03-20 15:13:14 -07001098 cdict = ZSTD_createCDict_advanced(dictionary.start, dictionary.filled, ZSTD_dlm_byRef, ZSTD_dct_fullDict, cParams, ZSTD_defaultCMem);
Nick Terrelle600b5d2017-10-16 17:18:43 -07001099 ddict = ZSTD_createDDict(dictionary.start, dictionary.filled);
1100
1101 if (!cdict || !ddict) goto _output_error;
1102
Yann Collet5c686392018-11-15 16:12:39 -08001103 ZSTD_CCtx_reset(zc, ZSTD_reset_session_only);
Nick Terrelle600b5d2017-10-16 17:18:43 -07001104 ZSTD_resetDStream(zd);
1105 CHECK_Z(ZSTD_CCtx_refCDict(zc, cdict));
1106 CHECK_Z(ZSTD_initDStream_usingDDict(zd, ddict));
Yann Collet3e042d52018-12-04 17:30:58 -08001107 CHECK_Z(ZSTD_DCtx_setParameter(zd, ZSTD_d_windowLogMax, kMaxWindowLog));
Nick Terrelle600b5d2017-10-16 17:18:43 -07001108 /* Test all values < 300 */
1109 for (value = 0; value < 300; ++value) {
1110 for (type = (SEQ_gen_type)0; type < SEQ_gen_max; ++type) {
1111 CHECK_Z(SEQ_generateRoundTrip(zc, zd, &xxh, &seq, type, value));
1112 }
1113 }
1114 /* Test values 2^8 to 2^17 */
1115 for (value = (1 << 8); value < (1 << 17); value <<= 1) {
1116 for (type = (SEQ_gen_type)0; type < SEQ_gen_max; ++type) {
1117 CHECK_Z(SEQ_generateRoundTrip(zc, zd, &xxh, &seq, type, value));
1118 CHECK_Z(SEQ_generateRoundTrip(zc, zd, &xxh, &seq, type, value + (value >> 2)));
1119 }
1120 }
1121 /* Test offset values up to the max window log */
1122 for (value = 8; value <= kMaxWindowLog; ++value) {
1123 CHECK_Z(SEQ_generateRoundTrip(zc, zd, &xxh, &seq, SEQ_gen_of, (1U << value) - 1));
1124 }
1125
1126 CHECK_Z(SEQ_roundTrip(zc, zd, &xxh, NULL, 0, ZSTD_e_end));
1127 CHECK(SEQ_digest(&seq) != XXH64_digest(&xxh), "SEQ XXH64 does not match");
1128
1129 ZSTD_freeCDict(cdict);
1130 ZSTD_freeDDict(ddict);
1131 }
1132 DISPLAYLEVEL(3, "OK \n");
Stella Lau90a31bf2017-08-30 14:36:54 -07001133
Nick Terrell6d222c42018-07-12 17:56:58 -07001134 DISPLAYLEVEL(3, "test%3i : ZSTD_initCStream_srcSize sets requestedParams : ", testNb++);
Yann Colletd4d4e102018-11-21 15:37:26 -08001135 { int level;
Nick Terrell6d222c42018-07-12 17:56:58 -07001136 CHECK_Z(ZSTD_initCStream_srcSize(zc, 11, ZSTD_CONTENTSIZE_UNKNOWN));
Yann Collet3583d192018-12-05 17:26:02 -08001137 CHECK_Z(ZSTD_CCtx_getParameter(zc, ZSTD_c_compressionLevel, &level));
Nick Terrell6d222c42018-07-12 17:56:58 -07001138 CHECK(level != 11, "Compression level does not match");
1139 ZSTD_resetCStream(zc, ZSTD_CONTENTSIZE_UNKNOWN);
Yann Collet3583d192018-12-05 17:26:02 -08001140 CHECK_Z(ZSTD_CCtx_getParameter(zc, ZSTD_c_compressionLevel, &level));
Nick Terrell6d222c42018-07-12 17:56:58 -07001141 CHECK(level != 11, "Compression level does not match");
1142 }
1143 DISPLAYLEVEL(3, "OK \n");
1144
1145 DISPLAYLEVEL(3, "test%3i : ZSTD_initCStream_advanced sets requestedParams : ", testNb++);
1146 { ZSTD_parameters const params = ZSTD_getParams(9, 0, 0);
1147 CHECK_Z(ZSTD_initCStream_advanced(zc, NULL, 0, params, ZSTD_CONTENTSIZE_UNKNOWN));
1148 CHECK(badParameters(zc, params), "Compression parameters do not match");
1149 ZSTD_resetCStream(zc, ZSTD_CONTENTSIZE_UNKNOWN);
1150 CHECK(badParameters(zc, params), "Compression parameters do not match");
1151 }
1152 DISPLAYLEVEL(3, "OK \n");
1153
Sean Purcell887eaa92017-02-15 16:43:45 -08001154 /* Overlen overwriting window data bug */
1155 DISPLAYLEVEL(3, "test%3i : wildcopy doesn't overwrite potential match data : ", testNb++);
Sean Purcell0ed39012017-02-16 13:29:47 -08001156 { /* This test has a window size of 1024 bytes and consists of 3 blocks:
1157 1. 'a' repeated 517 times
1158 2. 'b' repeated 516 times
1159 3. a compressed block with no literals and 3 sequence commands:
1160 litlength = 0, offset = 24, match length = 24
1161 litlength = 0, offset = 24, match length = 3 (this one creates an overlength write of length 2*WILDCOPY_OVERLENGTH - 3)
1162 litlength = 0, offset = 1021, match length = 3 (this one will try to read from overwritten data if the buffer is too small) */
1163
1164 const char* testCase =
1165 "\x28\xB5\x2F\xFD\x04\x00\x4C\x00\x00\x10\x61\x61\x01\x00\x00\x2A"
1166 "\x80\x05\x44\x00\x00\x08\x62\x01\x00\x00\x2A\x20\x04\x5D\x00\x00"
1167 "\x00\x03\x40\x00\x00\x64\x60\x27\xB0\xE0\x0C\x67\x62\xCE\xE0";
Yann Colletd6770f82017-09-28 02:14:48 -07001168 ZSTD_DStream* const zds = ZSTD_createDStream();
1169 if (zds==NULL) goto _output_error;
Sean Purcell887eaa92017-02-15 16:43:45 -08001170
Yann Colletd6770f82017-09-28 02:14:48 -07001171 CHECK_Z( ZSTD_initDStream(zds) );
Sean Purcell887eaa92017-02-15 16:43:45 -08001172 inBuff.src = testCase;
Sean Purcell0ed39012017-02-16 13:29:47 -08001173 inBuff.size = 47;
Sean Purcell887eaa92017-02-15 16:43:45 -08001174 inBuff.pos = 0;
1175 outBuff.dst = decodedBuffer;
1176 outBuff.size = CNBufferSize;
1177 outBuff.pos = 0;
1178
1179 while (inBuff.pos < inBuff.size) {
Yann Colletd6770f82017-09-28 02:14:48 -07001180 CHECK_Z( ZSTD_decompressStream(zds, &outBuff, &inBuff) );
Sean Purcell887eaa92017-02-15 16:43:45 -08001181 }
Przemyslaw Skibinski684858e2017-02-21 18:17:24 +01001182
1183 ZSTD_freeDStream(zds);
Sean Purcell887eaa92017-02-15 16:43:45 -08001184 }
1185 DISPLAYLEVEL(3, "OK \n");
1186
Ephraim Park01e83842019-06-27 17:27:29 -07001187 /* Small Sequence Section bug */
1188 DISPLAYLEVEL(3, "test%3i : decompress blocks with small sequences section : ", testNb++);
1189 { /* This test consists of 3 blocks. Each block has one sequence.
1190 The sequence has literal length of 10, match length of 10 and offset of 10.
1191 The sequence value and compression mode for the blocks are following:
1192 The order of values are ll, ml, of.
1193 - First block : (10, 7, 13) (rle, rle, rle)
1194 - size of sequences section: 6 bytes (1 byte for nbSeq, 1 byte for encoding mode, 3 bytes for rle, 1 byte bitstream)
1195 - Second block : (10, 7, 1) (repeat, repeat, rle)
1196 - size of sequences section: 4 bytes (1 byte for nbSeq, 1 byte for encoding mode, 1 bytes for rle, 1 byte bitstream)
1197 - Third block : (10, 7, 1) (repeat, repeat, repeat)
1198 - size of sequences section: 3 bytes (1 byte for nbSeq, 1 byte for encoding mode, 1 byte bitstream) */
1199
1200 unsigned char compressed[] = {
1201 0x28, 0xb5, 0x2f, 0xfd, 0x24, 0x3c, 0x35, 0x01, 0x00, 0xf0, 0x85, 0x08,
1202 0xc2, 0xc4, 0x70, 0xcf, 0xd7, 0xc0, 0x96, 0x7e, 0x4c, 0x6b, 0xa9, 0x8b,
1203 0xbc, 0xc5, 0xb6, 0xd9, 0x7f, 0x4c, 0xf1, 0x05, 0xa6, 0x54, 0xef, 0xac,
1204 0x69, 0x94, 0x89, 0x1c, 0x03, 0x44, 0x0a, 0x07, 0x00, 0xb4, 0x04, 0x80,
1205 0x40, 0x0a, 0xa4
1206 };
1207 unsigned int compressedSize = 51;
1208 unsigned char decompressed[] = {
1209 0x85, 0x08, 0xc2, 0xc4, 0x70, 0xcf, 0xd7, 0xc0, 0x96, 0x7e, 0x85, 0x08,
1210 0xc2, 0xc4, 0x70, 0xcf, 0xd7, 0xc0, 0x96, 0x7e, 0x4c, 0x6b, 0xa9, 0x8b,
1211 0xbc, 0xc5, 0xb6, 0xd9, 0x7f, 0x4c, 0x4c, 0x6b, 0xa9, 0x8b, 0xbc, 0xc5,
1212 0xb6, 0xd9, 0x7f, 0x4c, 0xf1, 0x05, 0xa6, 0x54, 0xef, 0xac, 0x69, 0x94,
1213 0x89, 0x1c, 0xf1, 0x05, 0xa6, 0x54, 0xef, 0xac, 0x69, 0x94, 0x89, 0x1c
1214 };
1215 unsigned int decompressedSize = 60;
1216
1217 ZSTD_DStream* const zds = ZSTD_createDStream();
1218 if (zds==NULL) goto _output_error;
1219
1220 CHECK_Z( ZSTD_initDStream(zds) );
1221 inBuff.src = compressed;
1222 inBuff.size = compressedSize;
1223 inBuff.pos = 0;
1224 outBuff.dst = decodedBuffer;
1225 outBuff.size = CNBufferSize;
1226 outBuff.pos = 0;
1227
Ephraim Park28309522019-07-01 10:17:30 -07001228 CHECK(ZSTD_decompressStream(zds, &outBuff, &inBuff) != 0,
1229 "Decompress did not reach the end of frame");
1230 CHECK(inBuff.pos != inBuff.size, "Decompress did not fully consume input");
1231 CHECK(outBuff.pos != decompressedSize, "Decompressed size does not match");
1232 CHECK(memcmp(outBuff.dst, decompressed, decompressedSize) != 0,
1233 "Decompressed data does not match");
Ephraim Park01e83842019-06-27 17:27:29 -07001234
1235 ZSTD_freeDStream(zds);
1236 }
1237 DISPLAYLEVEL(3, "OK \n");
1238
W. Felix Handtedb4c8d02018-08-24 14:30:21 -07001239 DISPLAYLEVEL(3, "test%3i : dictionary + uncompressible block + reusing tables checks offset table validity: ", testNb++);
1240 { ZSTD_CDict* const cdict = ZSTD_createCDict_advanced(
1241 dictionary.start, dictionary.filled,
1242 ZSTD_dlm_byRef, ZSTD_dct_fullDict,
1243 ZSTD_getCParams(3, 0, dictionary.filled),
1244 ZSTD_defaultCMem);
1245 const size_t inbufsize = 2 * 128 * 1024; /* 2 blocks */
1246 const size_t outbufsize = ZSTD_compressBound(inbufsize);
1247 size_t inbufpos = 0;
1248 size_t cursegmentlen;
1249 BYTE *inbuf = (BYTE *)malloc(inbufsize);
1250 BYTE *outbuf = (BYTE *)malloc(outbufsize);
1251 BYTE *checkbuf = (BYTE *)malloc(inbufsize);
1252 size_t ret;
1253
1254 CHECK(cdict == NULL, "failed to alloc cdict");
1255 CHECK(inbuf == NULL, "failed to alloc input buffer");
Yann Colletd195eec2018-09-13 12:29:52 -07001256
W. Felix Handtedb4c8d02018-08-24 14:30:21 -07001257 /* first block is uncompressible */
1258 cursegmentlen = 128 * 1024;
1259 RDG_genBuffer(inbuf + inbufpos, cursegmentlen, 0., 0., seed);
1260 inbufpos += cursegmentlen;
1261
1262 /* second block is compressible */
1263 cursegmentlen = 128 * 1024 - 256;
1264 RDG_genBuffer(inbuf + inbufpos, cursegmentlen, 0.05, 0., seed);
1265 inbufpos += cursegmentlen;
1266
1267 /* and includes a very long backref */
1268 cursegmentlen = 128;
1269 memcpy(inbuf + inbufpos, dictionary.start + 256, cursegmentlen);
1270 inbufpos += cursegmentlen;
1271
1272 /* and includes a very long backref */
1273 cursegmentlen = 128;
1274 memcpy(inbuf + inbufpos, dictionary.start + 128, cursegmentlen);
1275 inbufpos += cursegmentlen;
1276
1277 ret = ZSTD_compress_usingCDict(zc, outbuf, outbufsize, inbuf, inbufpos, cdict);
1278 CHECK_Z(ret);
1279
1280 ret = ZSTD_decompress_usingDict(zd, checkbuf, inbufsize, outbuf, ret, dictionary.start, dictionary.filled);
1281 CHECK_Z(ret);
1282
1283 CHECK(memcmp(inbuf, checkbuf, inbufpos), "start and finish buffers don't match");
1284
1285 ZSTD_freeCDict(cdict);
1286 free(inbuf);
1287 free(outbuf);
1288 free(checkbuf);
1289 }
1290 DISPLAYLEVEL(3, "OK \n");
1291
Nick Terrell146049a2018-09-28 12:09:14 -07001292 DISPLAYLEVEL(3, "test%3i : dictionary + small blocks + reusing tables checks offset table validity: ", testNb++);
1293 { ZSTD_CDict* const cdict = ZSTD_createCDict_advanced(
1294 dictionary.start, dictionary.filled,
1295 ZSTD_dlm_byRef, ZSTD_dct_fullDict,
1296 ZSTD_getCParams(3, 0, dictionary.filled),
1297 ZSTD_defaultCMem);
1298 ZSTD_outBuffer out = {compressedBuffer, compressedBufferSize, 0};
1299 int remainingInput = 256 * 1024;
Nick Terrelleb4423e2018-09-28 14:24:38 -07001300 int offset;
Nick Terrell146049a2018-09-28 12:09:14 -07001301
Yann Collet5c686392018-11-15 16:12:39 -08001302 CHECK_Z(ZSTD_CCtx_reset(zc, ZSTD_reset_session_and_parameters));
Nick Terrell146049a2018-09-28 12:09:14 -07001303 CHECK_Z(ZSTD_CCtx_refCDict(zc, cdict));
Yann Collet3583d192018-12-05 17:26:02 -08001304 CHECK_Z(ZSTD_CCtx_setParameter(zc, ZSTD_c_checksumFlag, 1));
Nick Terrell146049a2018-09-28 12:09:14 -07001305 /* Write a bunch of 6 byte blocks */
1306 while (remainingInput > 0) {
Nick Terrell0e7a7f12018-09-28 12:14:24 -07001307 char testBuffer[6] = "\xAA\xAA\xAA\xAA\xAA\xAA";
1308 const size_t kSmallBlockSize = sizeof(testBuffer);
Nick Terrell146049a2018-09-28 12:09:14 -07001309 ZSTD_inBuffer in = {testBuffer, kSmallBlockSize, 0};
1310
Yann Colletd8e215c2018-11-30 11:16:26 -08001311 CHECK_Z(ZSTD_compressStream2(zc, &out, &in, ZSTD_e_flush));
Nick Terrell146049a2018-09-28 12:09:14 -07001312 CHECK(in.pos != in.size, "input not fully consumed");
1313 remainingInput -= kSmallBlockSize;
1314 }
1315 /* Write several very long offset matches into the dictionary */
Nick Terrelleb4423e2018-09-28 14:24:38 -07001316 for (offset = 1024; offset >= 0; offset -= 128) {
Nick Terrell146049a2018-09-28 12:09:14 -07001317 ZSTD_inBuffer in = {dictionary.start + offset, 128, 0};
1318 ZSTD_EndDirective flush = offset > 0 ? ZSTD_e_continue : ZSTD_e_end;
Yann Colletd8e215c2018-11-30 11:16:26 -08001319 CHECK_Z(ZSTD_compressStream2(zc, &out, &in, flush));
Nick Terrell146049a2018-09-28 12:09:14 -07001320 CHECK(in.pos != in.size, "input not fully consumed");
1321 }
1322 /* Ensure decompression works */
1323 CHECK_Z(ZSTD_decompress_usingDict(zd, decodedBuffer, CNBufferSize, out.dst, out.pos, dictionary.start, dictionary.filled));
1324
1325 ZSTD_freeCDict(cdict);
1326 }
1327 DISPLAYLEVEL(3, "OK \n");
1328
Yann Colletd7883a22016-08-12 16:48:02 +02001329_end:
Yann Collet33fce032017-01-16 19:46:22 -08001330 FUZ_freeDictionary(dictionary);
Yann Colletd7883a22016-08-12 16:48:02 +02001331 ZSTD_freeCStream(zc);
1332 ZSTD_freeDStream(zd);
Stella Lau90a31bf2017-08-30 14:36:54 -07001333 ZSTDMT_freeCCtx(mtctx);
Yann Colletd7883a22016-08-12 16:48:02 +02001334 free(CNBuffer);
1335 free(compressedBuffer);
1336 free(decodedBuffer);
1337 return testResult;
1338
1339_output_error:
1340 testResult = 1;
1341 DISPLAY("Error detected in Unit tests ! \n");
1342 goto _end;
1343}
1344
1345
Yann Collet3ecbe6a2016-09-14 17:26:59 +02001346/* ====== Fuzzer tests ====== */
1347
Yann Colletd7883a22016-08-12 16:48:02 +02001348static size_t findDiff(const void* buf1, const void* buf2, size_t max)
1349{
1350 const BYTE* b1 = (const BYTE*)buf1;
1351 const BYTE* b2 = (const BYTE*)buf2;
1352 size_t u;
1353 for (u=0; u<max; u++) {
1354 if (b1[u] != b2[u]) break;
1355 }
Yann Collet940634a2018-01-19 13:19:59 -08001356 if (u==max) {
Yann Colletededcfc2018-12-21 16:19:44 -08001357 DISPLAY("=> No difference detected within %u bytes \n", (unsigned)max);
Yann Collet940634a2018-01-19 13:19:59 -08001358 return u;
1359 }
Yann Colletededcfc2018-12-21 16:19:44 -08001360 DISPLAY("Error at position %u / %u \n", (unsigned)u, (unsigned)max);
Yann Colletdc696232018-01-19 12:41:56 -08001361 if (u>=3)
1362 DISPLAY(" %02X %02X %02X ",
1363 b1[u-3], b1[u-2], b1[u-1]);
1364 DISPLAY(" :%02X: %02X %02X %02X %02X %02X \n",
1365 b1[u], b1[u+1], b1[u+2], b1[u+3], b1[u+4], b1[u+5]);
1366 if (u>=3)
1367 DISPLAY(" %02X %02X %02X ",
1368 b2[u-3], b2[u-2], b2[u-1]);
1369 DISPLAY(" :%02X: %02X %02X %02X %02X %02X \n",
1370 b2[u], b2[u+1], b2[u+2], b2[u+3], b2[u+4], b2[u+5]);
Yann Colletd7883a22016-08-12 16:48:02 +02001371 return u;
1372}
1373
1374static size_t FUZ_rLogLength(U32* seed, U32 logLength)
1375{
1376 size_t const lengthMask = ((size_t)1 << logLength) - 1;
1377 return (lengthMask+1) + (FUZ_rand(seed) & lengthMask);
1378}
1379
1380static size_t FUZ_randomLength(U32* seed, U32 maxLog)
1381{
1382 U32 const logLength = FUZ_rand(seed) % maxLog;
1383 return FUZ_rLogLength(seed, logLength);
1384}
1385
Stella Lau9e406022017-09-06 08:39:46 -07001386/* Return value in range minVal <= v <= maxVal */
1387static U32 FUZ_randomClampedLength(U32* seed, U32 minVal, U32 maxVal)
1388{
1389 U32 const mod = maxVal < minVal ? 1 : (maxVal + 1) - minVal;
1390 return (U32)((FUZ_rand(seed) % mod) + minVal);
1391}
1392
Yann Colletededcfc2018-12-21 16:19:44 -08001393static int fuzzerTests(U32 seed, unsigned nbTests, unsigned startTest, double compressibility, int bigTests)
Yann Colletd7883a22016-08-12 16:48:02 +02001394{
Yann Colletf99c2c12017-06-21 23:35:58 -07001395 U32 const maxSrcLog = bigTests ? 24 : 22;
Yann Colletd7883a22016-08-12 16:48:02 +02001396 static const U32 maxSampleLog = 19;
Yann Collet58d5dfe2016-09-25 01:34:03 +02001397 size_t const srcBufferSize = (size_t)1<<maxSrcLog;
Yann Colletd7883a22016-08-12 16:48:02 +02001398 BYTE* cNoiseBuffer[5];
Yann Colletbc32b402017-09-27 17:27:38 -07001399 size_t const copyBufferSize = srcBufferSize + (1<<maxSampleLog);
Yann Collet58d5dfe2016-09-25 01:34:03 +02001400 BYTE* const copyBuffer = (BYTE*)malloc (copyBufferSize);
Yann Colletbc32b402017-09-27 17:27:38 -07001401 size_t const cBufferSize = ZSTD_compressBound(srcBufferSize);
Yann Collet58d5dfe2016-09-25 01:34:03 +02001402 BYTE* const cBuffer = (BYTE*)malloc (cBufferSize);
1403 size_t const dstBufferSize = srcBufferSize;
1404 BYTE* const dstBuffer = (BYTE*)malloc (dstBufferSize);
Yann Colletd7883a22016-08-12 16:48:02 +02001405 U32 result = 0;
Yann Colletededcfc2018-12-21 16:19:44 -08001406 unsigned testNb = 0;
Yann Colletd7883a22016-08-12 16:48:02 +02001407 U32 coreSeed = seed;
Yann Colletbc32b402017-09-27 17:27:38 -07001408 ZSTD_CStream* zc = ZSTD_createCStream(); /* will be re-created sometimes */
1409 ZSTD_DStream* zd = ZSTD_createDStream(); /* will be re-created sometimes */
Yann Collet58d5dfe2016-09-25 01:34:03 +02001410 ZSTD_DStream* const zd_noise = ZSTD_createDStream();
Nick Terrell9a2f6f42017-11-29 19:11:12 -08001411 UTIL_time_t const startClock = UTIL_getTime();
Yann Colletbc32b402017-09-27 17:27:38 -07001412 const BYTE* dict = NULL; /* can keep same dict on 2 consecutive tests */
Yann Colletcf409a72016-09-26 16:41:05 +02001413 size_t dictSize = 0;
1414 U32 oldTestLog = 0;
Yann Collet49f84592017-06-21 18:43:39 -07001415 U32 const cLevelMax = bigTests ? (U32)ZSTD_maxCLevel() : g_cLevelMax_smallTests;
Yann Colletd7883a22016-08-12 16:48:02 +02001416
1417 /* allocations */
Yann Colletd7883a22016-08-12 16:48:02 +02001418 cNoiseBuffer[0] = (BYTE*)malloc (srcBufferSize);
1419 cNoiseBuffer[1] = (BYTE*)malloc (srcBufferSize);
1420 cNoiseBuffer[2] = (BYTE*)malloc (srcBufferSize);
1421 cNoiseBuffer[3] = (BYTE*)malloc (srcBufferSize);
1422 cNoiseBuffer[4] = (BYTE*)malloc (srcBufferSize);
Yann Colletd7883a22016-08-12 16:48:02 +02001423 CHECK (!cNoiseBuffer[0] || !cNoiseBuffer[1] || !cNoiseBuffer[2] || !cNoiseBuffer[3] || !cNoiseBuffer[4] ||
Yann Collet58d5dfe2016-09-25 01:34:03 +02001424 !copyBuffer || !dstBuffer || !cBuffer || !zc || !zd || !zd_noise ,
Yann Colletd7883a22016-08-12 16:48:02 +02001425 "Not enough memory, fuzzer tests cancelled");
1426
1427 /* Create initial samples */
1428 RDG_genBuffer(cNoiseBuffer[0], srcBufferSize, 0.00, 0., coreSeed); /* pure noise */
1429 RDG_genBuffer(cNoiseBuffer[1], srcBufferSize, 0.05, 0., coreSeed); /* barely compressible */
1430 RDG_genBuffer(cNoiseBuffer[2], srcBufferSize, compressibility, 0., coreSeed);
1431 RDG_genBuffer(cNoiseBuffer[3], srcBufferSize, 0.95, 0., coreSeed); /* highly compressible */
1432 RDG_genBuffer(cNoiseBuffer[4], srcBufferSize, 1.00, 0., coreSeed); /* sparse content */
1433 memset(copyBuffer, 0x65, copyBufferSize); /* make copyBuffer considered initialized */
Yann Collet58d5dfe2016-09-25 01:34:03 +02001434 ZSTD_initDStream_usingDict(zd, NULL, 0); /* ensure at least one init */
Yann Colletd7883a22016-08-12 16:48:02 +02001435
1436 /* catch up testNb */
1437 for (testNb=1; testNb < startTest; testNb++)
1438 FUZ_rand(&coreSeed);
1439
1440 /* test loop */
Nick Terrell9a2f6f42017-11-29 19:11:12 -08001441 for ( ; (testNb <= nbTests) || (UTIL_clockSpanMicro(startClock) < g_clockTime) ; testNb++ ) {
Yann Colletd7883a22016-08-12 16:48:02 +02001442 U32 lseed;
1443 const BYTE* srcBuffer;
Yann Collet58d5dfe2016-09-25 01:34:03 +02001444 size_t totalTestSize, totalGenSize, cSize;
Yann Colletd7883a22016-08-12 16:48:02 +02001445 XXH64_state_t xxhState;
1446 U64 crcOrig;
Yann Collet58d5dfe2016-09-25 01:34:03 +02001447 U32 resetAllowed = 1;
Yann Colletcf409a72016-09-26 16:41:05 +02001448 size_t maxTestSize;
Yann Colletd7883a22016-08-12 16:48:02 +02001449
1450 /* init */
Yann Colletd7883a22016-08-12 16:48:02 +02001451 FUZ_rand(&coreSeed);
Yann Collet33fce032017-01-16 19:46:22 -08001452 lseed = coreSeed ^ prime32;
Yann Collet3ad7d492018-01-19 17:35:08 -08001453 if (nbTests >= testNb) {
Yann Collet9c40ae72018-01-26 17:48:33 -08001454 DISPLAYUPDATE(2, "\r%6u/%6u ", testNb, nbTests);
Yann Collet3ad7d492018-01-19 17:35:08 -08001455 } else {
Yann Collet9c40ae72018-01-26 17:48:33 -08001456 DISPLAYUPDATE(2, "\r%6u ", testNb);
Yann Collet3ad7d492018-01-19 17:35:08 -08001457 }
Yann Colletd7883a22016-08-12 16:48:02 +02001458
Yann Collet3ecbe6a2016-09-14 17:26:59 +02001459 /* states full reset (deliberately not synchronized) */
1460 /* some issues can only happen when reusing states */
Yann Colleted1d0392017-06-19 11:07:33 -07001461 if ((FUZ_rand(&lseed) & 0xFF) == 131) {
1462 ZSTD_freeCStream(zc);
1463 zc = ZSTD_createCStream();
Yann Colletdce78922017-06-21 15:53:42 -07001464 CHECK(zc==NULL, "ZSTD_createCStream : allocation error");
Yann Colleted1d0392017-06-19 11:07:33 -07001465 resetAllowed=0;
1466 }
1467 if ((FUZ_rand(&lseed) & 0xFF) == 132) {
1468 ZSTD_freeDStream(zd);
1469 zd = ZSTD_createDStream();
Yann Colletdce78922017-06-21 15:53:42 -07001470 CHECK(zd==NULL, "ZSTD_createDStream : allocation error");
1471 CHECK_Z( ZSTD_initDStream_usingDict(zd, NULL, 0) ); /* ensure at least one init */
Yann Colleted1d0392017-06-19 11:07:33 -07001472 }
Yann Colletd7883a22016-08-12 16:48:02 +02001473
1474 /* srcBuffer selection [0-4] */
1475 { U32 buffNb = FUZ_rand(&lseed) & 0x7F;
1476 if (buffNb & 7) buffNb=2; /* most common : compressible (P) */
1477 else {
1478 buffNb >>= 3;
1479 if (buffNb & 7) {
1480 const U32 tnb[2] = { 1, 3 }; /* barely/highly compressible */
1481 buffNb = tnb[buffNb >> 3];
1482 } else {
1483 const U32 tnb[2] = { 0, 4 }; /* not compressible / sparse */
1484 buffNb = tnb[buffNb >> 3];
1485 } }
1486 srcBuffer = cNoiseBuffer[buffNb];
1487 }
1488
1489 /* compression init */
Yann Colletcf409a72016-09-26 16:41:05 +02001490 if ((FUZ_rand(&lseed)&1) /* at beginning, to keep same nb of rand */
1491 && oldTestLog /* at least one test happened */ && resetAllowed) {
1492 maxTestSize = FUZ_randomLength(&lseed, oldTestLog+2);
Yann Colletbc32b402017-09-27 17:27:38 -07001493 maxTestSize = MIN(maxTestSize, srcBufferSize-16);
Yann Colletcf409a72016-09-26 16:41:05 +02001494 { U64 const pledgedSrcSize = (FUZ_rand(&lseed) & 3) ? 0 : maxTestSize;
Yann Collet01743a32017-06-16 17:56:41 -07001495 CHECK_Z( ZSTD_resetCStream(zc, pledgedSrcSize) );
Yann Colletcf409a72016-09-26 16:41:05 +02001496 }
Yann Collet58d5dfe2016-09-25 01:34:03 +02001497 } else {
1498 U32 const testLog = FUZ_rand(&lseed) % maxSrcLog;
Sean Purcellf5e50512017-03-15 15:04:54 -07001499 U32 const dictLog = FUZ_rand(&lseed) % maxSrcLog;
Yann Colletbfc2f002017-06-21 17:57:14 -07001500 U32 const cLevelCandidate = ( FUZ_rand(&lseed) %
Sean Purcell7ebf2de2017-03-20 11:25:00 -07001501 (ZSTD_maxCLevel() -
Yann Colletbfc2f002017-06-21 17:57:14 -07001502 (MAX(testLog, dictLog) / 3)))
Yann Colletce800982017-04-05 16:34:09 -07001503 + 1;
Yann Colletbfc2f002017-06-21 17:57:14 -07001504 U32 const cLevel = MIN(cLevelCandidate, cLevelMax);
Yann Colletd7883a22016-08-12 16:48:02 +02001505 maxTestSize = FUZ_rLogLength(&lseed, testLog);
Yann Colletcf409a72016-09-26 16:41:05 +02001506 oldTestLog = testLog;
Yann Colletd7883a22016-08-12 16:48:02 +02001507 /* random dictionary selection */
Yann Colletf99c2c12017-06-21 23:35:58 -07001508 dictSize = ((FUZ_rand(&lseed)&7)==1) ? FUZ_rLogLength(&lseed, dictLog) : 0;
Yann Colletd7883a22016-08-12 16:48:02 +02001509 { size_t const dictStart = FUZ_rand(&lseed) % (srcBufferSize - dictSize);
1510 dict = srcBuffer + dictStart;
1511 }
Yann Collet213ef3b2017-10-13 19:01:58 -07001512 { U64 const pledgedSrcSize = (FUZ_rand(&lseed) & 3) ? ZSTD_CONTENTSIZE_UNKNOWN : maxTestSize;
Yann Colletcf409a72016-09-26 16:41:05 +02001513 ZSTD_parameters params = ZSTD_getParams(cLevel, pledgedSrcSize, dictSize);
Yann Colletd7883a22016-08-12 16:48:02 +02001514 params.fParams.checksumFlag = FUZ_rand(&lseed) & 1;
1515 params.fParams.noDictIDFlag = FUZ_rand(&lseed) & 1;
Yann Collet213ef3b2017-10-13 19:01:58 -07001516 params.fParams.contentSizeFlag = FUZ_rand(&lseed) & 1;
Yann Collet01743a32017-06-16 17:56:41 -07001517 CHECK_Z ( ZSTD_initCStream_advanced(zc, dict, dictSize, params, pledgedSrcSize) );
1518 } }
Yann Colletd7883a22016-08-12 16:48:02 +02001519
1520 /* multi-segments compression test */
1521 XXH64_reset(&xxhState, 0);
Yann Collet2f263942016-09-26 14:06:08 +02001522 { ZSTD_outBuffer outBuff = { cBuffer, cBufferSize, 0 } ;
Yann Collet58d5dfe2016-09-25 01:34:03 +02001523 U32 n;
Yann Collet2f263942016-09-26 14:06:08 +02001524 for (n=0, cSize=0, totalTestSize=0 ; totalTestSize < maxTestSize ; n++) {
Yann Collete795c8a2016-12-13 16:39:36 +01001525 /* compress random chunks into randomly sized dst buffers */
Yann Collet2f263942016-09-26 14:06:08 +02001526 { size_t const randomSrcSize = FUZ_randomLength(&lseed, maxSampleLog);
Yann Collet150354c2017-11-01 16:57:48 -07001527 size_t const srcSize = MIN(maxTestSize-totalTestSize, randomSrcSize);
Yann Collet2f263942016-09-26 14:06:08 +02001528 size_t const srcStart = FUZ_rand(&lseed) % (srcBufferSize - srcSize);
Yann Colletd7883a22016-08-12 16:48:02 +02001529 size_t const randomDstSize = FUZ_randomLength(&lseed, maxSampleLog);
1530 size_t const dstBuffSize = MIN(cBufferSize - cSize, randomDstSize);
Yann Collet2f263942016-09-26 14:06:08 +02001531 ZSTD_inBuffer inBuff = { srcBuffer+srcStart, srcSize, 0 };
Yann Collet53e17fb2016-08-17 01:39:22 +02001532 outBuff.size = outBuff.pos + dstBuffSize;
Yann Colletd7883a22016-08-12 16:48:02 +02001533
Yann Colleted1d0392017-06-19 11:07:33 -07001534 CHECK_Z( ZSTD_compressStream(zc, &outBuff, &inBuff) );
Yann Colletd7883a22016-08-12 16:48:02 +02001535
Yann Collet53e17fb2016-08-17 01:39:22 +02001536 XXH64_update(&xxhState, srcBuffer+srcStart, inBuff.pos);
1537 memcpy(copyBuffer+totalTestSize, srcBuffer+srcStart, inBuff.pos);
1538 totalTestSize += inBuff.pos;
Yann Colletd7883a22016-08-12 16:48:02 +02001539 }
1540
1541 /* random flush operation, to mess around */
1542 if ((FUZ_rand(&lseed) & 15) == 0) {
1543 size_t const randomDstSize = FUZ_randomLength(&lseed, maxSampleLog);
Yann Collet53e17fb2016-08-17 01:39:22 +02001544 size_t const adjustedDstSize = MIN(cBufferSize - cSize, randomDstSize);
1545 outBuff.size = outBuff.pos + adjustedDstSize;
Yann Colleted1d0392017-06-19 11:07:33 -07001546 CHECK_Z( ZSTD_flushStream(zc, &outBuff) );
1547 } }
Yann Colletd7883a22016-08-12 16:48:02 +02001548
1549 /* final frame epilogue */
1550 { size_t remainingToFlush = (size_t)(-1);
1551 while (remainingToFlush) {
1552 size_t const randomDstSize = FUZ_randomLength(&lseed, maxSampleLog);
1553 size_t const adjustedDstSize = MIN(cBufferSize - cSize, randomDstSize);
Yann Collet53e17fb2016-08-17 01:39:22 +02001554 outBuff.size = outBuff.pos + adjustedDstSize;
1555 remainingToFlush = ZSTD_endStream(zc, &outBuff);
Yann Collet009d6042017-05-19 10:17:59 -07001556 CHECK (ZSTD_isError(remainingToFlush), "end error : %s", ZSTD_getErrorName(remainingToFlush));
Yann Colletd7883a22016-08-12 16:48:02 +02001557 } }
1558 crcOrig = XXH64_digest(&xxhState);
Yann Collet53e17fb2016-08-17 01:39:22 +02001559 cSize = outBuff.pos;
Yann Colletd7883a22016-08-12 16:48:02 +02001560 }
1561
1562 /* multi - fragments decompression test */
Yann Collet58d5dfe2016-09-25 01:34:03 +02001563 if (!dictSize /* don't reset if dictionary : could be different */ && (FUZ_rand(&lseed) & 1)) {
Yann Colletdce78922017-06-21 15:53:42 -07001564 CHECK_Z ( ZSTD_resetDStream(zd) );
Yann Collet9ffbeea2016-12-02 18:37:38 -08001565 } else {
Yann Colletdce78922017-06-21 15:53:42 -07001566 CHECK_Z ( ZSTD_initDStream_usingDict(zd, dict, dictSize) );
Yann Collet9ffbeea2016-12-02 18:37:38 -08001567 }
Yann Colletd7883a22016-08-12 16:48:02 +02001568 { size_t decompressionResult = 1;
Yann Collet53e17fb2016-08-17 01:39:22 +02001569 ZSTD_inBuffer inBuff = { cBuffer, cSize, 0 };
1570 ZSTD_outBuffer outBuff= { dstBuffer, dstBufferSize, 0 };
1571 for (totalGenSize = 0 ; decompressionResult ; ) {
Yann Colletd7883a22016-08-12 16:48:02 +02001572 size_t const readCSrcSize = FUZ_randomLength(&lseed, maxSampleLog);
1573 size_t const randomDstSize = FUZ_randomLength(&lseed, maxSampleLog);
1574 size_t const dstBuffSize = MIN(dstBufferSize - totalGenSize, randomDstSize);
Yann Collet53e17fb2016-08-17 01:39:22 +02001575 inBuff.size = inBuff.pos + readCSrcSize;
Yann Colletca306c12017-09-27 00:39:41 -07001576 outBuff.size = outBuff.pos + dstBuffSize;
Yann Collet53e17fb2016-08-17 01:39:22 +02001577 decompressionResult = ZSTD_decompressStream(zd, &outBuff, &inBuff);
Yann Colletb3f33cc2017-09-09 14:37:28 -07001578 if (ZSTD_getErrorCode(decompressionResult) == ZSTD_error_checksum_wrong) {
1579 DISPLAY("checksum error : \n");
1580 findDiff(copyBuffer, dstBuffer, totalTestSize);
1581 }
1582 CHECK( ZSTD_isError(decompressionResult), "decompression error : %s",
1583 ZSTD_getErrorName(decompressionResult) );
Yann Colletd7883a22016-08-12 16:48:02 +02001584 }
1585 CHECK (decompressionResult != 0, "frame not fully decoded");
Yann Colletb3f33cc2017-09-09 14:37:28 -07001586 CHECK (outBuff.pos != totalTestSize, "decompressed data : wrong size (%u != %u)",
Yann Colletededcfc2018-12-21 16:19:44 -08001587 (unsigned)outBuff.pos, (unsigned)totalTestSize);
Yann Collet53e17fb2016-08-17 01:39:22 +02001588 CHECK (inBuff.pos != cSize, "compressed data should be fully read")
Yann Colletd7883a22016-08-12 16:48:02 +02001589 { U64 const crcDest = XXH64(dstBuffer, totalTestSize, 0);
1590 if (crcDest!=crcOrig) findDiff(copyBuffer, dstBuffer, totalTestSize);
1591 CHECK (crcDest!=crcOrig, "decompressed data corrupted");
1592 } }
1593
1594 /*===== noisy/erroneous src decompression test =====*/
1595
1596 /* add some noise */
1597 { U32 const nbNoiseChunks = (FUZ_rand(&lseed) & 7) + 2;
1598 U32 nn; for (nn=0; nn<nbNoiseChunks; nn++) {
1599 size_t const randomNoiseSize = FUZ_randomLength(&lseed, maxSampleLog);
1600 size_t const noiseSize = MIN((cSize/3) , randomNoiseSize);
1601 size_t const noiseStart = FUZ_rand(&lseed) % (srcBufferSize - noiseSize);
1602 size_t const cStart = FUZ_rand(&lseed) % (cSize - noiseSize);
1603 memcpy(cBuffer+cStart, srcBuffer+noiseStart, noiseSize);
1604 } }
1605
1606 /* try decompression on noisy data */
Yann Colletdce78922017-06-21 15:53:42 -07001607 CHECK_Z( ZSTD_initDStream(zd_noise) ); /* note : no dictionary */
Yann Collet53e17fb2016-08-17 01:39:22 +02001608 { ZSTD_inBuffer inBuff = { cBuffer, cSize, 0 };
1609 ZSTD_outBuffer outBuff= { dstBuffer, dstBufferSize, 0 };
1610 while (outBuff.pos < dstBufferSize) {
Yann Colletd7883a22016-08-12 16:48:02 +02001611 size_t const randomCSrcSize = FUZ_randomLength(&lseed, maxSampleLog);
1612 size_t const randomDstSize = FUZ_randomLength(&lseed, maxSampleLog);
Yann Collet53e17fb2016-08-17 01:39:22 +02001613 size_t const adjustedDstSize = MIN(dstBufferSize - outBuff.pos, randomDstSize);
Yann Collet64bf8ff2017-01-27 17:25:07 -08001614 size_t const adjustedCSrcSize = MIN(cSize - inBuff.pos, randomCSrcSize);
Yann Collet53e17fb2016-08-17 01:39:22 +02001615 outBuff.size = outBuff.pos + adjustedDstSize;
Yann Collet64bf8ff2017-01-27 17:25:07 -08001616 inBuff.size = inBuff.pos + adjustedCSrcSize;
Yann Collet53e17fb2016-08-17 01:39:22 +02001617 { size_t const decompressError = ZSTD_decompressStream(zd, &outBuff, &inBuff);
Yann Colletd7883a22016-08-12 16:48:02 +02001618 if (ZSTD_isError(decompressError)) break; /* error correctly detected */
Yann Collet64bf8ff2017-01-27 17:25:07 -08001619 /* No forward progress possible */
1620 if (outBuff.pos < outBuff.size && inBuff.pos == cSize) break;
Yann Colletd7883a22016-08-12 16:48:02 +02001621 } } } }
1622 DISPLAY("\r%u fuzzer tests completed \n", testNb);
1623
1624_cleanup:
1625 ZSTD_freeCStream(zc);
1626 ZSTD_freeDStream(zd);
Yann Collet58d5dfe2016-09-25 01:34:03 +02001627 ZSTD_freeDStream(zd_noise);
Yann Colletd7883a22016-08-12 16:48:02 +02001628 free(cNoiseBuffer[0]);
1629 free(cNoiseBuffer[1]);
1630 free(cNoiseBuffer[2]);
1631 free(cNoiseBuffer[3]);
1632 free(cNoiseBuffer[4]);
1633 free(copyBuffer);
1634 free(cBuffer);
1635 free(dstBuffer);
1636 return result;
1637
1638_output_error:
1639 result = 1;
1640 goto _cleanup;
1641}
1642
1643
Yann Colletc9e8ee92018-06-18 19:20:37 -07001644/* fuzzing ZSTDMT_* interface */
Yann Colletededcfc2018-12-21 16:19:44 -08001645static int fuzzerTests_MT(U32 seed, int nbTests, int startTest,
Yann Colletc9e8ee92018-06-18 19:20:37 -07001646 double compressibility, int bigTests)
Yann Collet736788f2017-01-19 12:12:50 -08001647{
Yann Colletf99c2c12017-06-21 23:35:58 -07001648 const U32 maxSrcLog = bigTests ? 24 : 22;
Yann Collet736788f2017-01-19 12:12:50 -08001649 static const U32 maxSampleLog = 19;
1650 size_t const srcBufferSize = (size_t)1<<maxSrcLog;
1651 BYTE* cNoiseBuffer[5];
1652 size_t const copyBufferSize= srcBufferSize + (1<<maxSampleLog);
1653 BYTE* const copyBuffer = (BYTE*)malloc (copyBufferSize);
1654 size_t const cBufferSize = ZSTD_compressBound(srcBufferSize);
1655 BYTE* const cBuffer = (BYTE*)malloc (cBufferSize);
1656 size_t const dstBufferSize = srcBufferSize;
1657 BYTE* const dstBuffer = (BYTE*)malloc (dstBufferSize);
1658 U32 result = 0;
Yann Colletededcfc2018-12-21 16:19:44 -08001659 int testNb = 0;
Yann Collet736788f2017-01-19 12:12:50 -08001660 U32 coreSeed = seed;
Yann Colletededcfc2018-12-21 16:19:44 -08001661 int nbThreads = 2;
Yann Colletbc32b402017-09-27 17:27:38 -07001662 ZSTDMT_CCtx* zc = ZSTDMT_createCCtx(nbThreads); /* will be reset sometimes */
Yann Collet736788f2017-01-19 12:12:50 -08001663 ZSTD_DStream* zd = ZSTD_createDStream(); /* will be reset sometimes */
1664 ZSTD_DStream* const zd_noise = ZSTD_createDStream();
Nick Terrell9a2f6f42017-11-29 19:11:12 -08001665 UTIL_time_t const startClock = UTIL_getTime();
Yann Collet736788f2017-01-19 12:12:50 -08001666 const BYTE* dict=NULL; /* can keep same dict on 2 consecutive tests */
1667 size_t dictSize = 0;
Yann Colletbc32b402017-09-27 17:27:38 -07001668 int const cLevelMax = bigTests ? (U32)ZSTD_maxCLevel()-1 : g_cLevelMax_smallTests;
1669 U32 const nbThreadsMax = bigTests ? 4 : 2;
Yann Collet736788f2017-01-19 12:12:50 -08001670
1671 /* allocations */
1672 cNoiseBuffer[0] = (BYTE*)malloc (srcBufferSize);
1673 cNoiseBuffer[1] = (BYTE*)malloc (srcBufferSize);
1674 cNoiseBuffer[2] = (BYTE*)malloc (srcBufferSize);
1675 cNoiseBuffer[3] = (BYTE*)malloc (srcBufferSize);
1676 cNoiseBuffer[4] = (BYTE*)malloc (srcBufferSize);
1677 CHECK (!cNoiseBuffer[0] || !cNoiseBuffer[1] || !cNoiseBuffer[2] || !cNoiseBuffer[3] || !cNoiseBuffer[4] ||
1678 !copyBuffer || !dstBuffer || !cBuffer || !zc || !zd || !zd_noise ,
1679 "Not enough memory, fuzzer tests cancelled");
1680
1681 /* Create initial samples */
1682 RDG_genBuffer(cNoiseBuffer[0], srcBufferSize, 0.00, 0., coreSeed); /* pure noise */
1683 RDG_genBuffer(cNoiseBuffer[1], srcBufferSize, 0.05, 0., coreSeed); /* barely compressible */
1684 RDG_genBuffer(cNoiseBuffer[2], srcBufferSize, compressibility, 0., coreSeed);
1685 RDG_genBuffer(cNoiseBuffer[3], srcBufferSize, 0.95, 0., coreSeed); /* highly compressible */
1686 RDG_genBuffer(cNoiseBuffer[4], srcBufferSize, 1.00, 0., coreSeed); /* sparse content */
1687 memset(copyBuffer, 0x65, copyBufferSize); /* make copyBuffer considered initialized */
1688 ZSTD_initDStream_usingDict(zd, NULL, 0); /* ensure at least one init */
Yann Colletededcfc2018-12-21 16:19:44 -08001689 DISPLAYLEVEL(6, "Creating initial context with %i threads \n", nbThreads);
Yann Collet736788f2017-01-19 12:12:50 -08001690
1691 /* catch up testNb */
1692 for (testNb=1; testNb < startTest; testNb++)
1693 FUZ_rand(&coreSeed);
1694
1695 /* test loop */
Nick Terrell9a2f6f42017-11-29 19:11:12 -08001696 for ( ; (testNb <= nbTests) || (UTIL_clockSpanMicro(startClock) < g_clockTime) ; testNb++ ) {
Yann Collet736788f2017-01-19 12:12:50 -08001697 U32 lseed;
1698 const BYTE* srcBuffer;
1699 size_t totalTestSize, totalGenSize, cSize;
1700 XXH64_state_t xxhState;
1701 U64 crcOrig;
Yann Collet736788f2017-01-19 12:12:50 -08001702 size_t maxTestSize;
1703
Yann Collet736788f2017-01-19 12:12:50 -08001704 FUZ_rand(&coreSeed);
Yann Collet3ad7d492018-01-19 17:35:08 -08001705 if (nbTests >= testNb) {
Yann Collet8e128ea2018-01-26 10:20:38 -08001706 DISPLAYUPDATE(2, "\r%6u/%6u ", testNb, nbTests);
Yann Collet3ad7d492018-01-19 17:35:08 -08001707 } else {
Yann Collet8e128ea2018-01-26 10:20:38 -08001708 DISPLAYUPDATE(2, "\r%6u ", testNb);
Yann Collet3ad7d492018-01-19 17:35:08 -08001709 }
Yann Colletd7e3cb52017-01-20 16:44:50 -08001710 lseed = coreSeed ^ prime32;
Yann Collet736788f2017-01-19 12:12:50 -08001711
1712 /* states full reset (deliberately not synchronized) */
1713 /* some issues can only happen when reusing states */
1714 if ((FUZ_rand(&lseed) & 0xFF) == 131) {
Yann Collet9fe50ed2017-09-28 01:42:06 -07001715 nbThreads = (FUZ_rand(&lseed) % nbThreadsMax) + 1;
Yann Collet30c76982017-03-31 18:27:03 -07001716 DISPLAYLEVEL(5, "Creating new context with %u threads \n", nbThreads);
Yann Collet736788f2017-01-19 12:12:50 -08001717 ZSTDMT_freeCCtx(zc);
1718 zc = ZSTDMT_createCCtx(nbThreads);
Yann Colletdce78922017-06-21 15:53:42 -07001719 CHECK(zc==NULL, "ZSTDMT_createCCtx allocation error")
Yann Collet736788f2017-01-19 12:12:50 -08001720 }
1721 if ((FUZ_rand(&lseed) & 0xFF) == 132) {
1722 ZSTD_freeDStream(zd);
1723 zd = ZSTD_createDStream();
Yann Colletdce78922017-06-21 15:53:42 -07001724 CHECK(zd==NULL, "ZSTDMT_createCCtx allocation error")
Yann Collet736788f2017-01-19 12:12:50 -08001725 ZSTD_initDStream_usingDict(zd, NULL, 0); /* ensure at least one init */
1726 }
1727
1728 /* srcBuffer selection [0-4] */
1729 { U32 buffNb = FUZ_rand(&lseed) & 0x7F;
1730 if (buffNb & 7) buffNb=2; /* most common : compressible (P) */
1731 else {
1732 buffNb >>= 3;
1733 if (buffNb & 7) {
1734 const U32 tnb[2] = { 1, 3 }; /* barely/highly compressible */
1735 buffNb = tnb[buffNb >> 3];
1736 } else {
1737 const U32 tnb[2] = { 0, 4 }; /* not compressible / sparse */
1738 buffNb = tnb[buffNb >> 3];
1739 } }
1740 srcBuffer = cNoiseBuffer[buffNb];
1741 }
1742
1743 /* compression init */
Yann Collet3ad7d492018-01-19 17:35:08 -08001744 { U32 const testLog = FUZ_rand(&lseed) % maxSrcLog;
Sean Purcellf5e50512017-03-15 15:04:54 -07001745 U32 const dictLog = FUZ_rand(&lseed) % maxSrcLog;
Yann Colletbc32b402017-09-27 17:27:38 -07001746 int const cLevelCandidate = ( FUZ_rand(&lseed)
1747 % (ZSTD_maxCLevel() - (MAX(testLog, dictLog) / 2)) )
1748 + 1;
1749 int const cLevelThreadAdjusted = cLevelCandidate - (nbThreads * 2) + 2; /* reduce cLevel when multiple threads to reduce memory consumption */
1750 int const cLevelMin = MAX(cLevelThreadAdjusted, 1); /* no negative cLevel yet */
1751 int const cLevel = MIN(cLevelMin, cLevelMax);
Yann Collet736788f2017-01-19 12:12:50 -08001752 maxTestSize = FUZ_rLogLength(&lseed, testLog);
Yann Collet3ad7d492018-01-19 17:35:08 -08001753
1754 if (FUZ_rand(&lseed)&1) { /* simple init */
1755 int const compressionLevel = (FUZ_rand(&lseed) % 5) + 1;
1756 DISPLAYLEVEL(5, "Init with compression level = %i \n", compressionLevel);
1757 CHECK_Z( ZSTDMT_initCStream(zc, compressionLevel) );
1758 } else { /* advanced init */
1759 /* random dictionary selection */
1760 dictSize = ((FUZ_rand(&lseed)&63)==1) ? FUZ_rLogLength(&lseed, dictLog) : 0;
1761 { size_t const dictStart = FUZ_rand(&lseed) % (srcBufferSize - dictSize);
1762 dict = srcBuffer + dictStart;
1763 }
1764 { U64 const pledgedSrcSize = (FUZ_rand(&lseed) & 3) ? ZSTD_CONTENTSIZE_UNKNOWN : maxTestSize;
1765 ZSTD_parameters params = ZSTD_getParams(cLevel, pledgedSrcSize, dictSize);
1766 DISPLAYLEVEL(5, "Init with windowLog = %u, pledgedSrcSize = %u, dictSize = %u \n",
Yann Colletededcfc2018-12-21 16:19:44 -08001767 params.cParams.windowLog, (unsigned)pledgedSrcSize, (unsigned)dictSize);
Yann Collet3ad7d492018-01-19 17:35:08 -08001768 params.fParams.checksumFlag = FUZ_rand(&lseed) & 1;
1769 params.fParams.noDictIDFlag = FUZ_rand(&lseed) & 1;
1770 params.fParams.contentSizeFlag = FUZ_rand(&lseed) & 1;
1771 DISPLAYLEVEL(5, "checksumFlag : %u \n", params.fParams.checksumFlag);
Yann Colleteee789b2018-12-11 17:41:42 -08001772 CHECK_Z( ZSTDMT_setMTCtxParameter(zc, ZSTDMT_p_overlapLog, FUZ_rand(&lseed) % 12) );
Yann Collet5e6aaa32018-12-10 18:45:03 -08001773 CHECK_Z( ZSTDMT_setMTCtxParameter(zc, ZSTDMT_p_jobSize, FUZ_rand(&lseed) % (2*maxTestSize+1)) ); /* custom job size */
Yann Collet3ad7d492018-01-19 17:35:08 -08001774 CHECK_Z( ZSTDMT_initCStream_advanced(zc, dict, dictSize, params, pledgedSrcSize) );
1775 } } }
Yann Collet736788f2017-01-19 12:12:50 -08001776
1777 /* multi-segments compression test */
1778 XXH64_reset(&xxhState, 0);
1779 { ZSTD_outBuffer outBuff = { cBuffer, cBufferSize, 0 } ;
1780 U32 n;
1781 for (n=0, cSize=0, totalTestSize=0 ; totalTestSize < maxTestSize ; n++) {
1782 /* compress random chunks into randomly sized dst buffers */
1783 { size_t const randomSrcSize = FUZ_randomLength(&lseed, maxSampleLog);
1784 size_t const srcSize = MIN (maxTestSize-totalTestSize, randomSrcSize);
1785 size_t const srcStart = FUZ_rand(&lseed) % (srcBufferSize - srcSize);
1786 size_t const randomDstSize = FUZ_randomLength(&lseed, maxSampleLog);
1787 size_t const dstBuffSize = MIN(cBufferSize - cSize, randomDstSize);
1788 ZSTD_inBuffer inBuff = { srcBuffer+srcStart, srcSize, 0 };
1789 outBuff.size = outBuff.pos + dstBuffSize;
1790
Yann Colletededcfc2018-12-21 16:19:44 -08001791 DISPLAYLEVEL(6, "Sending %u bytes to compress \n", (unsigned)srcSize);
Yann Colletdce78922017-06-21 15:53:42 -07001792 CHECK_Z( ZSTDMT_compressStream(zc, &outBuff, &inBuff) );
Yann Colletededcfc2018-12-21 16:19:44 -08001793 DISPLAYLEVEL(6, "%u bytes read by ZSTDMT_compressStream \n", (unsigned)inBuff.pos);
Yann Collet736788f2017-01-19 12:12:50 -08001794
1795 XXH64_update(&xxhState, srcBuffer+srcStart, inBuff.pos);
1796 memcpy(copyBuffer+totalTestSize, srcBuffer+srcStart, inBuff.pos);
1797 totalTestSize += inBuff.pos;
1798 }
1799
1800 /* random flush operation, to mess around */
1801 if ((FUZ_rand(&lseed) & 15) == 0) {
1802 size_t const randomDstSize = FUZ_randomLength(&lseed, maxSampleLog);
1803 size_t const adjustedDstSize = MIN(cBufferSize - cSize, randomDstSize);
Yann Collet2e233332018-01-16 15:28:43 -08001804 size_t const previousPos = outBuff.pos;
Yann Collet736788f2017-01-19 12:12:50 -08001805 outBuff.size = outBuff.pos + adjustedDstSize;
Yann Colletededcfc2018-12-21 16:19:44 -08001806 DISPLAYLEVEL(5, "Flushing into dst buffer of size %u \n", (unsigned)adjustedDstSize);
Yann Colletdce78922017-06-21 15:53:42 -07001807 CHECK_Z( ZSTDMT_flushStream(zc, &outBuff) );
Yann Collet2e233332018-01-16 15:28:43 -08001808 assert(outBuff.pos >= previousPos);
Yann Colletededcfc2018-12-21 16:19:44 -08001809 DISPLAYLEVEL(6, "%u bytes flushed by ZSTDMT_flushStream \n", (unsigned)(outBuff.pos-previousPos));
Yann Colletdce78922017-06-21 15:53:42 -07001810 } }
Yann Collet736788f2017-01-19 12:12:50 -08001811
1812 /* final frame epilogue */
1813 { size_t remainingToFlush = (size_t)(-1);
1814 while (remainingToFlush) {
1815 size_t const randomDstSize = FUZ_randomLength(&lseed, maxSampleLog);
1816 size_t const adjustedDstSize = MIN(cBufferSize - cSize, randomDstSize);
Yann Collet2e233332018-01-16 15:28:43 -08001817 size_t const previousPos = outBuff.pos;
Yann Collet736788f2017-01-19 12:12:50 -08001818 outBuff.size = outBuff.pos + adjustedDstSize;
Yann Colletededcfc2018-12-21 16:19:44 -08001819 DISPLAYLEVEL(5, "Ending into dst buffer of size %u \n", (unsigned)adjustedDstSize);
Yann Collet736788f2017-01-19 12:12:50 -08001820 remainingToFlush = ZSTDMT_endStream(zc, &outBuff);
Yann Collet30c76982017-03-31 18:27:03 -07001821 CHECK (ZSTD_isError(remainingToFlush), "ZSTDMT_endStream error : %s", ZSTD_getErrorName(remainingToFlush));
Yann Collet2e233332018-01-16 15:28:43 -08001822 assert(outBuff.pos >= previousPos);
Yann Colletededcfc2018-12-21 16:19:44 -08001823 DISPLAYLEVEL(6, "%u bytes flushed by ZSTDMT_endStream \n", (unsigned)(outBuff.pos-previousPos));
1824 DISPLAYLEVEL(5, "endStream : remainingToFlush : %u \n", (unsigned)remainingToFlush);
Yann Collet736788f2017-01-19 12:12:50 -08001825 } }
Yann Collet736788f2017-01-19 12:12:50 -08001826 crcOrig = XXH64_digest(&xxhState);
1827 cSize = outBuff.pos;
Yann Collet3ad7d492018-01-19 17:35:08 -08001828 DISPLAYLEVEL(5, "Frame completed : %u bytes compressed into %u bytes \n",
Yann Colletededcfc2018-12-21 16:19:44 -08001829 (unsigned)totalTestSize, (unsigned)cSize);
Yann Collet736788f2017-01-19 12:12:50 -08001830 }
1831
1832 /* multi - fragments decompression test */
Yann Collet3ad7d492018-01-19 17:35:08 -08001833 assert(totalTestSize < dstBufferSize);
1834 memset(dstBuffer, 170, totalTestSize); /* init dest area */
Yann Collet736788f2017-01-19 12:12:50 -08001835 if (!dictSize /* don't reset if dictionary : could be different */ && (FUZ_rand(&lseed) & 1)) {
Yann Colletdce78922017-06-21 15:53:42 -07001836 CHECK_Z( ZSTD_resetDStream(zd) );
Yann Collet736788f2017-01-19 12:12:50 -08001837 } else {
Yann Colletdce78922017-06-21 15:53:42 -07001838 CHECK_Z( ZSTD_initDStream_usingDict(zd, dict, dictSize) );
Yann Collet736788f2017-01-19 12:12:50 -08001839 }
1840 { size_t decompressionResult = 1;
1841 ZSTD_inBuffer inBuff = { cBuffer, cSize, 0 };
1842 ZSTD_outBuffer outBuff= { dstBuffer, dstBufferSize, 0 };
1843 for (totalGenSize = 0 ; decompressionResult ; ) {
1844 size_t const readCSrcSize = FUZ_randomLength(&lseed, maxSampleLog);
1845 size_t const randomDstSize = FUZ_randomLength(&lseed, maxSampleLog);
1846 size_t const dstBuffSize = MIN(dstBufferSize - totalGenSize, randomDstSize);
1847 inBuff.size = inBuff.pos + readCSrcSize;
Yann Colletbfabd1d2017-09-27 01:01:11 -07001848 outBuff.size = outBuff.pos + dstBuffSize;
Yann Collet3ad7d492018-01-19 17:35:08 -08001849 DISPLAYLEVEL(6, "ZSTD_decompressStream input %u bytes into outBuff %u bytes \n",
Yann Colletededcfc2018-12-21 16:19:44 -08001850 (unsigned)readCSrcSize, (unsigned)dstBuffSize);
Yann Collet736788f2017-01-19 12:12:50 -08001851 decompressionResult = ZSTD_decompressStream(zd, &outBuff, &inBuff);
Yann Collet940634a2018-01-19 13:19:59 -08001852 if (ZSTD_isError(decompressionResult)) {
1853 DISPLAY("ZSTD_decompressStream error : %s \n", ZSTD_getErrorName(decompressionResult));
Yann Collet6f7280f2018-01-18 16:20:26 -08001854 findDiff(copyBuffer, dstBuffer, totalTestSize);
1855 }
Yann Collet736788f2017-01-19 12:12:50 -08001856 CHECK (ZSTD_isError(decompressionResult), "decompression error : %s", ZSTD_getErrorName(decompressionResult));
Yann Collet3ad7d492018-01-19 17:35:08 -08001857 DISPLAYLEVEL(6, "total ingested (inBuff.pos) = %u and produced (outBuff.pos) = %u \n",
Yann Colletededcfc2018-12-21 16:19:44 -08001858 (unsigned)inBuff.pos, (unsigned)outBuff.pos);
Yann Collet736788f2017-01-19 12:12:50 -08001859 }
Yann Colletededcfc2018-12-21 16:19:44 -08001860 CHECK (outBuff.pos != totalTestSize,
1861 "decompressed data : wrong size (%u != %u)",
1862 (unsigned)outBuff.pos, (unsigned)totalTestSize );
1863 CHECK (inBuff.pos != cSize,
1864 "compressed data should be fully read (%u != %u)",
1865 (unsigned)inBuff.pos, (unsigned)cSize );
Yann Collet736788f2017-01-19 12:12:50 -08001866 { U64 const crcDest = XXH64(dstBuffer, totalTestSize, 0);
1867 if (crcDest!=crcOrig) findDiff(copyBuffer, dstBuffer, totalTestSize);
1868 CHECK (crcDest!=crcOrig, "decompressed data corrupted");
1869 } }
1870
1871 /*===== noisy/erroneous src decompression test =====*/
1872
1873 /* add some noise */
1874 { U32 const nbNoiseChunks = (FUZ_rand(&lseed) & 7) + 2;
1875 U32 nn; for (nn=0; nn<nbNoiseChunks; nn++) {
1876 size_t const randomNoiseSize = FUZ_randomLength(&lseed, maxSampleLog);
1877 size_t const noiseSize = MIN((cSize/3) , randomNoiseSize);
1878 size_t const noiseStart = FUZ_rand(&lseed) % (srcBufferSize - noiseSize);
1879 size_t const cStart = FUZ_rand(&lseed) % (cSize - noiseSize);
1880 memcpy(cBuffer+cStart, srcBuffer+noiseStart, noiseSize);
1881 } }
1882
1883 /* try decompression on noisy data */
Yann Colletdce78922017-06-21 15:53:42 -07001884 CHECK_Z( ZSTD_initDStream(zd_noise) ); /* note : no dictionary */
Yann Collet736788f2017-01-19 12:12:50 -08001885 { ZSTD_inBuffer inBuff = { cBuffer, cSize, 0 };
1886 ZSTD_outBuffer outBuff= { dstBuffer, dstBufferSize, 0 };
1887 while (outBuff.pos < dstBufferSize) {
1888 size_t const randomCSrcSize = FUZ_randomLength(&lseed, maxSampleLog);
1889 size_t const randomDstSize = FUZ_randomLength(&lseed, maxSampleLog);
1890 size_t const adjustedDstSize = MIN(dstBufferSize - outBuff.pos, randomDstSize);
Nick Terrelld98bf492017-01-27 15:42:36 -08001891 size_t const adjustedCSrcSize = MIN(cSize - inBuff.pos, randomCSrcSize);
Yann Collet736788f2017-01-19 12:12:50 -08001892 outBuff.size = outBuff.pos + adjustedDstSize;
Nick Terrelld98bf492017-01-27 15:42:36 -08001893 inBuff.size = inBuff.pos + adjustedCSrcSize;
Yann Collet736788f2017-01-19 12:12:50 -08001894 { size_t const decompressError = ZSTD_decompressStream(zd, &outBuff, &inBuff);
1895 if (ZSTD_isError(decompressError)) break; /* error correctly detected */
Nick Terrelld98bf492017-01-27 15:42:36 -08001896 /* No forward progress possible */
1897 if (outBuff.pos < outBuff.size && inBuff.pos == cSize) break;
Yann Collet736788f2017-01-19 12:12:50 -08001898 } } } }
1899 DISPLAY("\r%u fuzzer tests completed \n", testNb);
1900
1901_cleanup:
1902 ZSTDMT_freeCCtx(zc);
1903 ZSTD_freeDStream(zd);
1904 ZSTD_freeDStream(zd_noise);
1905 free(cNoiseBuffer[0]);
1906 free(cNoiseBuffer[1]);
1907 free(cNoiseBuffer[2]);
1908 free(cNoiseBuffer[3]);
1909 free(cNoiseBuffer[4]);
1910 free(copyBuffer);
1911 free(cBuffer);
1912 free(dstBuffer);
1913 return result;
1914
1915_output_error:
1916 result = 1;
1917 goto _cleanup;
1918}
1919
Stella Lau73c73bf2017-08-21 12:41:19 -07001920/** If useOpaqueAPI, sets param in cctxParams.
1921 * Otherwise, sets the param in zc. */
1922static size_t setCCtxParameter(ZSTD_CCtx* zc, ZSTD_CCtx_params* cctxParams,
1923 ZSTD_cParameter param, unsigned value,
Yann Colletc9e8ee92018-06-18 19:20:37 -07001924 int useOpaqueAPI)
Stella Lau73c73bf2017-08-21 12:41:19 -07001925{
1926 if (useOpaqueAPI) {
Nick Terrell7ad7ba32019-02-19 17:41:56 -08001927 return ZSTD_CCtxParams_setParameter(cctxParams, param, value);
Stella Lau73c73bf2017-08-21 12:41:19 -07001928 } else {
1929 return ZSTD_CCtx_setParameter(zc, param, value);
1930 }
1931}
Yann Collet736788f2017-01-19 12:12:50 -08001932
Yann Colletd7a3bff2017-06-19 11:53:01 -07001933/* Tests for ZSTD_compress_generic() API */
Yann Colletededcfc2018-12-21 16:19:44 -08001934static int fuzzerTests_newAPI(U32 seed, int nbTests, int startTest,
Yann Colletc9e8ee92018-06-18 19:20:37 -07001935 double compressibility, int bigTests)
Yann Collet01743a32017-06-16 17:56:41 -07001936{
Yann Colletf99c2c12017-06-21 23:35:58 -07001937 U32 const maxSrcLog = bigTests ? 24 : 22;
Yann Collet01743a32017-06-16 17:56:41 -07001938 static const U32 maxSampleLog = 19;
1939 size_t const srcBufferSize = (size_t)1<<maxSrcLog;
1940 BYTE* cNoiseBuffer[5];
1941 size_t const copyBufferSize= srcBufferSize + (1<<maxSampleLog);
1942 BYTE* const copyBuffer = (BYTE*)malloc (copyBufferSize);
1943 size_t const cBufferSize = ZSTD_compressBound(srcBufferSize);
1944 BYTE* const cBuffer = (BYTE*)malloc (cBufferSize);
1945 size_t const dstBufferSize = srcBufferSize;
1946 BYTE* const dstBuffer = (BYTE*)malloc (dstBufferSize);
1947 U32 result = 0;
Yann Colletededcfc2018-12-21 16:19:44 -08001948 int testNb = 0;
Yann Collet01743a32017-06-16 17:56:41 -07001949 U32 coreSeed = seed;
1950 ZSTD_CCtx* zc = ZSTD_createCCtx(); /* will be reset sometimes */
1951 ZSTD_DStream* zd = ZSTD_createDStream(); /* will be reset sometimes */
1952 ZSTD_DStream* const zd_noise = ZSTD_createDStream();
Nick Terrell9a2f6f42017-11-29 19:11:12 -08001953 UTIL_time_t const startClock = UTIL_getTime();
Yann Colletd7a3bff2017-06-19 11:53:01 -07001954 const BYTE* dict = NULL; /* can keep same dict on 2 consecutive tests */
Yann Collet01743a32017-06-16 17:56:41 -07001955 size_t dictSize = 0;
1956 U32 oldTestLog = 0;
Yann Colletaa800c42017-09-27 18:00:15 -07001957 U32 windowLogMalus = 0; /* can survive between 2 loops */
1958 U32 const cLevelMax = bigTests ? (U32)ZSTD_maxCLevel()-1 : g_cLevelMax_smallTests;
1959 U32 const nbThreadsMax = bigTests ? 4 : 2;
Stella Lau023b24e2017-08-20 22:55:07 -07001960 ZSTD_CCtx_params* cctxParams = ZSTD_createCCtxParams();
Yann Collet01743a32017-06-16 17:56:41 -07001961
1962 /* allocations */
1963 cNoiseBuffer[0] = (BYTE*)malloc (srcBufferSize);
1964 cNoiseBuffer[1] = (BYTE*)malloc (srcBufferSize);
1965 cNoiseBuffer[2] = (BYTE*)malloc (srcBufferSize);
1966 cNoiseBuffer[3] = (BYTE*)malloc (srcBufferSize);
1967 cNoiseBuffer[4] = (BYTE*)malloc (srcBufferSize);
1968 CHECK (!cNoiseBuffer[0] || !cNoiseBuffer[1] || !cNoiseBuffer[2] || !cNoiseBuffer[3] || !cNoiseBuffer[4] ||
1969 !copyBuffer || !dstBuffer || !cBuffer || !zc || !zd || !zd_noise ,
1970 "Not enough memory, fuzzer tests cancelled");
1971
1972 /* Create initial samples */
1973 RDG_genBuffer(cNoiseBuffer[0], srcBufferSize, 0.00, 0., coreSeed); /* pure noise */
1974 RDG_genBuffer(cNoiseBuffer[1], srcBufferSize, 0.05, 0., coreSeed); /* barely compressible */
1975 RDG_genBuffer(cNoiseBuffer[2], srcBufferSize, compressibility, 0., coreSeed);
1976 RDG_genBuffer(cNoiseBuffer[3], srcBufferSize, 0.95, 0., coreSeed); /* highly compressible */
1977 RDG_genBuffer(cNoiseBuffer[4], srcBufferSize, 1.00, 0., coreSeed); /* sparse content */
1978 memset(copyBuffer, 0x65, copyBufferSize); /* make copyBuffer considered initialized */
Yann Colletdce78922017-06-21 15:53:42 -07001979 CHECK_Z( ZSTD_initDStream_usingDict(zd, NULL, 0) ); /* ensure at least one init */
Yann Collet01743a32017-06-16 17:56:41 -07001980
1981 /* catch up testNb */
1982 for (testNb=1; testNb < startTest; testNb++)
1983 FUZ_rand(&coreSeed);
1984
1985 /* test loop */
Nick Terrell9a2f6f42017-11-29 19:11:12 -08001986 for ( ; (testNb <= nbTests) || (UTIL_clockSpanMicro(startClock) < g_clockTime) ; testNb++ ) {
Yann Collet01743a32017-06-16 17:56:41 -07001987 U32 lseed;
Yann Colletc9e8ee92018-06-18 19:20:37 -07001988 int opaqueAPI;
Yann Collet01743a32017-06-16 17:56:41 -07001989 const BYTE* srcBuffer;
1990 size_t totalTestSize, totalGenSize, cSize;
1991 XXH64_state_t xxhState;
1992 U64 crcOrig;
1993 U32 resetAllowed = 1;
1994 size_t maxTestSize;
Nick Terrellca778222018-04-25 16:32:29 -07001995 ZSTD_parameters savedParams;
Yann Collet01743a32017-06-16 17:56:41 -07001996
1997 /* init */
1998 if (nbTests >= testNb) { DISPLAYUPDATE(2, "\r%6u/%6u ", testNb, nbTests); }
1999 else { DISPLAYUPDATE(2, "\r%6u ", testNb); }
2000 FUZ_rand(&coreSeed);
2001 lseed = coreSeed ^ prime32;
Yann Collet9b5b47a2017-09-28 01:25:40 -07002002 DISPLAYLEVEL(5, " *** Test %u *** \n", testNb);
Yann Colletc9e8ee92018-06-18 19:20:37 -07002003 opaqueAPI = FUZ_rand(&lseed) & 1;
Yann Collet01743a32017-06-16 17:56:41 -07002004
2005 /* states full reset (deliberately not synchronized) */
2006 /* some issues can only happen when reusing states */
2007 if ((FUZ_rand(&lseed) & 0xFF) == 131) {
2008 DISPLAYLEVEL(5, "Creating new context \n");
2009 ZSTD_freeCCtx(zc);
2010 zc = ZSTD_createCCtx();
Yann Collet62469c92018-06-19 20:14:03 -07002011 CHECK(zc == NULL, "ZSTD_createCCtx allocation error");
2012 resetAllowed = 0;
Yann Collet01743a32017-06-16 17:56:41 -07002013 }
2014 if ((FUZ_rand(&lseed) & 0xFF) == 132) {
2015 ZSTD_freeDStream(zd);
2016 zd = ZSTD_createDStream();
Yann Collet62469c92018-06-19 20:14:03 -07002017 CHECK(zd == NULL, "ZSTD_createDStream allocation error");
Yann Collet01743a32017-06-16 17:56:41 -07002018 ZSTD_initDStream_usingDict(zd, NULL, 0); /* ensure at least one init */
2019 }
2020
2021 /* srcBuffer selection [0-4] */
2022 { U32 buffNb = FUZ_rand(&lseed) & 0x7F;
2023 if (buffNb & 7) buffNb=2; /* most common : compressible (P) */
2024 else {
2025 buffNb >>= 3;
2026 if (buffNb & 7) {
2027 const U32 tnb[2] = { 1, 3 }; /* barely/highly compressible */
2028 buffNb = tnb[buffNb >> 3];
2029 } else {
2030 const U32 tnb[2] = { 0, 4 }; /* not compressible / sparse */
2031 buffNb = tnb[buffNb >> 3];
2032 } }
2033 srcBuffer = cNoiseBuffer[buffNb];
2034 }
2035
2036 /* compression init */
Yann Colletb7372932017-06-27 15:49:12 -07002037 CHECK_Z( ZSTD_CCtx_loadDictionary(zc, NULL, 0) ); /* cancel previous dict /*/
Yann Collet01743a32017-06-16 17:56:41 -07002038 if ((FUZ_rand(&lseed)&1) /* at beginning, to keep same nb of rand */
Yann Collet2108dec2018-06-01 15:18:32 -07002039 && oldTestLog /* at least one test happened */
2040 && resetAllowed) {
2041 /* just set a compression level */
Yann Collet01743a32017-06-16 17:56:41 -07002042 maxTestSize = FUZ_randomLength(&lseed, oldTestLog+2);
2043 if (maxTestSize >= srcBufferSize) maxTestSize = srcBufferSize-1;
Yann Collet01743a32017-06-16 17:56:41 -07002044 { int const compressionLevel = (FUZ_rand(&lseed) % 5) + 1;
Yann Collet2108dec2018-06-01 15:18:32 -07002045 DISPLAYLEVEL(5, "t%u : compression level : %i \n", testNb, compressionLevel);
Yann Collet3583d192018-12-05 17:26:02 -08002046 CHECK_Z (setCCtxParameter(zc, cctxParams, ZSTD_c_compressionLevel, compressionLevel, opaqueAPI) );
Yann Collet01743a32017-06-16 17:56:41 -07002047 }
2048 } else {
2049 U32 const testLog = FUZ_rand(&lseed) % maxSrcLog;
2050 U32 const dictLog = FUZ_rand(&lseed) % maxSrcLog;
Yann Colletbfc2f002017-06-21 17:57:14 -07002051 U32 const cLevelCandidate = (FUZ_rand(&lseed) %
Yann Collet01743a32017-06-16 17:56:41 -07002052 (ZSTD_maxCLevel() -
Yann Collet9fe50ed2017-09-28 01:42:06 -07002053 (MAX(testLog, dictLog) / 2))) +
Yann Collet01743a32017-06-16 17:56:41 -07002054 1;
Yann Colletededcfc2018-12-21 16:19:44 -08002055 int const cLevel = MIN(cLevelCandidate, cLevelMax);
2056 DISPLAYLEVEL(5, "t%i: base cLevel : %u \n", testNb, cLevel);
Yann Collet01743a32017-06-16 17:56:41 -07002057 maxTestSize = FUZ_rLogLength(&lseed, testLog);
Yann Colletededcfc2018-12-21 16:19:44 -08002058 DISPLAYLEVEL(5, "t%i: maxTestSize : %u \n", testNb, (unsigned)maxTestSize);
Yann Collet01743a32017-06-16 17:56:41 -07002059 oldTestLog = testLog;
2060 /* random dictionary selection */
2061 dictSize = ((FUZ_rand(&lseed)&63)==1) ? FUZ_rLogLength(&lseed, dictLog) : 0;
2062 { size_t const dictStart = FUZ_rand(&lseed) % (srcBufferSize - dictSize);
2063 dict = srcBuffer + dictStart;
Yann Colletd7a3bff2017-06-19 11:53:01 -07002064 if (!dictSize) dict=NULL;
Yann Collet01743a32017-06-16 17:56:41 -07002065 }
2066 { U64 const pledgedSrcSize = (FUZ_rand(&lseed) & 3) ? ZSTD_CONTENTSIZE_UNKNOWN : maxTestSize;
2067 ZSTD_compressionParameters cParams = ZSTD_getCParams(cLevel, pledgedSrcSize, dictSize);
Nick Terrell7ee910e2018-09-27 13:55:24 -07002068 const U32 windowLogMax = bigTests ? 24 : 20;
2069 const U32 searchLogMax = bigTests ? 15 : 13;
Yann Collet2108dec2018-06-01 15:18:32 -07002070 if (dictSize)
2071 DISPLAYLEVEL(5, "t%u: with dictionary of size : %zu \n", testNb, dictSize);
Yann Collet01743a32017-06-16 17:56:41 -07002072
2073 /* mess with compression parameters */
2074 cParams.windowLog += (FUZ_rand(&lseed) & 3) - 1;
Nick Terrellc233bdb2017-09-22 14:04:39 -07002075 cParams.windowLog = MIN(windowLogMax, cParams.windowLog);
Yann Collet01743a32017-06-16 17:56:41 -07002076 cParams.hashLog += (FUZ_rand(&lseed) & 3) - 1;
2077 cParams.chainLog += (FUZ_rand(&lseed) & 3) - 1;
2078 cParams.searchLog += (FUZ_rand(&lseed) & 3) - 1;
Nick Terrell7ee910e2018-09-27 13:55:24 -07002079 cParams.searchLog = MIN(searchLogMax, cParams.searchLog);
Yann Collete874dac2018-11-20 14:56:07 -08002080 cParams.minMatch += (FUZ_rand(&lseed) & 3) - 1;
Yann Colletaa800c42017-09-27 18:00:15 -07002081 cParams.targetLength = (U32)((cParams.targetLength + 1 ) * (0.5 + ((double)(FUZ_rand(&lseed) & 127) / 128)));
Yann Collet2108dec2018-06-01 15:18:32 -07002082 cParams = ZSTD_adjustCParams(cParams, pledgedSrcSize, dictSize);
Yann Collet01743a32017-06-16 17:56:41 -07002083
Yann Colletaa800c42017-09-27 18:00:15 -07002084 if (FUZ_rand(&lseed) & 1) {
Yann Colletd3c59ed2017-11-29 16:42:20 -08002085 DISPLAYLEVEL(5, "t%u: windowLog : %u \n", testNb, cParams.windowLog);
Yann Collet3583d192018-12-05 17:26:02 -08002086 CHECK_Z( setCCtxParameter(zc, cctxParams, ZSTD_c_windowLog, cParams.windowLog, opaqueAPI) );
Yann Colletaa800c42017-09-27 18:00:15 -07002087 assert(cParams.windowLog >= ZSTD_WINDOWLOG_MIN); /* guaranteed by ZSTD_adjustCParams() */
2088 windowLogMalus = (cParams.windowLog - ZSTD_WINDOWLOG_MIN) / 5;
2089 }
Yann Collet9b5b47a2017-09-28 01:25:40 -07002090 if (FUZ_rand(&lseed) & 1) {
Yann Collet9b5b47a2017-09-28 01:25:40 -07002091 DISPLAYLEVEL(5, "t%u: hashLog : %u \n", testNb, cParams.hashLog);
Yann Collet3583d192018-12-05 17:26:02 -08002092 CHECK_Z( setCCtxParameter(zc, cctxParams, ZSTD_c_hashLog, cParams.hashLog, opaqueAPI) );
Yann Collet9b5b47a2017-09-28 01:25:40 -07002093 }
2094 if (FUZ_rand(&lseed) & 1) {
Yann Collet9b5b47a2017-09-28 01:25:40 -07002095 DISPLAYLEVEL(5, "t%u: chainLog : %u \n", testNb, cParams.chainLog);
Yann Collet3583d192018-12-05 17:26:02 -08002096 CHECK_Z( setCCtxParameter(zc, cctxParams, ZSTD_c_chainLog, cParams.chainLog, opaqueAPI) );
Yann Collet9b5b47a2017-09-28 01:25:40 -07002097 }
Yann Collet3583d192018-12-05 17:26:02 -08002098 if (FUZ_rand(&lseed) & 1) CHECK_Z( setCCtxParameter(zc, cctxParams, ZSTD_c_searchLog, cParams.searchLog, opaqueAPI) );
2099 if (FUZ_rand(&lseed) & 1) CHECK_Z( setCCtxParameter(zc, cctxParams, ZSTD_c_minMatch, cParams.minMatch, opaqueAPI) );
2100 if (FUZ_rand(&lseed) & 1) CHECK_Z( setCCtxParameter(zc, cctxParams, ZSTD_c_targetLength, cParams.targetLength, opaqueAPI) );
Yann Collet01743a32017-06-16 17:56:41 -07002101
Stella Lau9e406022017-09-06 08:39:46 -07002102 /* mess with long distance matching parameters */
Yann Colletd3c59ed2017-11-29 16:42:20 -08002103 if (bigTests) {
Yann Collet3583d192018-12-05 17:26:02 -08002104 if (FUZ_rand(&lseed) & 1) CHECK_Z( setCCtxParameter(zc, cctxParams, ZSTD_c_enableLongDistanceMatching, FUZ_rand(&lseed) & 63, opaqueAPI) );
2105 if (FUZ_rand(&lseed) & 3) CHECK_Z( setCCtxParameter(zc, cctxParams, ZSTD_c_ldmHashLog, FUZ_randomClampedLength(&lseed, ZSTD_HASHLOG_MIN, 23), opaqueAPI) );
2106 if (FUZ_rand(&lseed) & 3) CHECK_Z( setCCtxParameter(zc, cctxParams, ZSTD_c_ldmMinMatch, FUZ_randomClampedLength(&lseed, ZSTD_LDM_MINMATCH_MIN, ZSTD_LDM_MINMATCH_MAX), opaqueAPI) );
2107 if (FUZ_rand(&lseed) & 3) CHECK_Z( setCCtxParameter(zc, cctxParams, ZSTD_c_ldmBucketSizeLog, FUZ_randomClampedLength(&lseed, ZSTD_LDM_BUCKETSIZELOG_MIN, ZSTD_LDM_BUCKETSIZELOG_MAX), opaqueAPI) );
2108 if (FUZ_rand(&lseed) & 3) CHECK_Z( setCCtxParameter(zc, cctxParams, ZSTD_c_ldmHashRateLog, FUZ_randomClampedLength(&lseed, ZSTD_LDM_HASHRATELOG_MIN, ZSTD_LDM_HASHRATELOG_MAX), opaqueAPI) );
Nick Magerkoc7a24d72019-08-20 13:06:15 -07002109 if (FUZ_rand(&lseed) & 3) CHECK_Z( setCCtxParameter(zc, cctxParams, ZSTD_c_srcSizeHint, FUZ_randomClampedLength(&lseed, ZSTD_SRCSIZEHINT_MIN, ZSTD_SRCSIZEHINT_MAX), opaqueAPI) );
Yann Colletd3c59ed2017-11-29 16:42:20 -08002110 }
Stella Lau6a546ef2017-07-28 15:51:33 -07002111
Yann Collet01743a32017-06-16 17:56:41 -07002112 /* mess with frame parameters */
Yann Colletebd955e2018-01-23 13:12:40 -08002113 if (FUZ_rand(&lseed) & 1) {
Yann Colletededcfc2018-12-21 16:19:44 -08002114 int const checksumFlag = FUZ_rand(&lseed) & 1;
Yann Colletebd955e2018-01-23 13:12:40 -08002115 DISPLAYLEVEL(5, "t%u: frame checksum : %u \n", testNb, checksumFlag);
Yann Collet3583d192018-12-05 17:26:02 -08002116 CHECK_Z( setCCtxParameter(zc, cctxParams, ZSTD_c_checksumFlag, checksumFlag, opaqueAPI) );
Yann Colletebd955e2018-01-23 13:12:40 -08002117 }
Yann Collet3583d192018-12-05 17:26:02 -08002118 if (FUZ_rand(&lseed) & 1) CHECK_Z( setCCtxParameter(zc, cctxParams, ZSTD_c_dictIDFlag, FUZ_rand(&lseed) & 1, opaqueAPI) );
2119 if (FUZ_rand(&lseed) & 1) CHECK_Z( setCCtxParameter(zc, cctxParams, ZSTD_c_contentSizeFlag, FUZ_rand(&lseed) & 1, opaqueAPI) );
Yann Colletd3c59ed2017-11-29 16:42:20 -08002120 if (FUZ_rand(&lseed) & 1) {
Yann Colletededcfc2018-12-21 16:19:44 -08002121 DISPLAYLEVEL(5, "t%u: pledgedSrcSize : %u \n", testNb, (unsigned)pledgedSrcSize);
Yann Colletd3c59ed2017-11-29 16:42:20 -08002122 CHECK_Z( ZSTD_CCtx_setPledgedSrcSize(zc, pledgedSrcSize) );
2123 }
Yann Collet01743a32017-06-16 17:56:41 -07002124
Josh Sorefa880ca22019-04-12 14:18:11 -04002125 /* multi-threading parameters. Only adjust occasionally for small tests. */
Nick Terrelld8c73cd2018-09-27 15:49:31 -07002126 if (bigTests || (FUZ_rand(&lseed) & 0xF) == 0xF) {
2127 U32 const nbThreadsCandidate = (FUZ_rand(&lseed) & 4) + 1;
Yann Colletaa800c42017-09-27 18:00:15 -07002128 U32 const nbThreadsAdjusted = (windowLogMalus < nbThreadsCandidate) ? nbThreadsCandidate - windowLogMalus : 1;
Yann Colletededcfc2018-12-21 16:19:44 -08002129 int const nbThreads = MIN(nbThreadsAdjusted, nbThreadsMax);
2130 DISPLAYLEVEL(5, "t%i: nbThreads : %u \n", testNb, nbThreads);
Yann Collet3583d192018-12-05 17:26:02 -08002131 CHECK_Z( setCCtxParameter(zc, cctxParams, ZSTD_c_nbWorkers, nbThreads, opaqueAPI) );
Yann Collet01743a32017-06-16 17:56:41 -07002132 if (nbThreads > 1) {
Yann Colleted1d0392017-06-19 11:07:33 -07002133 U32 const jobLog = FUZ_rand(&lseed) % (testLog+1);
Yann Collet9b784de2018-12-11 16:55:33 -08002134 CHECK_Z( setCCtxParameter(zc, cctxParams, ZSTD_c_overlapLog, FUZ_rand(&lseed) % 10, opaqueAPI) );
Yann Collet3583d192018-12-05 17:26:02 -08002135 CHECK_Z( setCCtxParameter(zc, cctxParams, ZSTD_c_jobSize, (U32)FUZ_rLogLength(&lseed, jobLog), opaqueAPI) );
Stella Lau023b24e2017-08-20 22:55:07 -07002136 }
2137 }
Nick Terrell71fe78c2018-11-14 13:53:14 -08002138 /* Enable rsyncable mode 1 in 4 times. */
Yann Collet3583d192018-12-05 17:26:02 -08002139 setCCtxParameter(zc, cctxParams, ZSTD_c_rsyncable, (FUZ_rand(&lseed) % 4 == 0), opaqueAPI);
Stella Lau023b24e2017-08-20 22:55:07 -07002140
Yann Collet3583d192018-12-05 17:26:02 -08002141 if (FUZ_rand(&lseed) & 1) CHECK_Z( setCCtxParameter(zc, cctxParams, ZSTD_c_forceMaxWindow, FUZ_rand(&lseed) & 1, opaqueAPI) );
Stella Lau023b24e2017-08-20 22:55:07 -07002142
2143 /* Apply parameters */
Yann Colletc9e8ee92018-06-18 19:20:37 -07002144 if (opaqueAPI) {
Yann Collet2108dec2018-06-01 15:18:32 -07002145 DISPLAYLEVEL(5, "t%u: applying CCtxParams \n", testNb);
Stella Lau82d636b2017-08-29 18:03:06 -07002146 CHECK_Z (ZSTD_CCtx_setParametersUsingCCtxParams(zc, cctxParams) );
Stella Lau73c73bf2017-08-21 12:41:19 -07002147 }
Stella Lau023b24e2017-08-20 22:55:07 -07002148
2149 if (FUZ_rand(&lseed) & 1) {
Stella Laueb7bbab2017-08-25 10:48:07 -07002150 if (FUZ_rand(&lseed) & 1) {
2151 CHECK_Z( ZSTD_CCtx_loadDictionary(zc, dict, dictSize) );
2152 } else {
2153 CHECK_Z( ZSTD_CCtx_loadDictionary_byReference(zc, dict, dictSize) );
2154 }
Stella Lau73c73bf2017-08-21 12:41:19 -07002155 } else {
Stella Lau023b24e2017-08-20 22:55:07 -07002156 CHECK_Z( ZSTD_CCtx_refPrefix(zc, dict, dictSize) );
2157 }
2158 } }
Yann Collet01743a32017-06-16 17:56:41 -07002159
Nick Terrellca778222018-04-25 16:32:29 -07002160 CHECK_Z(getCCtxParams(zc, &savedParams));
2161
Yann Collet01743a32017-06-16 17:56:41 -07002162 /* multi-segments compression test */
2163 XXH64_reset(&xxhState, 0);
2164 { ZSTD_outBuffer outBuff = { cBuffer, cBufferSize, 0 } ;
Yann Collet052a95f2017-07-11 17:18:26 -07002165 for (cSize=0, totalTestSize=0 ; (totalTestSize < maxTestSize) ; ) {
Yann Collet01743a32017-06-16 17:56:41 -07002166 /* compress random chunks into randomly sized dst buffers */
Yann Colleted1d0392017-06-19 11:07:33 -07002167 size_t const randomSrcSize = FUZ_randomLength(&lseed, maxSampleLog);
2168 size_t const srcSize = MIN(maxTestSize-totalTestSize, randomSrcSize);
2169 size_t const srcStart = FUZ_rand(&lseed) % (srcBufferSize - srcSize);
Yann Collet052a95f2017-07-11 17:18:26 -07002170 size_t const randomDstSize = FUZ_randomLength(&lseed, maxSampleLog+1);
Yann Colleted1d0392017-06-19 11:07:33 -07002171 size_t const dstBuffSize = MIN(cBufferSize - cSize, randomDstSize);
2172 ZSTD_EndDirective const flush = (FUZ_rand(&lseed) & 15) ? ZSTD_e_continue : ZSTD_e_flush;
2173 ZSTD_inBuffer inBuff = { srcBuffer+srcStart, srcSize, 0 };
2174 outBuff.size = outBuff.pos + dstBuffSize;
Yann Collet01743a32017-06-16 17:56:41 -07002175
Yann Colletd8e215c2018-11-30 11:16:26 -08002176 CHECK_Z( ZSTD_compressStream2(zc, &outBuff, &inBuff, flush) );
Yann Colletebd955e2018-01-23 13:12:40 -08002177 DISPLAYLEVEL(6, "t%u: compress consumed %u bytes (total : %u) ; flush: %u (total : %u) \n",
Yann Colletededcfc2018-12-21 16:19:44 -08002178 testNb, (unsigned)inBuff.pos, (unsigned)(totalTestSize + inBuff.pos), (unsigned)flush, (unsigned)outBuff.pos);
Yann Collet01743a32017-06-16 17:56:41 -07002179
Yann Colleted1d0392017-06-19 11:07:33 -07002180 XXH64_update(&xxhState, srcBuffer+srcStart, inBuff.pos);
2181 memcpy(copyBuffer+totalTestSize, srcBuffer+srcStart, inBuff.pos);
2182 totalTestSize += inBuff.pos;
2183 }
Yann Collet01743a32017-06-16 17:56:41 -07002184
2185 /* final frame epilogue */
Yann Colletebd955e2018-01-23 13:12:40 -08002186 { size_t remainingToFlush = 1;
Yann Collet01743a32017-06-16 17:56:41 -07002187 while (remainingToFlush) {
2188 ZSTD_inBuffer inBuff = { NULL, 0, 0 };
Yann Collet052a95f2017-07-11 17:18:26 -07002189 size_t const randomDstSize = FUZ_randomLength(&lseed, maxSampleLog+1);
Yann Collet01743a32017-06-16 17:56:41 -07002190 size_t const adjustedDstSize = MIN(cBufferSize - cSize, randomDstSize);
2191 outBuff.size = outBuff.pos + adjustedDstSize;
Yann Colletededcfc2018-12-21 16:19:44 -08002192 DISPLAYLEVEL(6, "t%u: End-flush into dst buffer of size %u \n", testNb, (unsigned)adjustedDstSize);
Yann Colletd8e215c2018-11-30 11:16:26 -08002193 remainingToFlush = ZSTD_compressStream2(zc, &outBuff, &inBuff, ZSTD_e_end);
Yann Colletededcfc2018-12-21 16:19:44 -08002194 DISPLAYLEVEL(6, "t%u: Total flushed so far : %u bytes \n", testNb, (unsigned)outBuff.pos);
Yann Colletd6770f82017-09-28 02:14:48 -07002195 CHECK( ZSTD_isError(remainingToFlush),
Yann Colletd8e215c2018-11-30 11:16:26 -08002196 "ZSTD_compressStream2 w/ ZSTD_e_end error : %s",
Yann Colletd6770f82017-09-28 02:14:48 -07002197 ZSTD_getErrorName(remainingToFlush) );
Yann Collet01743a32017-06-16 17:56:41 -07002198 } }
2199 crcOrig = XXH64_digest(&xxhState);
2200 cSize = outBuff.pos;
Yann Collet2108dec2018-06-01 15:18:32 -07002201 DISPLAYLEVEL(5, "Frame completed : %zu bytes \n", cSize);
Yann Collet01743a32017-06-16 17:56:41 -07002202 }
2203
Nick Terrellca778222018-04-25 16:32:29 -07002204 CHECK(badParameters(zc, savedParams), "CCtx params are wrong");
2205
Yann Collet01743a32017-06-16 17:56:41 -07002206 /* multi - fragments decompression test */
2207 if (!dictSize /* don't reset if dictionary : could be different */ && (FUZ_rand(&lseed) & 1)) {
Yann Colletededcfc2018-12-21 16:19:44 -08002208 DISPLAYLEVEL(5, "resetting DCtx (dict:%p) \n", dict);
Yann Colletdce78922017-06-21 15:53:42 -07002209 CHECK_Z( ZSTD_resetDStream(zd) );
Yann Collet01743a32017-06-16 17:56:41 -07002210 } else {
Yann Collet2108dec2018-06-01 15:18:32 -07002211 if (dictSize)
2212 DISPLAYLEVEL(5, "using dictionary of size %zu \n", dictSize);
Yann Colletdce78922017-06-21 15:53:42 -07002213 CHECK_Z( ZSTD_initDStream_usingDict(zd, dict, dictSize) );
Yann Collet01743a32017-06-16 17:56:41 -07002214 }
2215 { size_t decompressionResult = 1;
2216 ZSTD_inBuffer inBuff = { cBuffer, cSize, 0 };
2217 ZSTD_outBuffer outBuff= { dstBuffer, dstBufferSize, 0 };
2218 for (totalGenSize = 0 ; decompressionResult ; ) {
2219 size_t const readCSrcSize = FUZ_randomLength(&lseed, maxSampleLog);
2220 size_t const randomDstSize = FUZ_randomLength(&lseed, maxSampleLog);
2221 size_t const dstBuffSize = MIN(dstBufferSize - totalGenSize, randomDstSize);
2222 inBuff.size = inBuff.pos + readCSrcSize;
Yann Colletbfabd1d2017-09-27 01:01:11 -07002223 outBuff.size = outBuff.pos + dstBuffSize;
Yann Collet4f7c8962018-01-23 18:00:51 -08002224 DISPLAYLEVEL(6, "decompression presented %u new bytes (pos:%u/%u)\n",
Yann Colletededcfc2018-12-21 16:19:44 -08002225 (unsigned)readCSrcSize, (unsigned)inBuff.pos, (unsigned)cSize);
Yann Collet01743a32017-06-16 17:56:41 -07002226 decompressionResult = ZSTD_decompressStream(zd, &outBuff, &inBuff);
Yann Collet4f7c8962018-01-23 18:00:51 -08002227 DISPLAYLEVEL(6, "so far: consumed = %u, produced = %u \n",
Yann Colletededcfc2018-12-21 16:19:44 -08002228 (unsigned)inBuff.pos, (unsigned)outBuff.pos);
Yann Colletebd955e2018-01-23 13:12:40 -08002229 if (ZSTD_isError(decompressionResult)) {
2230 DISPLAY("ZSTD_decompressStream error : %s \n", ZSTD_getErrorName(decompressionResult));
2231 findDiff(copyBuffer, dstBuffer, totalTestSize);
2232 }
Yann Collet01743a32017-06-16 17:56:41 -07002233 CHECK (ZSTD_isError(decompressionResult), "decompression error : %s", ZSTD_getErrorName(decompressionResult));
Yann Colletededcfc2018-12-21 16:19:44 -08002234 CHECK (inBuff.pos > cSize, "ZSTD_decompressStream consumes too much input : %u > %u ", (unsigned)inBuff.pos, (unsigned)cSize);
Yann Collet01743a32017-06-16 17:56:41 -07002235 }
Yann Colletededcfc2018-12-21 16:19:44 -08002236 CHECK (inBuff.pos != cSize, "compressed data should be fully read (%u != %u)", (unsigned)inBuff.pos, (unsigned)cSize);
2237 CHECK (outBuff.pos != totalTestSize, "decompressed data : wrong size (%u != %u)", (unsigned)outBuff.pos, (unsigned)totalTestSize);
Yann Collet01743a32017-06-16 17:56:41 -07002238 { U64 const crcDest = XXH64(dstBuffer, totalTestSize, 0);
2239 if (crcDest!=crcOrig) findDiff(copyBuffer, dstBuffer, totalTestSize);
2240 CHECK (crcDest!=crcOrig, "decompressed data corrupted");
2241 } }
2242
2243 /*===== noisy/erroneous src decompression test =====*/
2244
2245 /* add some noise */
2246 { U32 const nbNoiseChunks = (FUZ_rand(&lseed) & 7) + 2;
2247 U32 nn; for (nn=0; nn<nbNoiseChunks; nn++) {
2248 size_t const randomNoiseSize = FUZ_randomLength(&lseed, maxSampleLog);
2249 size_t const noiseSize = MIN((cSize/3) , randomNoiseSize);
2250 size_t const noiseStart = FUZ_rand(&lseed) % (srcBufferSize - noiseSize);
2251 size_t const cStart = FUZ_rand(&lseed) % (cSize - noiseSize);
2252 memcpy(cBuffer+cStart, srcBuffer+noiseStart, noiseSize);
2253 } }
2254
2255 /* try decompression on noisy data */
Yann Colletdce78922017-06-21 15:53:42 -07002256 CHECK_Z( ZSTD_initDStream(zd_noise) ); /* note : no dictionary */
Yann Collet01743a32017-06-16 17:56:41 -07002257 { ZSTD_inBuffer inBuff = { cBuffer, cSize, 0 };
2258 ZSTD_outBuffer outBuff= { dstBuffer, dstBufferSize, 0 };
2259 while (outBuff.pos < dstBufferSize) {
2260 size_t const randomCSrcSize = FUZ_randomLength(&lseed, maxSampleLog);
2261 size_t const randomDstSize = FUZ_randomLength(&lseed, maxSampleLog);
2262 size_t const adjustedDstSize = MIN(dstBufferSize - outBuff.pos, randomDstSize);
2263 size_t const adjustedCSrcSize = MIN(cSize - inBuff.pos, randomCSrcSize);
2264 outBuff.size = outBuff.pos + adjustedDstSize;
2265 inBuff.size = inBuff.pos + adjustedCSrcSize;
2266 { size_t const decompressError = ZSTD_decompressStream(zd, &outBuff, &inBuff);
2267 if (ZSTD_isError(decompressError)) break; /* error correctly detected */
Yann Colleted1d0392017-06-19 11:07:33 -07002268 /* Good so far, but no more progress possible */
Yann Collet01743a32017-06-16 17:56:41 -07002269 if (outBuff.pos < outBuff.size && inBuff.pos == cSize) break;
2270 } } } }
Yann Collet8dee0ec2017-06-18 23:25:15 -07002271 DISPLAY("\r%u fuzzer tests completed \n", testNb-1);
Yann Collet01743a32017-06-16 17:56:41 -07002272
2273_cleanup:
2274 ZSTD_freeCCtx(zc);
2275 ZSTD_freeDStream(zd);
2276 ZSTD_freeDStream(zd_noise);
Stella Lau023b24e2017-08-20 22:55:07 -07002277 ZSTD_freeCCtxParams(cctxParams);
Yann Collet01743a32017-06-16 17:56:41 -07002278 free(cNoiseBuffer[0]);
2279 free(cNoiseBuffer[1]);
2280 free(cNoiseBuffer[2]);
2281 free(cNoiseBuffer[3]);
2282 free(cNoiseBuffer[4]);
2283 free(copyBuffer);
2284 free(cBuffer);
2285 free(dstBuffer);
2286 return result;
2287
2288_output_error:
2289 result = 1;
2290 goto _cleanup;
2291}
2292
Yann Colletd7883a22016-08-12 16:48:02 +02002293/*-*******************************************************
2294* Command line
2295*********************************************************/
Nick Terrellf2d6db42018-09-27 15:13:43 -07002296static int FUZ_usage(const char* programName)
Yann Colletd7883a22016-08-12 16:48:02 +02002297{
2298 DISPLAY( "Usage :\n");
2299 DISPLAY( " %s [args]\n", programName);
2300 DISPLAY( "\n");
2301 DISPLAY( "Arguments :\n");
2302 DISPLAY( " -i# : Nb of tests (default:%u) \n", nbTestsDefault);
2303 DISPLAY( " -s# : Select seed (default:prompt user)\n");
2304 DISPLAY( " -t# : Select starting test number (default:0)\n");
2305 DISPLAY( " -P# : Select compressibility in %% (default:%i%%)\n", FUZ_COMPRESSIBILITY_DEFAULT);
2306 DISPLAY( " -v : verbose\n");
2307 DISPLAY( " -p : pause at the end\n");
2308 DISPLAY( " -h : display help and exit\n");
2309 return 0;
2310}
2311
Yann Collet01743a32017-06-16 17:56:41 -07002312typedef enum { simple_api, mt_api, advanced_api } e_api;
Yann Colletd7883a22016-08-12 16:48:02 +02002313
2314int main(int argc, const char** argv)
2315{
Yann Colletbd88f632017-11-27 12:15:23 -08002316 U32 seed = 0;
2317 int seedset = 0;
Yann Colletd7883a22016-08-12 16:48:02 +02002318 int nbTests = nbTestsDefault;
2319 int testNb = 0;
2320 int proba = FUZ_COMPRESSIBILITY_DEFAULT;
Yann Colletbd88f632017-11-27 12:15:23 -08002321 int result = 0;
Yann Collet19d670b2017-01-19 15:32:07 -08002322 int mainPause = 0;
Yann Colletafb0aca2017-06-29 18:19:09 -07002323 int bigTests = (sizeof(size_t) == 8);
Yann Collet01743a32017-06-16 17:56:41 -07002324 e_api selected_api = simple_api;
Yann Collet19d670b2017-01-19 15:32:07 -08002325 const char* const programName = argv[0];
Yann Colletbd88f632017-11-27 12:15:23 -08002326 int argNb;
Yann Colletd7883a22016-08-12 16:48:02 +02002327
2328 /* Check command line */
2329 for(argNb=1; argNb<argc; argNb++) {
2330 const char* argument = argv[argNb];
Yann Colletbd88f632017-11-27 12:15:23 -08002331 assert(argument != NULL);
Yann Colletd7883a22016-08-12 16:48:02 +02002332
2333 /* Parsing commands. Aggregated commands are allowed */
2334 if (argument[0]=='-') {
Yann Colletd7883a22016-08-12 16:48:02 +02002335
Yann Collet47c6a952017-09-28 18:27:22 -07002336 if (!strcmp(argument, "--mt")) { selected_api=mt_api; testNb += !testNb; continue; }
2337 if (!strcmp(argument, "--newapi")) { selected_api=advanced_api; testNb += !testNb; continue; }
Sean Purcell7ebf2de2017-03-20 11:25:00 -07002338 if (!strcmp(argument, "--no-big-tests")) { bigTests=0; continue; }
Yann Collet19d670b2017-01-19 15:32:07 -08002339
2340 argument++;
Yann Colletd7883a22016-08-12 16:48:02 +02002341 while (*argument!=0) {
2342 switch(*argument)
2343 {
2344 case 'h':
2345 return FUZ_usage(programName);
Yann Collet736788f2017-01-19 12:12:50 -08002346
Yann Colletd7883a22016-08-12 16:48:02 +02002347 case 'v':
2348 argument++;
Yann Collet736788f2017-01-19 12:12:50 -08002349 g_displayLevel++;
Yann Colletd7883a22016-08-12 16:48:02 +02002350 break;
Yann Collet736788f2017-01-19 12:12:50 -08002351
Yann Colletd7883a22016-08-12 16:48:02 +02002352 case 'q':
2353 argument++;
2354 g_displayLevel--;
2355 break;
Yann Collet736788f2017-01-19 12:12:50 -08002356
Yann Colletd7883a22016-08-12 16:48:02 +02002357 case 'p': /* pause at the end */
2358 argument++;
2359 mainPause = 1;
2360 break;
2361
Yann Collet736788f2017-01-19 12:12:50 -08002362 case 'i': /* limit tests by nb of iterations (default) */
Yann Colletd7883a22016-08-12 16:48:02 +02002363 argument++;
Yann Colletef9999f2016-09-01 16:44:48 -07002364 nbTests=0; g_clockTime=0;
Yann Colletd7883a22016-08-12 16:48:02 +02002365 while ((*argument>='0') && (*argument<='9')) {
2366 nbTests *= 10;
2367 nbTests += *argument - '0';
2368 argument++;
2369 }
2370 break;
2371
Yann Collet736788f2017-01-19 12:12:50 -08002372 case 'T': /* limit tests by time */
Yann Colletd7883a22016-08-12 16:48:02 +02002373 argument++;
Yann Colletef9999f2016-09-01 16:44:48 -07002374 nbTests=0; g_clockTime=0;
Yann Colletd7883a22016-08-12 16:48:02 +02002375 while ((*argument>='0') && (*argument<='9')) {
Yann Colletef9999f2016-09-01 16:44:48 -07002376 g_clockTime *= 10;
2377 g_clockTime += *argument - '0';
Yann Colletd7883a22016-08-12 16:48:02 +02002378 argument++;
2379 }
Yann Colletbd88f632017-11-27 12:15:23 -08002380 if (*argument=='m') { /* -T1m == -T60 */
2381 g_clockTime *=60, argument++;
2382 if (*argument=='n') argument++; /* -T1mn == -T60 */
2383 } else if (*argument=='s') argument++; /* -T10s == -T10 */
Nick Terrell9a2f6f42017-11-29 19:11:12 -08002384 g_clockTime *= SEC_TO_MICRO;
Yann Colletd7883a22016-08-12 16:48:02 +02002385 break;
2386
Yann Collet736788f2017-01-19 12:12:50 -08002387 case 's': /* manually select seed */
Yann Colletd7883a22016-08-12 16:48:02 +02002388 argument++;
Yann Colletd7883a22016-08-12 16:48:02 +02002389 seedset=1;
Yann Colletbd88f632017-11-27 12:15:23 -08002390 seed=0;
Yann Colletd7883a22016-08-12 16:48:02 +02002391 while ((*argument>='0') && (*argument<='9')) {
2392 seed *= 10;
2393 seed += *argument - '0';
2394 argument++;
2395 }
2396 break;
2397
Yann Collet736788f2017-01-19 12:12:50 -08002398 case 't': /* select starting test number */
Yann Colletd7883a22016-08-12 16:48:02 +02002399 argument++;
2400 testNb=0;
2401 while ((*argument>='0') && (*argument<='9')) {
2402 testNb *= 10;
2403 testNb += *argument - '0';
2404 argument++;
2405 }
2406 break;
2407
2408 case 'P': /* compressibility % */
2409 argument++;
2410 proba=0;
2411 while ((*argument>='0') && (*argument<='9')) {
2412 proba *= 10;
2413 proba += *argument - '0';
2414 argument++;
2415 }
2416 if (proba<0) proba=0;
2417 if (proba>100) proba=100;
2418 break;
2419
2420 default:
2421 return FUZ_usage(programName);
2422 }
2423 } } } /* for(argNb=1; argNb<argc; argNb++) */
2424
2425 /* Get Seed */
Yann Colletbb855812016-08-25 19:11:11 +02002426 DISPLAY("Starting zstream tester (%i-bits, %s)\n", (int)(sizeof(size_t)*8), ZSTD_VERSION_STRING);
Yann Colletd7883a22016-08-12 16:48:02 +02002427
Yann Colletef9999f2016-09-01 16:44:48 -07002428 if (!seedset) {
2429 time_t const t = time(NULL);
2430 U32 const h = XXH32(&t, sizeof(t), 1);
2431 seed = h % 10000;
2432 }
2433
Yann Colletededcfc2018-12-21 16:19:44 -08002434 DISPLAY("Seed = %u\n", (unsigned)seed);
Yann Colletd7883a22016-08-12 16:48:02 +02002435 if (proba!=FUZ_COMPRESSIBILITY_DEFAULT) DISPLAY("Compressibility : %i%%\n", proba);
2436
2437 if (nbTests<=0) nbTests=1;
2438
2439 if (testNb==0) {
Yann Colletbd88f632017-11-27 12:15:23 -08002440 result = basicUnitTests(0, ((double)proba) / 100); /* constant seed for predictability */
Yann Collet4616fad2017-07-10 17:16:41 -07002441 }
Yann Colletd7883a22016-08-12 16:48:02 +02002442
Yann Collet01743a32017-06-16 17:56:41 -07002443 if (!result) {
2444 switch(selected_api)
2445 {
2446 case simple_api :
2447 result = fuzzerTests(seed, nbTests, testNb, ((double)proba) / 100, bigTests);
2448 break;
2449 case mt_api :
2450 result = fuzzerTests_MT(seed, nbTests, testNb, ((double)proba) / 100, bigTests);
2451 break;
2452 case advanced_api :
Yann Colletc9e8ee92018-06-18 19:20:37 -07002453 result = fuzzerTests_newAPI(seed, nbTests, testNb, ((double)proba) / 100, bigTests);
Yann Collet01743a32017-06-16 17:56:41 -07002454 break;
2455 default :
2456 assert(0); /* impossible */
2457 }
2458 }
Yann Colletd7883a22016-08-12 16:48:02 +02002459
2460 if (mainPause) {
2461 int unused;
2462 DISPLAY("Press Enter \n");
2463 unused = getchar();
2464 (void)unused;
2465 }
2466 return result;
2467}