blob: 14c4af82fb76c1fb5675829668cc70a3e17b72ed [file] [log] [blame]
Yann Collet32fb4072017-08-18 16:52:05 -07001/*
Elliott Hughes44aba642023-09-12 20:18:59 +00002 * Copyright (c) Meta Platforms, Inc. and affiliates.
Yann Collet4ded9e52016-08-30 10:04:33 -07003 * 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 */
Elliott Hughes44aba642023-09-12 20:18:59 +000028#include <time.h> /* time_t, time(), to randomize seed */
Yann Collet01743a32017-06-16 17:56:41 -070029#include <assert.h> /* assert */
Lzu Taofb6901b2019-04-12 21:28:17 +070030#include "timefn.h" /* UTIL_time_t, UTIL_getTime */
Yann Colletd7883a22016-08-12 16:48:02 +020031#include "mem.h"
sen40def702021-05-13 14:41:21 -040032#define ZSTD_DISABLE_DEPRECATE_WARNINGS /* No deprecation warnings, we still test some deprecated functions */
Yann Colleta5ffe3d2017-05-12 16:29:19 -070033#define ZSTD_STATIC_LINKING_ONLY /* ZSTD_maxCLevel, ZSTD_customMem, ZSTD_getDictID_fromFrame */
Yann Colletd7883a22016-08-12 16:48:02 +020034#include "zstd.h" /* ZSTD_compressBound */
Yann Collete795c8a2016-12-13 16:39:36 +010035#include "zstd_errors.h" /* ZSTD_error_srcSize_wrong */
Yann Collet33fce032017-01-16 19:46:22 -080036#include "zdict.h" /* ZDICT_trainFromBuffer */
Yann Colletd7883a22016-08-12 16:48:02 +020037#include "datagen.h" /* RDG_genBuffer */
Yann Colletef9999f2016-09-01 16:44:48 -070038#define XXH_STATIC_LINKING_ONLY /* XXH64_state_t */
Yann Colletd7883a22016-08-12 16:48:02 +020039#include "xxhash.h" /* XXH64_* */
Nick Terrelle600b5d2017-10-16 17:18:43 -070040#include "seqgen.h"
Nick Terrell9a2f6f42017-11-29 19:11:12 -080041#include "util.h"
Yann Collet59a71162019-04-10 12:37:03 -070042#include "timefn.h" /* UTIL_time_t, UTIL_clockSpanMicro, UTIL_getTime */
Elliott Hughes44aba642023-09-12 20:18:59 +000043#include "external_matchfinder.h" /* zstreamSequenceProducer, EMF_testCase */
Yann Colletd7883a22016-08-12 16:48:02 +020044
45/*-************************************
Yann Colletc9e8ee92018-06-18 19:20:37 -070046 * Constants
47 **************************************/
Yann Colletd7883a22016-08-12 16:48:02 +020048#define KB *(1U<<10)
49#define MB *(1U<<20)
50#define GB *(1U<<30)
51
Yann Colletededcfc2018-12-21 16:19:44 -080052static const int nbTestsDefault = 10000;
Yann Colletf99c2c12017-06-21 23:35:58 -070053static const U32 g_cLevelMax_smallTests = 10;
Yann Colletd7883a22016-08-12 16:48:02 +020054#define COMPRESSIBLE_NOISE_LENGTH (10 MB)
55#define FUZ_COMPRESSIBILITY_DEFAULT 50
Yann Collet33fce032017-01-16 19:46:22 -080056static const U32 prime32 = 2654435761U;
Yann Colletd7883a22016-08-12 16:48:02 +020057
58
Yann Colletd7883a22016-08-12 16:48:02 +020059/*-************************************
Yann Colletc9e8ee92018-06-18 19:20:37 -070060 * Display Macros
61 **************************************/
Yann Colletd7883a22016-08-12 16:48:02 +020062#define DISPLAY(...) fprintf(stderr, __VA_ARGS__)
Yann Collet0be6fd32017-05-08 16:08:01 -070063#define DISPLAYLEVEL(l, ...) if (g_displayLevel>=l) { \
64 DISPLAY(__VA_ARGS__); \
65 if (g_displayLevel>=4) fflush(stderr); }
Yann Colletd7883a22016-08-12 16:48:02 +020066static U32 g_displayLevel = 2;
67
Nick Terrell9a2f6f42017-11-29 19:11:12 -080068static const U64 g_refreshRate = SEC_TO_MICRO / 6;
69static UTIL_time_t g_displayClock = UTIL_TIME_INITIALIZER;
Yann Colletd7883a22016-08-12 16:48:02 +020070
Nick Terrell9a2f6f42017-11-29 19:11:12 -080071#define DISPLAYUPDATE(l, ...) if (g_displayLevel>=l) { \
72 if ((UTIL_clockSpanMicro(g_displayClock) > g_refreshRate) || (g_displayLevel>=4)) \
73 { g_displayClock = UTIL_getTime(); DISPLAY(__VA_ARGS__); \
74 if (g_displayLevel>=4) fflush(stderr); } }
75
76static U64 g_clockTime = 0;
Yann Colletd7883a22016-08-12 16:48:02 +020077
78
79/*-*******************************************************
Yann Colletc9e8ee92018-06-18 19:20:37 -070080 * Check macros
81 *********************************************************/
Nick Terrell9a2f6f42017-11-29 19:11:12 -080082#undef MIN
83#undef MAX
84#define MIN(a,b) ((a)<(b)?(a):(b))
Yann Colletd7883a22016-08-12 16:48:02 +020085#define MAX(a,b) ((a)>(b)?(a):(b))
Yann Colletd7883a22016-08-12 16:48:02 +020086/*! FUZ_rand() :
87 @return : a 27 bits random value, from a 32-bits `seed`.
88 `seed` is also modified */
Yann Collet95162342016-10-25 16:19:52 -070089#define FUZ_rotl32(x,r) ((x << r) | (x >> (32 - r)))
Yann Colletededcfc2018-12-21 16:19:44 -080090static U32 FUZ_rand(U32* seedPtr)
Yann Colletd7883a22016-08-12 16:48:02 +020091{
Yann Collet33fce032017-01-16 19:46:22 -080092 static const U32 prime2 = 2246822519U;
Yann Colletd7883a22016-08-12 16:48:02 +020093 U32 rand32 = *seedPtr;
Yann Collet33fce032017-01-16 19:46:22 -080094 rand32 *= prime32;
Yann Colletd7883a22016-08-12 16:48:02 +020095 rand32 += prime2;
96 rand32 = FUZ_rotl32(rand32, 13);
97 *seedPtr = rand32;
98 return rand32 >> 5;
99}
100
Nick Terrelle600b5d2017-10-16 17:18:43 -0700101#define CHECK(cond, ...) { \
102 if (cond) { \
103 DISPLAY("Error => "); \
104 DISPLAY(__VA_ARGS__); \
Yann Colletebd955e2018-01-23 13:12:40 -0800105 DISPLAY(" (seed %u, test nb %u, line %u) \n", \
Yann Colletededcfc2018-12-21 16:19:44 -0800106 (unsigned)seed, testNb, __LINE__); \
Yann Colletd6770f82017-09-28 02:14:48 -0700107 goto _output_error; \
108} }
109
Nick Terrelle600b5d2017-10-16 17:18:43 -0700110#define CHECK_Z(f) { \
111 size_t const err = f; \
112 CHECK(ZSTD_isError(err), "%s : %s ", \
113 #f, ZSTD_getErrorName(err)); \
114}
115
Nick Terrellca778222018-04-25 16:32:29 -0700116#define CHECK_RET(ret, cond, ...) { \
117 if (cond) { \
118 DISPLAY("Error %llu => ", (unsigned long long)ret); \
119 DISPLAY(__VA_ARGS__); \
120 DISPLAY(" (line %u)\n", __LINE__); \
121 return ret; \
122} }
123
124#define CHECK_RET_Z(f) { \
125 size_t const err = f; \
126 CHECK_RET(err, ZSTD_isError(err), "%s : %s ", \
127 #f, ZSTD_getErrorName(err)); \
128}
129
Yann Colletcb327632016-08-23 00:30:31 +0200130
131/*======================================================
Yann Colletc9e8ee92018-06-18 19:20:37 -0700132 * Basic Unit tests
133 *======================================================*/
Yann Colletcb327632016-08-23 00:30:31 +0200134
Yann Collet33fce032017-01-16 19:46:22 -0800135typedef struct {
136 void* start;
137 size_t size;
138 size_t filled;
139} buffer_t;
140
Yann Colletd195eec2018-09-13 12:29:52 -0700141static const buffer_t kBuffNull = { NULL, 0 , 0 };
142
143static void FUZ_freeDictionary(buffer_t dict)
144{
145 free(dict.start);
146}
Yann Collet33fce032017-01-16 19:46:22 -0800147
148static buffer_t FUZ_createDictionary(const void* src, size_t srcSize, size_t blockSize, size_t requestedDictSize)
149{
Yann Colletd195eec2018-09-13 12:29:52 -0700150 buffer_t dict = kBuffNull;
Yann Collet33fce032017-01-16 19:46:22 -0800151 size_t const nbBlocks = (srcSize + (blockSize-1)) / blockSize;
Yann Colletd195eec2018-09-13 12:29:52 -0700152 size_t* const blockSizes = (size_t*)malloc(nbBlocks * sizeof(size_t));
153 if (!blockSizes) return kBuffNull;
Yann Collet33fce032017-01-16 19:46:22 -0800154 dict.start = malloc(requestedDictSize);
Yann Colletd195eec2018-09-13 12:29:52 -0700155 if (!dict.start) { free(blockSizes); return kBuffNull; }
Yann Collet33fce032017-01-16 19:46:22 -0800156 { size_t nb;
157 for (nb=0; nb<nbBlocks-1; nb++) blockSizes[nb] = blockSize;
158 blockSizes[nbBlocks-1] = srcSize - (blockSize * (nbBlocks-1));
159 }
160 { size_t const dictSize = ZDICT_trainFromBuffer(dict.start, requestedDictSize, src, blockSizes, (unsigned)nbBlocks);
161 free(blockSizes);
Yann Colletd195eec2018-09-13 12:29:52 -0700162 if (ZDICT_isError(dictSize)) { FUZ_freeDictionary(dict); return kBuffNull; }
Yann Collet33fce032017-01-16 19:46:22 -0800163 dict.size = requestedDictSize;
164 dict.filled = dictSize;
Yann Colletd195eec2018-09-13 12:29:52 -0700165 return dict;
Yann Collet33fce032017-01-16 19:46:22 -0800166 }
167}
168
Nick Terrelle600b5d2017-10-16 17:18:43 -0700169/* Round trips data and updates xxh with the decompressed data produced */
170static size_t SEQ_roundTrip(ZSTD_CCtx* cctx, ZSTD_DCtx* dctx,
171 XXH64_state_t* xxh, void* data, size_t size,
172 ZSTD_EndDirective endOp)
173{
174 static BYTE compressed[1024];
175 static BYTE uncompressed[1024];
176
177 ZSTD_inBuffer cin = {data, size, 0};
178 size_t cret;
179
180 do {
Yann Colletd8e215c2018-11-30 11:16:26 -0800181 ZSTD_outBuffer cout = { compressed, sizeof(compressed), 0 };
182 ZSTD_inBuffer din = { compressed, 0, 0 };
183 ZSTD_outBuffer dout = { uncompressed, 0, 0 };
Nick Terrelle600b5d2017-10-16 17:18:43 -0700184
Yann Colletd8e215c2018-11-30 11:16:26 -0800185 cret = ZSTD_compressStream2(cctx, &cout, &cin, endOp);
Nick Terrelle600b5d2017-10-16 17:18:43 -0700186 if (ZSTD_isError(cret))
187 return cret;
188
189 din.size = cout.pos;
190 while (din.pos < din.size || (endOp == ZSTD_e_end && cret == 0)) {
191 size_t dret;
192
193 dout.pos = 0;
194 dout.size = sizeof(uncompressed);
195 dret = ZSTD_decompressStream(dctx, &dout, &din);
196 if (ZSTD_isError(dret))
197 return dret;
198 XXH64_update(xxh, dout.dst, dout.pos);
199 if (dret == 0)
200 break;
201 }
202 } while (cin.pos < cin.size || (endOp != ZSTD_e_continue && cret != 0));
203 return 0;
204}
205
206/* Generates some data and round trips it */
207static size_t SEQ_generateRoundTrip(ZSTD_CCtx* cctx, ZSTD_DCtx* dctx,
208 XXH64_state_t* xxh, SEQ_stream* seq,
209 SEQ_gen_type type, unsigned value)
210{
211 static BYTE data[1024];
212 size_t gen;
213
214 do {
215 SEQ_outBuffer sout = {data, sizeof(data), 0};
216 size_t ret;
217 gen = SEQ_gen(seq, type, value, &sout);
218
219 ret = SEQ_roundTrip(cctx, dctx, xxh, sout.dst, sout.pos, ZSTD_e_continue);
220 if (ZSTD_isError(ret))
221 return ret;
222 } while (gen != 0);
223
224 return 0;
225}
Yann Collet33fce032017-01-16 19:46:22 -0800226
Nick Terrellca778222018-04-25 16:32:29 -0700227static size_t getCCtxParams(ZSTD_CCtx* zc, ZSTD_parameters* savedParams)
228{
Yann Colletd4d4e102018-11-21 15:37:26 -0800229 int value;
Yann Collet3583d192018-12-05 17:26:02 -0800230 CHECK_RET_Z(ZSTD_CCtx_getParameter(zc, ZSTD_c_windowLog, (int*)&savedParams->cParams.windowLog));
231 CHECK_RET_Z(ZSTD_CCtx_getParameter(zc, ZSTD_c_hashLog, (int*)&savedParams->cParams.hashLog));
232 CHECK_RET_Z(ZSTD_CCtx_getParameter(zc, ZSTD_c_chainLog, (int*)&savedParams->cParams.chainLog));
233 CHECK_RET_Z(ZSTD_CCtx_getParameter(zc, ZSTD_c_searchLog, (int*)&savedParams->cParams.searchLog));
234 CHECK_RET_Z(ZSTD_CCtx_getParameter(zc, ZSTD_c_minMatch, (int*)&savedParams->cParams.minMatch));
235 CHECK_RET_Z(ZSTD_CCtx_getParameter(zc, ZSTD_c_targetLength, (int*)&savedParams->cParams.targetLength));
Yann Colletbe9e5612018-12-06 15:00:52 -0800236 CHECK_RET_Z(ZSTD_CCtx_getParameter(zc, ZSTD_c_strategy, &value));
Nick Terrellca778222018-04-25 16:32:29 -0700237 savedParams->cParams.strategy = value;
238
Yann Collet3583d192018-12-05 17:26:02 -0800239 CHECK_RET_Z(ZSTD_CCtx_getParameter(zc, ZSTD_c_checksumFlag, &savedParams->fParams.checksumFlag));
240 CHECK_RET_Z(ZSTD_CCtx_getParameter(zc, ZSTD_c_contentSizeFlag, &savedParams->fParams.contentSizeFlag));
241 CHECK_RET_Z(ZSTD_CCtx_getParameter(zc, ZSTD_c_dictIDFlag, &value));
Nick Terrellca778222018-04-25 16:32:29 -0700242 savedParams->fParams.noDictIDFlag = !value;
243 return 0;
244}
245
246static U32 badParameters(ZSTD_CCtx* zc, ZSTD_parameters const savedParams)
247{
248 ZSTD_parameters params;
249 if (ZSTD_isError(getCCtxParams(zc, &params))) return 10;
250 CHECK_RET(1, params.cParams.windowLog != savedParams.cParams.windowLog, "windowLog");
251 CHECK_RET(2, params.cParams.hashLog != savedParams.cParams.hashLog, "hashLog");
252 CHECK_RET(3, params.cParams.chainLog != savedParams.cParams.chainLog, "chainLog");
253 CHECK_RET(4, params.cParams.searchLog != savedParams.cParams.searchLog, "searchLog");
Yann Collete874dac2018-11-20 14:56:07 -0800254 CHECK_RET(5, params.cParams.minMatch != savedParams.cParams.minMatch, "minMatch");
Nick Terrellca778222018-04-25 16:32:29 -0700255 CHECK_RET(6, params.cParams.targetLength != savedParams.cParams.targetLength, "targetLength");
256
257 CHECK_RET(7, params.fParams.checksumFlag != savedParams.fParams.checksumFlag, "checksumFlag");
258 CHECK_RET(8, params.fParams.contentSizeFlag != savedParams.fParams.contentSizeFlag, "contentSizeFlag");
259 CHECK_RET(9, params.fParams.noDictIDFlag != savedParams.fParams.noDictIDFlag, "noDictIDFlag");
260 return 0;
261}
262
Elliott Hughes44aba642023-09-12 20:18:59 +0000263static int basicUnitTests(U32 seed, double compressibility, int bigTests)
Yann Colletd7883a22016-08-12 16:48:02 +0200264{
Yann Colletb3060f72016-09-09 16:44:16 +0200265 size_t const CNBufferSize = COMPRESSIBLE_NOISE_LENGTH;
Yann Colletd7883a22016-08-12 16:48:02 +0200266 void* CNBuffer = malloc(CNBufferSize);
Nick Terrelle19b0822017-11-01 13:10:03 -0700267 size_t const skippableFrameSize = 200 KB;
Yann Colletd7883a22016-08-12 16:48:02 +0200268 size_t const compressedBufferSize = (8 + skippableFrameSize) + ZSTD_compressBound(COMPRESSIBLE_NOISE_LENGTH);
269 void* compressedBuffer = malloc(compressedBufferSize);
270 size_t const decodedBufferSize = CNBufferSize;
271 void* decodedBuffer = malloc(decodedBufferSize);
272 size_t cSize;
Yann Colletb3060f72016-09-09 16:44:16 +0200273 int testResult = 0;
Yann Colletededcfc2018-12-21 16:19:44 -0800274 int testNb = 1;
Yann Collet67113962018-01-19 22:11:11 -0800275 U32 coreSeed = 0; /* this name to conform with CHECK_Z macro display */
Yann Colletbd88f632017-11-27 12:15:23 -0800276 ZSTD_CStream* zc = ZSTD_createCStream();
277 ZSTD_DStream* zd = ZSTD_createDStream();
Nick Terrellc51a9e72020-10-01 18:47:54 -0700278 ZSTD_CCtx* mtctx = ZSTD_createCCtx();
Stella Lau90a31bf2017-08-30 14:36:54 -0700279
Yann Collet9ffbeea2016-12-02 18:37:38 -0800280 ZSTD_inBuffer inBuff, inBuff2;
Yann Collet53e17fb2016-08-17 01:39:22 +0200281 ZSTD_outBuffer outBuff;
Yann Colletd195eec2018-09-13 12:29:52 -0700282 buffer_t dictionary = kBuffNull;
Yann Collet30ab64e2017-05-10 11:30:19 -0700283 size_t const dictSize = 128 KB;
Yann Collet33fce032017-01-16 19:46:22 -0800284 unsigned dictID = 0;
Yann Colletd7883a22016-08-12 16:48:02 +0200285
286 /* Create compressible test buffer */
Nick Terrellc51a9e72020-10-01 18:47:54 -0700287 if (!CNBuffer || !compressedBuffer || !decodedBuffer || !zc || !zd || !mtctx) {
Yann Collet33fce032017-01-16 19:46:22 -0800288 DISPLAY("Not enough memory, aborting \n");
Yann Colletd7883a22016-08-12 16:48:02 +0200289 goto _output_error;
290 }
291 RDG_genBuffer(CNBuffer, CNBufferSize, compressibility, 0., seed);
292
Nick Terrellc51a9e72020-10-01 18:47:54 -0700293 CHECK_Z(ZSTD_CCtx_setParameter(mtctx, ZSTD_c_nbWorkers, 2));
294
Yann Collet33fce032017-01-16 19:46:22 -0800295 /* Create dictionary */
Yann Collete0065cf2017-09-28 18:34:38 -0700296 DISPLAYLEVEL(3, "creating dictionary for unit tests \n");
Yann Colletb18cb7e2018-03-20 16:18:48 -0700297 dictionary = FUZ_createDictionary(CNBuffer, CNBufferSize / 3, 16 KB, 48 KB);
Yann Collet33fce032017-01-16 19:46:22 -0800298 if (!dictionary.start) {
299 DISPLAY("Error creating dictionary, aborting \n");
300 goto _output_error;
301 }
302 dictID = ZDICT_getDictID(dictionary.start, dictionary.filled);
303
Yann Collet21f76722017-12-07 03:06:01 -0500304 /* Basic compression test */
305 DISPLAYLEVEL(3, "test%3i : compress %u bytes : ", testNb++, COMPRESSIBLE_NOISE_LENGTH);
306 CHECK_Z( ZSTD_initCStream(zc, 1 /* cLevel */) );
307 outBuff.dst = (char*)(compressedBuffer);
308 outBuff.size = compressedBufferSize;
309 outBuff.pos = 0;
310 inBuff.src = CNBuffer;
311 inBuff.size = CNBufferSize;
312 inBuff.pos = 0;
313 CHECK_Z( ZSTD_compressStream(zc, &outBuff, &inBuff) );
314 if (inBuff.pos != inBuff.size) goto _output_error; /* entire input should be consumed */
315 { size_t const r = ZSTD_endStream(zc, &outBuff);
316 if (r != 0) goto _output_error; } /* error, or some data not flushed */
Yann Colletededcfc2018-12-21 16:19:44 -0800317 DISPLAYLEVEL(3, "OK (%u bytes)\n", (unsigned)outBuff.pos);
Yann Collet21f76722017-12-07 03:06:01 -0500318
Yann Colletd7883a22016-08-12 16:48:02 +0200319 /* generate skippable frame */
320 MEM_writeLE32(compressedBuffer, ZSTD_MAGIC_SKIPPABLE_START);
321 MEM_writeLE32(((char*)compressedBuffer)+4, (U32)skippableFrameSize);
322 cSize = skippableFrameSize + 8;
323
Yann Collet21f76722017-12-07 03:06:01 -0500324 /* Basic compression test using dict */
325 DISPLAYLEVEL(3, "test%3i : skipframe + compress %u bytes : ", testNb++, COMPRESSIBLE_NOISE_LENGTH);
sen698f2612021-05-06 17:59:32 -0400326 CHECK_Z( ZSTD_CCtx_reset(zc, ZSTD_reset_session_only) );
327 CHECK_Z( ZSTD_CCtx_setParameter(zc, ZSTD_c_compressionLevel, 1) );
328 CHECK_Z( ZSTD_CCtx_loadDictionary(zc, CNBuffer, dictSize) );
Yann Collet53e17fb2016-08-17 01:39:22 +0200329 outBuff.dst = (char*)(compressedBuffer)+cSize;
Yann Collet3c1e3f82017-10-13 18:32:06 -0700330 assert(compressedBufferSize > cSize);
331 outBuff.size = compressedBufferSize - cSize;
Yann Collet53e17fb2016-08-17 01:39:22 +0200332 outBuff.pos = 0;
333 inBuff.src = CNBuffer;
334 inBuff.size = CNBufferSize;
335 inBuff.pos = 0;
Yann Colletd6770f82017-09-28 02:14:48 -0700336 CHECK_Z( ZSTD_compressStream(zc, &outBuff, &inBuff) );
Yann Collet53e17fb2016-08-17 01:39:22 +0200337 if (inBuff.pos != inBuff.size) goto _output_error; /* entire input should be consumed */
338 { size_t const r = ZSTD_endStream(zc, &outBuff);
Yann Collet9a021c12016-08-26 09:05:06 +0200339 if (r != 0) goto _output_error; } /* error, or some data not flushed */
Yann Collet53e17fb2016-08-17 01:39:22 +0200340 cSize += outBuff.pos;
Yann Colletededcfc2018-12-21 16:19:44 -0800341 DISPLAYLEVEL(3, "OK (%u bytes : %.2f%%)\n",
342 (unsigned)cSize, (double)cSize/COMPRESSIBLE_NOISE_LENGTH*100);
Yann Colletd7883a22016-08-12 16:48:02 +0200343
Yann Collet30ab64e2017-05-10 11:30:19 -0700344 /* context size functions */
345 DISPLAYLEVEL(3, "test%3i : estimate CStream size : ", testNb++);
346 { ZSTD_compressionParameters const cParams = ZSTD_getCParams(1, CNBufferSize, dictSize);
Yann Collet96f0cde2017-09-24 16:47:02 -0700347 size_t const cstreamSize = ZSTD_estimateCStreamSize_usingCParams(cParams);
348 size_t const cdictSize = ZSTD_estimateCDictSize_advanced(dictSize, cParams, ZSTD_dlm_byCopy); /* uses ZSTD_initCStream_usingDict() */
349 if (ZSTD_isError(cstreamSize)) goto _output_error;
350 if (ZSTD_isError(cdictSize)) goto _output_error;
Yann Colletededcfc2018-12-21 16:19:44 -0800351 DISPLAYLEVEL(3, "OK (%u bytes) \n", (unsigned)(cstreamSize + cdictSize));
Yann Collet30ab64e2017-05-10 11:30:19 -0700352 }
353
Nick Terrell56682a72019-04-01 17:51:28 -0700354 /* context size functions */
355 DISPLAYLEVEL(3, "test%3i : estimate CStream size using CCtxParams : ", testNb++);
356 { ZSTD_CCtx_params* const params = ZSTD_createCCtxParams();
357 size_t cstreamSize, cctxSize;
358 CHECK_Z( ZSTD_CCtxParams_setParameter(params, ZSTD_c_compressionLevel, 19) );
359 cstreamSize = ZSTD_estimateCStreamSize_usingCCtxParams(params);
360 CHECK_Z(cstreamSize);
361 cctxSize = ZSTD_estimateCCtxSize_usingCCtxParams(params);
362 CHECK_Z(cctxSize);
363 if (cstreamSize <= cctxSize + 2 * ZSTD_BLOCKSIZE_MAX) goto _output_error;
364 ZSTD_freeCCtxParams(params);
365 DISPLAYLEVEL(3, "OK \n");
366 }
367
Yann Collet30ab64e2017-05-10 11:30:19 -0700368 DISPLAYLEVEL(3, "test%3i : check actual CStream size : ", testNb++);
Yann Colletdce78922017-06-21 15:53:42 -0700369 { size_t const s = ZSTD_sizeof_CStream(zc);
370 if (ZSTD_isError(s)) goto _output_error;
Yann Colletededcfc2018-12-21 16:19:44 -0800371 DISPLAYLEVEL(3, "OK (%u bytes) \n", (unsigned)s);
Yann Colletcb327632016-08-23 00:30:31 +0200372 }
373
Yann Collet4b987ad2017-04-10 17:50:44 -0700374 /* Attempt bad compression parameters */
sen698f2612021-05-06 17:59:32 -0400375 DISPLAYLEVEL(3, "test%3i : use bad compression parameters with ZSTD_initCStream_advanced : ", testNb++);
Yann Collet4b987ad2017-04-10 17:50:44 -0700376 { size_t r;
377 ZSTD_parameters params = ZSTD_getParams(1, 0, 0);
Yann Collete874dac2018-11-20 14:56:07 -0800378 params.cParams.minMatch = 2;
Yann Collet4b987ad2017-04-10 17:50:44 -0700379 r = ZSTD_initCStream_advanced(zc, NULL, 0, params, 0);
380 if (!ZSTD_isError(r)) goto _output_error;
381 DISPLAYLEVEL(3, "init error : %s \n", ZSTD_getErrorName(r));
382 }
383
Yann Colletd7883a22016-08-12 16:48:02 +0200384 /* skippable frame test */
Yann Collet736788f2017-01-19 12:12:50 -0800385 DISPLAYLEVEL(3, "test%3i : decompress skippable frame : ", testNb++);
Yann Colletd6770f82017-09-28 02:14:48 -0700386 CHECK_Z( ZSTD_initDStream_usingDict(zd, CNBuffer, dictSize) );
Yann Collet53e17fb2016-08-17 01:39:22 +0200387 inBuff.src = compressedBuffer;
388 inBuff.size = cSize;
389 inBuff.pos = 0;
390 outBuff.dst = decodedBuffer;
391 outBuff.size = CNBufferSize;
392 outBuff.pos = 0;
Yann Colletdce78922017-06-21 15:53:42 -0700393 { size_t const r = ZSTD_decompressStream(zd, &outBuff, &inBuff);
Yann Colletededcfc2018-12-21 16:19:44 -0800394 DISPLAYLEVEL(5, " ( ZSTD_decompressStream => %u ) ", (unsigned)r);
Yann Colletdce78922017-06-21 15:53:42 -0700395 if (r != 0) goto _output_error;
396 }
Yann Colleta33ae642017-02-28 01:15:28 -0800397 if (outBuff.pos != 0) goto _output_error; /* skippable frame output len is 0 */
Yann Collet736788f2017-01-19 12:12:50 -0800398 DISPLAYLEVEL(3, "OK \n");
Yann Colletd7883a22016-08-12 16:48:02 +0200399
400 /* Basic decompression test */
Yann Collet9ffbeea2016-12-02 18:37:38 -0800401 inBuff2 = inBuff;
Yann Collet736788f2017-01-19 12:12:50 -0800402 DISPLAYLEVEL(3, "test%3i : decompress %u bytes : ", testNb++, COMPRESSIBLE_NOISE_LENGTH);
Yann Collet30ab64e2017-05-10 11:30:19 -0700403 ZSTD_initDStream_usingDict(zd, CNBuffer, dictSize);
Yann Collet3e042d52018-12-04 17:30:58 -0800404 CHECK_Z( ZSTD_DCtx_setParameter(zd, ZSTD_d_windowLogMax, ZSTD_WINDOWLOG_LIMIT_DEFAULT+1) ); /* large limit */
Yann Collet9ffbeea2016-12-02 18:37:38 -0800405 { size_t const remaining = ZSTD_decompressStream(zd, &outBuff, &inBuff);
406 if (remaining != 0) goto _output_error; } /* should reach end of frame == 0; otherwise, some data left, or an error */
407 if (outBuff.pos != CNBufferSize) goto _output_error; /* should regenerate the same amount */
408 if (inBuff.pos != inBuff.size) goto _output_error; /* should have read the entire frame */
Yann Collet736788f2017-01-19 12:12:50 -0800409 DISPLAYLEVEL(3, "OK \n");
Yann Collet9ffbeea2016-12-02 18:37:38 -0800410
411 /* Re-use without init */
Yann Collet736788f2017-01-19 12:12:50 -0800412 DISPLAYLEVEL(3, "test%3i : decompress again without init (re-use previous settings): ", testNb++);
Yann Collet9ffbeea2016-12-02 18:37:38 -0800413 outBuff.pos = 0;
414 { size_t const remaining = ZSTD_decompressStream(zd, &outBuff, &inBuff2);
415 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 +0200416 if (outBuff.pos != CNBufferSize) goto _output_error; /* should regenerate the same amount */
417 if (inBuff.pos != inBuff.size) goto _output_error; /* should have read the entire frame */
Yann Collet736788f2017-01-19 12:12:50 -0800418 DISPLAYLEVEL(3, "OK \n");
Yann Colletd7883a22016-08-12 16:48:02 +0200419
420 /* check regenerated data is byte exact */
Yann Collet736788f2017-01-19 12:12:50 -0800421 DISPLAYLEVEL(3, "test%3i : check decompressed result : ", testNb++);
Yann Colletd7883a22016-08-12 16:48:02 +0200422 { size_t i;
423 for (i=0; i<CNBufferSize; i++) {
424 if (((BYTE*)decodedBuffer)[i] != ((BYTE*)CNBuffer)[i]) goto _output_error;
425 } }
Yann Collet736788f2017-01-19 12:12:50 -0800426 DISPLAYLEVEL(3, "OK \n");
Yann Colletd7883a22016-08-12 16:48:02 +0200427
Elliott Hughes44aba642023-09-12 20:18:59 +0000428 /* check decompression fails early if first bytes are wrong */
429 DISPLAYLEVEL(3, "test%3i : early decompression error if first bytes are incorrect : ", testNb++);
430 { const char buf[3] = { 0 }; /* too short, not enough to start decoding header */
431 ZSTD_inBuffer inb = { buf, sizeof(buf), 0 };
432 size_t const remaining = ZSTD_decompressStream(zd, &outBuff, &inb);
433 if (!ZSTD_isError(remaining)) goto _output_error; /* should have errored out immediately (note: this does not test the exact error code) */
434 }
435 DISPLAYLEVEL(3, "OK \n");
436
Yann Colletf16f4492017-05-09 16:18:17 -0700437 /* context size functions */
438 DISPLAYLEVEL(3, "test%3i : estimate DStream size : ", testNb++);
439 { ZSTD_frameHeader fhi;
440 const void* cStart = (char*)compressedBuffer + (skippableFrameSize + 8);
441 size_t const gfhError = ZSTD_getFrameHeader(&fhi, cStart, cSize);
442 if (gfhError!=0) goto _output_error;
Yann Colletededcfc2018-12-21 16:19:44 -0800443 DISPLAYLEVEL(5, " (windowSize : %u) ", (unsigned)fhi.windowSize);
Yann Colletdde10b22017-06-26 17:44:26 -0700444 { size_t const s = ZSTD_estimateDStreamSize(fhi.windowSize)
Yann Collet25989e32017-05-25 15:07:37 -0700445 /* uses ZSTD_initDStream_usingDict() */
Stella Lauc88fb922017-08-29 11:55:02 -0700446 + ZSTD_estimateDDictSize(dictSize, ZSTD_dlm_byCopy);
Yann Colletf16f4492017-05-09 16:18:17 -0700447 if (ZSTD_isError(s)) goto _output_error;
Yann Colletededcfc2018-12-21 16:19:44 -0800448 DISPLAYLEVEL(3, "OK (%u bytes) \n", (unsigned)s);
Yann Colletf16f4492017-05-09 16:18:17 -0700449 } }
450
451 DISPLAYLEVEL(3, "test%3i : check actual DStream size : ", testNb++);
Yann Collet70e3b312016-08-23 01:18:06 +0200452 { size_t const s = ZSTD_sizeof_DStream(zd);
Yann Colletcb327632016-08-23 00:30:31 +0200453 if (ZSTD_isError(s)) goto _output_error;
Yann Colletededcfc2018-12-21 16:19:44 -0800454 DISPLAYLEVEL(3, "OK (%u bytes) \n", (unsigned)s);
Yann Colletcb327632016-08-23 00:30:31 +0200455 }
456
Yann Collet67113962018-01-19 22:11:11 -0800457 /* Decompression by small increment */
Yann Collet736788f2017-01-19 12:12:50 -0800458 DISPLAYLEVEL(3, "test%3i : decompress byte-by-byte : ", testNb++);
Yann Collet3ecbe6a2016-09-14 17:26:59 +0200459 { /* skippable frame */
460 size_t r = 1;
Yann Collet30ab64e2017-05-10 11:30:19 -0700461 ZSTD_initDStream_usingDict(zd, CNBuffer, dictSize);
Yann Collet53e17fb2016-08-17 01:39:22 +0200462 inBuff.src = compressedBuffer;
463 outBuff.dst = decodedBuffer;
464 inBuff.pos = 0;
465 outBuff.pos = 0;
Yann Colletd7883a22016-08-12 16:48:02 +0200466 while (r) { /* skippable frame */
Yann Collet31769ce2018-06-22 17:58:21 -0700467 size_t const inSize = (FUZ_rand(&coreSeed) & 15) + 1;
468 size_t const outSize = (FUZ_rand(&coreSeed) & 15) + 1;
Yann Collet67113962018-01-19 22:11:11 -0800469 inBuff.size = inBuff.pos + inSize;
470 outBuff.size = outBuff.pos + outSize;
Yann Collet53e17fb2016-08-17 01:39:22 +0200471 r = ZSTD_decompressStream(zd, &outBuff, &inBuff);
Yann Collet31769ce2018-06-22 17:58:21 -0700472 if (ZSTD_isError(r)) DISPLAYLEVEL(4, "ZSTD_decompressStream on skippable frame error : %s \n", ZSTD_getErrorName(r));
Yann Colletd7883a22016-08-12 16:48:02 +0200473 if (ZSTD_isError(r)) goto _output_error;
474 }
Yann Collet3ecbe6a2016-09-14 17:26:59 +0200475 /* normal frame */
Yann Collet30ab64e2017-05-10 11:30:19 -0700476 ZSTD_initDStream_usingDict(zd, CNBuffer, dictSize);
Yann Colletd7883a22016-08-12 16:48:02 +0200477 r=1;
Yann Collet3ecbe6a2016-09-14 17:26:59 +0200478 while (r) {
Yann Collet67113962018-01-19 22:11:11 -0800479 size_t const inSize = FUZ_rand(&coreSeed) & 15;
Yann Collet31769ce2018-06-22 17:58:21 -0700480 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 -0800481 inBuff.size = inBuff.pos + inSize;
482 outBuff.size = outBuff.pos + outSize;
Yann Collet53e17fb2016-08-17 01:39:22 +0200483 r = ZSTD_decompressStream(zd, &outBuff, &inBuff);
Yann Collet31769ce2018-06-22 17:58:21 -0700484 if (ZSTD_isError(r)) DISPLAYLEVEL(4, "ZSTD_decompressStream error : %s \n", ZSTD_getErrorName(r));
Yann Colletd7883a22016-08-12 16:48:02 +0200485 if (ZSTD_isError(r)) goto _output_error;
486 }
487 }
Yann Collet31769ce2018-06-22 17:58:21 -0700488 if (outBuff.pos != CNBufferSize) DISPLAYLEVEL(4, "outBuff.pos != CNBufferSize : should have regenerated same amount ! \n");
Yann Collet53e17fb2016-08-17 01:39:22 +0200489 if (outBuff.pos != CNBufferSize) goto _output_error; /* should regenerate the same amount */
Yann Collet31769ce2018-06-22 17:58:21 -0700490 if (inBuff.pos != cSize) DISPLAYLEVEL(4, "inBuff.pos != cSize : should have real all input ! \n");
Yann Collet53e17fb2016-08-17 01:39:22 +0200491 if (inBuff.pos != cSize) goto _output_error; /* should have read the entire frame */
Yann Collet736788f2017-01-19 12:12:50 -0800492 DISPLAYLEVEL(3, "OK \n");
Yann Colletd7883a22016-08-12 16:48:02 +0200493
494 /* check regenerated data is byte exact */
Yann Collet736788f2017-01-19 12:12:50 -0800495 DISPLAYLEVEL(3, "test%3i : check decompressed result : ", testNb++);
Yann Colletd7883a22016-08-12 16:48:02 +0200496 { size_t i;
497 for (i=0; i<CNBufferSize; i++) {
Ed Masteb81d7cc2019-08-15 21:17:06 -0400498 if (((BYTE*)decodedBuffer)[i] != ((BYTE*)CNBuffer)[i]) goto _output_error;
Yann Colletd7883a22016-08-12 16:48:02 +0200499 } }
Yann Collet736788f2017-01-19 12:12:50 -0800500 DISPLAYLEVEL(3, "OK \n");
Yann Colletd7883a22016-08-12 16:48:02 +0200501
Yann Collet31769ce2018-06-22 17:58:21 -0700502 /* Decompression forward progress */
503 DISPLAYLEVEL(3, "test%3i : generate error when ZSTD_decompressStream() doesn't progress : ", testNb++);
504 { /* skippable frame */
505 size_t r = 0;
506 int decNb = 0;
507 int const maxDec = 100;
508 inBuff.src = compressedBuffer;
509 inBuff.size = cSize;
510 inBuff.pos = 0;
511
512 outBuff.dst = decodedBuffer;
513 outBuff.pos = 0;
514 outBuff.size = CNBufferSize-1; /* 1 byte missing */
515
516 for (decNb=0; decNb<maxDec; decNb++) {
517 if (r==0) ZSTD_initDStream_usingDict(zd, CNBuffer, dictSize);
518 r = ZSTD_decompressStream(zd, &outBuff, &inBuff);
519 if (ZSTD_isError(r)) break;
520 }
521 if (!ZSTD_isError(r)) DISPLAYLEVEL(4, "ZSTD_decompressStream should have triggered a no_forward_progress error \n");
522 if (!ZSTD_isError(r)) goto _output_error; /* should have triggered no_forward_progress error */
523 }
524 DISPLAYLEVEL(3, "OK \n");
525
Elliott Hughes44aba642023-09-12 20:18:59 +0000526 DISPLAYLEVEL(3, "test%3i : NULL output and NULL input : ", testNb++);
Nick Terrell659e9f02019-11-20 18:21:51 -0800527 inBuff.src = NULL;
528 inBuff.size = 0;
529 inBuff.pos = 0;
530 outBuff.dst = NULL;
531 outBuff.size = 0;
532 outBuff.pos = 0;
533 CHECK_Z( ZSTD_compressStream(zc, &outBuff, &inBuff) );
534 CHECK(inBuff.pos != inBuff.size, "Entire input should be consumed");
535 CHECK_Z( ZSTD_endStream(zc, &outBuff) );
536 outBuff.dst = (char*)(compressedBuffer);
537 outBuff.size = compressedBufferSize;
538 outBuff.pos = 0;
539 { size_t const r = ZSTD_endStream(zc, &outBuff);
540 CHECK(r != 0, "Error or some data not flushed (ret=%zu)", r);
541 }
542 inBuff.src = outBuff.dst;
543 inBuff.size = outBuff.pos;
544 inBuff.pos = 0;
545 outBuff.dst = NULL;
546 outBuff.size = 0;
547 outBuff.pos = 0;
548 CHECK_Z( ZSTD_initDStream(zd) );
549 { size_t const ret = ZSTD_decompressStream(zd, &outBuff, &inBuff);
550 if (ret != 0) goto _output_error;
551 }
Danielle Rozenblita06e9532022-09-08 18:30:07 -0700552 DISPLAYLEVEL(3, "OK\n");
Elliott Hughes44aba642023-09-12 20:18:59 +0000553
554 DISPLAYLEVEL(3, "test%3i : NULL output buffer with non-NULL input : ", testNb++);
555 {
556 const char* test = "aa";
557 inBuff.src = test;
558 inBuff.size = 2;
559 inBuff.pos = 0;
560 outBuff.dst = NULL;
561 outBuff.size = 0;
562 outBuff.pos = 0;
563 CHECK_Z( ZSTD_compressStream(zc, &outBuff, &inBuff) );
564 CHECK(inBuff.pos != inBuff.size, "Entire input should be consumed");
565 CHECK_Z( ZSTD_endStream(zc, &outBuff) );
566 outBuff.dst = (char*)(compressedBuffer);
567 outBuff.size = compressedBufferSize;
568 outBuff.pos = 0;
569 { size_t const r = ZSTD_endStream(zc, &outBuff);
570 CHECK(r != 0, "Error or some data not flushed (ret=%zu)", r);
571 }
572 inBuff.src = outBuff.dst;
573 inBuff.size = outBuff.pos;
574 inBuff.pos = 0;
575 outBuff.dst = NULL;
576 outBuff.size = 0;
577 outBuff.pos = 0;
578 CHECK_Z( ZSTD_initDStream(zd) );
579 CHECK_Z(ZSTD_decompressStream(zd, &outBuff, &inBuff));
580 }
581
582 DISPLAYLEVEL(3, "OK\n");
Yann Collete795c8a2016-12-13 16:39:36 +0100583 /* _srcSize compression test */
Yann Collet736788f2017-01-19 12:12:50 -0800584 DISPLAYLEVEL(3, "test%3i : compress_srcSize %u bytes : ", testNb++, COMPRESSIBLE_NOISE_LENGTH);
sen698f2612021-05-06 17:59:32 -0400585 CHECK_Z( ZSTD_CCtx_reset(zc, ZSTD_reset_session_only) );
586 CHECK_Z( ZSTD_CCtx_refCDict(zc, NULL) );
587 CHECK_Z( ZSTD_CCtx_setParameter(zc, ZSTD_c_compressionLevel, 1) );
588 CHECK_Z( ZSTD_CCtx_setPledgedSrcSize(zc, CNBufferSize) );
Yann Colletd564faa2016-12-18 21:39:15 +0100589 outBuff.dst = (char*)(compressedBuffer);
Yann Collete795c8a2016-12-13 16:39:36 +0100590 outBuff.size = compressedBufferSize;
591 outBuff.pos = 0;
592 inBuff.src = CNBuffer;
593 inBuff.size = CNBufferSize;
594 inBuff.pos = 0;
Yann Colletd6770f82017-09-28 02:14:48 -0700595 CHECK_Z( ZSTD_compressStream(zc, &outBuff, &inBuff) );
Nick Terrelle55da9e2019-03-13 14:05:18 -0700596 CHECK(inBuff.pos != inBuff.size, "Entire input should be consumed");
597 { size_t const r = ZSTD_endStream(zc, &outBuff);
598 CHECK(r != 0, "Error or some data not flushed (ret=%zu)", r);
599 }
600 { unsigned long long origSize = ZSTD_findDecompressedSize(outBuff.dst, outBuff.pos);
601 CHECK(origSize == ZSTD_CONTENTSIZE_UNKNOWN, "Unknown!");
602 CHECK((size_t)origSize != CNBufferSize, "Exact original size must be present (got %llu)", origSize);
603 }
Yann Colletededcfc2018-12-21 16:19:44 -0800604 DISPLAYLEVEL(3, "OK (%u bytes : %.2f%%)\n", (unsigned)cSize, (double)cSize/COMPRESSIBLE_NOISE_LENGTH*100);
Yann Collete795c8a2016-12-13 16:39:36 +0100605
606 /* wrong _srcSize compression test */
Nick Terrell48acadd2018-02-01 12:04:05 -0800607 DISPLAYLEVEL(3, "test%3i : too large srcSize : %u bytes : ", testNb++, COMPRESSIBLE_NOISE_LENGTH-1);
sen698f2612021-05-06 17:59:32 -0400608 CHECK_Z( ZSTD_CCtx_reset(zc, ZSTD_reset_session_only) );
609 CHECK_Z( ZSTD_CCtx_refCDict(zc, NULL) );
610 CHECK_Z( ZSTD_CCtx_setParameter(zc, ZSTD_c_compressionLevel, 1) );
611 CHECK_Z( ZSTD_CCtx_setPledgedSrcSize(zc, CNBufferSize+1) );
Yann Colletd564faa2016-12-18 21:39:15 +0100612 outBuff.dst = (char*)(compressedBuffer);
Yann Collete795c8a2016-12-13 16:39:36 +0100613 outBuff.size = compressedBufferSize;
614 outBuff.pos = 0;
615 inBuff.src = CNBuffer;
616 inBuff.size = CNBufferSize;
617 inBuff.pos = 0;
Yann Colletd6770f82017-09-28 02:14:48 -0700618 CHECK_Z( ZSTD_compressStream(zc, &outBuff, &inBuff) );
Yann Collete795c8a2016-12-13 16:39:36 +0100619 if (inBuff.pos != inBuff.size) goto _output_error; /* entire input should be consumed */
620 { size_t const r = ZSTD_endStream(zc, &outBuff);
621 if (ZSTD_getErrorCode(r) != ZSTD_error_srcSize_wrong) goto _output_error; /* must fail : wrong srcSize */
Yann Collet736788f2017-01-19 12:12:50 -0800622 DISPLAYLEVEL(3, "OK (error detected : %s) \n", ZSTD_getErrorName(r)); }
Yann Collete795c8a2016-12-13 16:39:36 +0100623
Nick Terrell48acadd2018-02-01 12:04:05 -0800624 /* wrong _srcSize compression test */
625 DISPLAYLEVEL(3, "test%3i : too small srcSize : %u bytes : ", testNb++, COMPRESSIBLE_NOISE_LENGTH-1);
sen698f2612021-05-06 17:59:32 -0400626 CHECK_Z( ZSTD_CCtx_reset(zc, ZSTD_reset_session_only) );
627 CHECK_Z( ZSTD_CCtx_refCDict(zc, NULL) );
628 CHECK_Z( ZSTD_CCtx_setParameter(zc, ZSTD_c_compressionLevel, 1) );
629 CHECK_Z( ZSTD_CCtx_setPledgedSrcSize(zc, CNBufferSize-1) );
Nick Terrell48acadd2018-02-01 12:04:05 -0800630 outBuff.dst = (char*)(compressedBuffer);
631 outBuff.size = compressedBufferSize;
632 outBuff.pos = 0;
633 inBuff.src = CNBuffer;
634 inBuff.size = CNBufferSize;
635 inBuff.pos = 0;
636 { size_t const r = ZSTD_compressStream(zc, &outBuff, &inBuff);
637 if (ZSTD_getErrorCode(r) != ZSTD_error_srcSize_wrong) goto _output_error; /* must fail : wrong srcSize */
638 DISPLAYLEVEL(3, "OK (error detected : %s) \n", ZSTD_getErrorName(r));
639 }
640
Nick Terrell3c3f59e2018-04-12 16:02:03 -0700641 DISPLAYLEVEL(3, "test%3i : wrong srcSize !contentSizeFlag : %u bytes : ", testNb++, COMPRESSIBLE_NOISE_LENGTH-1);
sen698f2612021-05-06 17:59:32 -0400642 { CHECK_Z( ZSTD_CCtx_reset(zc, ZSTD_reset_session_only) );
643 CHECK_Z( ZSTD_CCtx_setParameter(zc, ZSTD_c_contentSizeFlag, 0) );
644 CHECK_Z( ZSTD_CCtx_setPledgedSrcSize(zc, CNBufferSize - MIN(CNBufferSize, 200 KB)) );
Nick Terrell3c3f59e2018-04-12 16:02:03 -0700645 outBuff.dst = (char*)compressedBuffer;
646 outBuff.size = compressedBufferSize;
647 outBuff.pos = 0;
648 inBuff.src = CNBuffer;
649 inBuff.size = CNBufferSize;
650 inBuff.pos = 0;
651 { size_t const r = ZSTD_compressStream(zc, &outBuff, &inBuff);
652 if (ZSTD_getErrorCode(r) != ZSTD_error_srcSize_wrong) goto _output_error; /* must fail : wrong srcSize */
653 DISPLAYLEVEL(3, "OK (error detected : %s) \n", ZSTD_getErrorName(r));
654 } }
655
Elliott Hughes44aba642023-09-12 20:18:59 +0000656 /* Compression state re-use scenario */
Yann Collet736788f2017-01-19 12:12:50 -0800657 DISPLAYLEVEL(3, "test%3i : context re-use : ", testNb++);
Yann Collet12083a42016-09-06 15:01:51 +0200658 ZSTD_freeCStream(zc);
Yann Colletbd88f632017-11-27 12:15:23 -0800659 zc = ZSTD_createCStream();
Yann Collet12083a42016-09-06 15:01:51 +0200660 if (zc==NULL) goto _output_error; /* memory allocation issue */
661 /* use 1 */
662 { size_t const inSize = 513;
Yann Collet0be6fd32017-05-08 16:08:01 -0700663 DISPLAYLEVEL(5, "use1 ");
sen698f2612021-05-06 17:59:32 -0400664 CHECK_Z( ZSTD_CCtx_reset(zc, ZSTD_reset_session_only) );
665 CHECK_Z( ZSTD_CCtx_setParameter(zc, ZSTD_c_compressionLevel, 19) );
666 CHECK_Z( ZSTD_CCtx_setPledgedSrcSize(zc, inSize) );
Yann Collet12083a42016-09-06 15:01:51 +0200667 inBuff.src = CNBuffer;
668 inBuff.size = inSize;
669 inBuff.pos = 0;
670 outBuff.dst = (char*)(compressedBuffer)+cSize;
671 outBuff.size = ZSTD_compressBound(inSize);
672 outBuff.pos = 0;
Yann Collet0be6fd32017-05-08 16:08:01 -0700673 DISPLAYLEVEL(5, "compress1 ");
Yann Colletd6770f82017-09-28 02:14:48 -0700674 CHECK_Z( ZSTD_compressStream(zc, &outBuff, &inBuff) );
Yann Collet12083a42016-09-06 15:01:51 +0200675 if (inBuff.pos != inBuff.size) goto _output_error; /* entire input should be consumed */
Yann Collet0be6fd32017-05-08 16:08:01 -0700676 DISPLAYLEVEL(5, "end1 ");
Elliott Hughes44aba642023-09-12 20:18:59 +0000677 if (ZSTD_endStream(zc, &outBuff) != 0) goto _output_error; /* error, or some data not flushed */
Yann Collet12083a42016-09-06 15:01:51 +0200678 }
679 /* use 2 */
680 { size_t const inSize = 1025; /* will not continue, because tables auto-adjust and are therefore different size */
Yann Collet0be6fd32017-05-08 16:08:01 -0700681 DISPLAYLEVEL(5, "use2 ");
sen698f2612021-05-06 17:59:32 -0400682 CHECK_Z( ZSTD_CCtx_reset(zc, ZSTD_reset_session_only) );
683 CHECK_Z( ZSTD_CCtx_setParameter(zc, ZSTD_c_compressionLevel, 19) );
684 CHECK_Z( ZSTD_CCtx_setPledgedSrcSize(zc, inSize) );
Yann Collet12083a42016-09-06 15:01:51 +0200685 inBuff.src = CNBuffer;
686 inBuff.size = inSize;
687 inBuff.pos = 0;
688 outBuff.dst = (char*)(compressedBuffer)+cSize;
689 outBuff.size = ZSTD_compressBound(inSize);
690 outBuff.pos = 0;
Yann Collet0be6fd32017-05-08 16:08:01 -0700691 DISPLAYLEVEL(5, "compress2 ");
Yann Colletd6770f82017-09-28 02:14:48 -0700692 CHECK_Z( ZSTD_compressStream(zc, &outBuff, &inBuff) );
Yann Collet12083a42016-09-06 15:01:51 +0200693 if (inBuff.pos != inBuff.size) goto _output_error; /* entire input should be consumed */
Yann Collet0be6fd32017-05-08 16:08:01 -0700694 DISPLAYLEVEL(5, "end2 ");
Elliott Hughes44aba642023-09-12 20:18:59 +0000695 if (ZSTD_endStream(zc, &outBuff) != 0) goto _output_error; /* error, or some data not flushed */
Yann Collet12083a42016-09-06 15:01:51 +0200696 }
Yann Collet736788f2017-01-19 12:12:50 -0800697 DISPLAYLEVEL(3, "OK \n");
Yann Collet12083a42016-09-06 15:01:51 +0200698
Nick Terrellf33de062020-04-27 18:10:45 -0700699 /* Decompression single pass with empty frame */
700 cSize = ZSTD_compress(compressedBuffer, compressedBufferSize, NULL, 0, 1);
701 CHECK_Z(cSize);
702 DISPLAYLEVEL(3, "test%3i : ZSTD_decompressStream() single pass on empty frame : ", testNb++);
703 { ZSTD_DCtx* dctx = ZSTD_createDCtx();
704 size_t const dctxSize = ZSTD_sizeof_DCtx(dctx);
705 CHECK_Z(ZSTD_DCtx_setParameter(dctx, ZSTD_d_stableOutBuffer, 1));
706
707 outBuff.dst = decodedBuffer;
708 outBuff.pos = 0;
709 outBuff.size = CNBufferSize;
710
711 inBuff.src = compressedBuffer;
712 inBuff.size = cSize;
713 inBuff.pos = 0;
714 { size_t const r = ZSTD_decompressStream(dctx, &outBuff, &inBuff);
715 CHECK_Z(r);
716 CHECK(r != 0, "Entire frame must be decompressed");
717 CHECK(outBuff.pos != 0, "Wrong size!");
718 CHECK(memcmp(CNBuffer, outBuff.dst, CNBufferSize) != 0, "Corruption!");
719 }
720 CHECK(dctxSize != ZSTD_sizeof_DCtx(dctx), "No buffers allocated");
721 ZSTD_freeDCtx(dctx);
722 }
723 DISPLAYLEVEL(3, "OK \n");
724
Nick Terrella4ff2172020-04-27 17:42:03 -0700725 /* Decompression with ZSTD_d_stableOutBuffer */
726 cSize = ZSTD_compress(compressedBuffer, compressedBufferSize, CNBuffer, CNBufferSize, 1);
727 CHECK_Z(cSize);
728 { ZSTD_DCtx* dctx = ZSTD_createDCtx();
Nick Terrell34aff7e2021-05-03 14:37:06 -0700729 size_t const dctxSize0 = ZSTD_sizeof_DCtx(dctx);
Nick Terrella4ff2172020-04-27 17:42:03 -0700730 size_t dctxSize1;
731 CHECK_Z(ZSTD_DCtx_setParameter(dctx, ZSTD_d_stableOutBuffer, 1));
732
733 outBuff.dst = decodedBuffer;
734 outBuff.pos = 0;
735 outBuff.size = CNBufferSize;
736
737 DISPLAYLEVEL(3, "test%3i : ZSTD_decompressStream() single pass : ", testNb++);
738 inBuff.src = compressedBuffer;
739 inBuff.size = cSize;
740 inBuff.pos = 0;
741 { size_t const r = ZSTD_decompressStream(dctx, &outBuff, &inBuff);
742 CHECK_Z(r);
743 CHECK(r != 0, "Entire frame must be decompressed");
744 CHECK(outBuff.pos != CNBufferSize, "Wrong size!");
745 CHECK(memcmp(CNBuffer, outBuff.dst, CNBufferSize) != 0, "Corruption!");
746 }
747 CHECK(dctxSize0 != ZSTD_sizeof_DCtx(dctx), "No buffers allocated");
748 DISPLAYLEVEL(3, "OK \n");
749
750 DISPLAYLEVEL(3, "test%3i : ZSTD_decompressStream() stable out buffer : ", testNb++);
751 outBuff.pos = 0;
752 inBuff.pos = 0;
753 inBuff.size = 0;
754 while (inBuff.pos < cSize) {
755 inBuff.size += MIN(cSize - inBuff.pos, 1 + (FUZ_rand(&coreSeed) & 15));
756 CHECK_Z(ZSTD_decompressStream(dctx, &outBuff, &inBuff));
757 }
758 CHECK(outBuff.pos != CNBufferSize, "Wrong size!");
759 CHECK(memcmp(CNBuffer, outBuff.dst, CNBufferSize) != 0, "Corruption!");
760 dctxSize1 = ZSTD_sizeof_DCtx(dctx);
761 CHECK(!(dctxSize0 < dctxSize1), "Input buffer allocated");
762 DISPLAYLEVEL(3, "OK \n");
763
764 DISPLAYLEVEL(3, "test%3i : ZSTD_decompressStream() stable out buffer too small : ", testNb++);
765 ZSTD_DCtx_reset(dctx, ZSTD_reset_session_only);
766 CHECK_Z(ZSTD_DCtx_setParameter(dctx, ZSTD_d_stableOutBuffer, 1));
767 inBuff.src = compressedBuffer;
768 inBuff.size = cSize;
769 inBuff.pos = 0;
770 outBuff.pos = 0;
771 outBuff.size = CNBufferSize - 1;
772 { size_t const r = ZSTD_decompressStream(dctx, &outBuff, &inBuff);
773 CHECK(ZSTD_getErrorCode(r) != ZSTD_error_dstSize_tooSmall, "Must error but got %s", ZSTD_getErrorName(r));
774 }
775 DISPLAYLEVEL(3, "OK \n");
776
777 DISPLAYLEVEL(3, "test%3i : ZSTD_decompressStream() stable out buffer modified : ", testNb++);
778 ZSTD_DCtx_reset(dctx, ZSTD_reset_session_only);
779 CHECK_Z(ZSTD_DCtx_setParameter(dctx, ZSTD_d_stableOutBuffer, 1));
780 inBuff.src = compressedBuffer;
781 inBuff.size = cSize - 1;
782 inBuff.pos = 0;
783 outBuff.pos = 0;
784 outBuff.size = CNBufferSize;
785 CHECK_Z(ZSTD_decompressStream(dctx, &outBuff, &inBuff));
786 ++inBuff.size;
787 outBuff.pos = 0;
788 { size_t const r = ZSTD_decompressStream(dctx, &outBuff, &inBuff);
789 CHECK(ZSTD_getErrorCode(r) != ZSTD_error_dstBuffer_wrong, "Must error but got %s", ZSTD_getErrorName(r));
790 }
791 DISPLAYLEVEL(3, "OK \n");
Nick Terrell34aff7e2021-05-03 14:37:06 -0700792
Nick Terrella4ff2172020-04-27 17:42:03 -0700793 DISPLAYLEVEL(3, "test%3i : ZSTD_decompressStream() buffered output : ", testNb++);
794 ZSTD_DCtx_reset(dctx, ZSTD_reset_session_only);
795 CHECK_Z(ZSTD_DCtx_setParameter(dctx, ZSTD_d_stableOutBuffer, 0));
796 outBuff.pos = 0;
797 inBuff.pos = 0;
798 inBuff.size = 0;
799 while (inBuff.pos < cSize) {
800 inBuff.size += MIN(cSize - inBuff.pos, 1 + (FUZ_rand(&coreSeed) & 15));
801 CHECK_Z(ZSTD_decompressStream(dctx, &outBuff, &inBuff));
802 }
803 CHECK(outBuff.pos != CNBufferSize, "Wrong size!");
804 CHECK(memcmp(CNBuffer, outBuff.dst, CNBufferSize) != 0, "Corruption!");
805 CHECK(!(dctxSize1 < ZSTD_sizeof_DCtx(dctx)), "Output buffer allocated");
806 DISPLAYLEVEL(3, "OK \n");
807
808 ZSTD_freeDCtx(dctx);
809 }
810
Nick Terrell2ebf6d52020-10-12 18:40:14 -0700811 /* Compression with ZSTD_c_stable{In,Out}Buffer */
Elliott Hughes44aba642023-09-12 20:18:59 +0000812 { ZSTD_CCtx* const cctx = ZSTD_createCCtx();
Nick Terrell2ebf6d52020-10-12 18:40:14 -0700813 ZSTD_inBuffer in;
814 ZSTD_outBuffer out;
815 size_t cctxSize1;
816 size_t cctxSize2;
Elliott Hughes44aba642023-09-12 20:18:59 +0000817 assert(cctx != NULL);
Nick Terrell2ebf6d52020-10-12 18:40:14 -0700818 in.src = CNBuffer;
819 in.size = CNBufferSize;
820 out.dst = compressedBuffer;
821 out.size = compressedBufferSize;
822 CHECK_Z(ZSTD_CCtx_setParameter(cctx, ZSTD_c_checksumFlag, 1));
823 DISPLAYLEVEL(3, "test%3i : ZSTD_compress2() uses stable input and output : ", testNb++);
824 CHECK_Z(cSize = ZSTD_compress2(cctx, compressedBuffer, compressedBufferSize, CNBuffer, CNBufferSize));
825 CHECK(!(cSize < ZSTD_compressBound(CNBufferSize)), "cSize too large for test");
826 CHECK_Z(cSize = ZSTD_compress2(cctx, compressedBuffer, cSize + 4, CNBuffer, CNBufferSize));
827 CHECK_Z(cctxSize1 = ZSTD_sizeof_CCtx(cctx));
Elliott Hughes44aba642023-09-12 20:18:59 +0000828 /* @cctxSize2 : sizeof_CCtx when doing full streaming (no stable in/out) */
829 { ZSTD_CCtx* const cctx2 = ZSTD_createCCtx();
830 assert(cctx2 != NULL);
Nick Terrell2ebf6d52020-10-12 18:40:14 -0700831 in.pos = out.pos = 0;
832 CHECK_Z(ZSTD_compressStream2(cctx2, &out, &in, ZSTD_e_continue));
833 CHECK(!(ZSTD_compressStream2(cctx2, &out, &in, ZSTD_e_end) == 0), "Not finished");
834 CHECK_Z(cctxSize2 = ZSTD_sizeof_CCtx(cctx2));
835 ZSTD_freeCCtx(cctx2);
836 }
Elliott Hughes44aba642023-09-12 20:18:59 +0000837 /* @cctxSize1 : sizeof_CCtx when doing single-shot compression (no streaming) */
838 { ZSTD_CCtx* const cctx1 = ZSTD_createCCtx();
Nick Terrell2ebf6d52020-10-12 18:40:14 -0700839 ZSTD_parameters params = ZSTD_getParams(0, CNBufferSize, 0);
840 size_t cSize3;
Elliott Hughes44aba642023-09-12 20:18:59 +0000841 assert(cctx1 != NULL);
Nick Terrell2ebf6d52020-10-12 18:40:14 -0700842 params.fParams.checksumFlag = 1;
Elliott Hughes44aba642023-09-12 20:18:59 +0000843 cSize3 = ZSTD_compress_advanced(cctx1, compressedBuffer, compressedBufferSize, CNBuffer, CNBufferSize, NULL, 0, params);
Nick Terrell2ebf6d52020-10-12 18:40:14 -0700844 CHECK_Z(cSize3);
845 CHECK(!(cSize == cSize3), "Must be same compressed size");
Elliott Hughes44aba642023-09-12 20:18:59 +0000846 CHECK(!(cctxSize1 == ZSTD_sizeof_CCtx(cctx1)), "Must be same CCtx size");
847 ZSTD_freeCCtx(cctx1);
Nick Terrell2ebf6d52020-10-12 18:40:14 -0700848 }
849 CHECK(!(cctxSize1 < cctxSize2), "Stable buffers means less allocated size");
850 CHECK_Z(ZSTD_decompress(decodedBuffer, CNBufferSize, compressedBuffer, cSize));
851 DISPLAYLEVEL(3, "OK \n");
852
853 DISPLAYLEVEL(3, "test%3i : ZSTD_compress2() doesn't modify user parameters : ", testNb++);
Elliott Hughes44aba642023-09-12 20:18:59 +0000854 { int stableInBuffer;
Nick Terrell2ebf6d52020-10-12 18:40:14 -0700855 int stableOutBuffer;
856 CHECK_Z(ZSTD_CCtx_getParameter(cctx, ZSTD_c_stableInBuffer, &stableInBuffer));
857 CHECK_Z(ZSTD_CCtx_getParameter(cctx, ZSTD_c_stableOutBuffer, &stableOutBuffer));
858 CHECK(!(stableInBuffer == 0), "Modified");
859 CHECK(!(stableOutBuffer == 0), "Modified");
860 CHECK_Z(ZSTD_CCtx_setParameter(cctx, ZSTD_c_stableInBuffer, 1));
861 CHECK_Z(ZSTD_CCtx_setParameter(cctx, ZSTD_c_stableOutBuffer, 1));
862 CHECK_Z(cSize = ZSTD_compress2(cctx, compressedBuffer, compressedBufferSize, CNBuffer, CNBufferSize));
863 CHECK_Z(ZSTD_CCtx_getParameter(cctx, ZSTD_c_stableInBuffer, &stableInBuffer));
864 CHECK_Z(ZSTD_CCtx_getParameter(cctx, ZSTD_c_stableOutBuffer, &stableOutBuffer));
865 CHECK(!(stableInBuffer == 1), "Modified");
866 CHECK(!(stableOutBuffer == 1), "Modified");
867 }
868 DISPLAYLEVEL(3, "OK \n");
869
870 DISPLAYLEVEL(3, "test%3i : ZSTD_compressStream2() with ZSTD_c_stableInBuffer and ZSTD_c_stableOutBuffer : ", testNb++);
871 CHECK_Z(ZSTD_CCtx_reset(cctx, ZSTD_reset_session_and_parameters));
872 CHECK_Z(ZSTD_CCtx_setParameter(cctx, ZSTD_c_checksumFlag, 1));
873 CHECK_Z(ZSTD_CCtx_setParameter(cctx, ZSTD_c_stableInBuffer, 1));
874 CHECK_Z(ZSTD_CCtx_setParameter(cctx, ZSTD_c_stableOutBuffer, 1));
875 in.pos = out.pos = 0;
876 CHECK(!(ZSTD_compressStream2(cctx, &out, &in, ZSTD_e_end) == 0), "Not finished");
877 CHECK_Z(ZSTD_decompress(decodedBuffer, CNBufferSize, compressedBuffer, cSize));
878 DISPLAYLEVEL(3, "OK \n");
879
880 DISPLAYLEVEL(3, "test%3i : ZSTD_compressStream2() ZSTD_c_stableInBuffer and ZSTD_c_stableOutBuffer allocated size : ", testNb++);
881 { size_t const cctxSize = ZSTD_sizeof_CCtx(cctx);
882 CHECK(!(cctxSize1 == cctxSize), "Must be the same size as single pass");
883 }
884 DISPLAYLEVEL(3, "OK \n");
885
886 DISPLAYLEVEL(3, "test%3i : ZSTD_compressStream2() with ZSTD_c_stableInBuffer only : ", testNb++);
887 CHECK_Z(ZSTD_CCtx_reset(cctx, ZSTD_reset_session_and_parameters));
888 CHECK_Z(ZSTD_CCtx_setParameter(cctx, ZSTD_c_checksumFlag, 1));
889 CHECK_Z(ZSTD_CCtx_setParameter(cctx, ZSTD_c_stableInBuffer, 1));
890 in.pos = out.pos = 0;
891 out.size = cSize / 4;
892 for (;;) {
893 size_t const ret = ZSTD_compressStream2(cctx, &out, &in, ZSTD_e_end);
894 CHECK_Z(ret);
895 if (ret == 0)
896 break;
897 out.size = MIN(out.size + cSize / 4, compressedBufferSize);
898 }
899 CHECK_Z(ZSTD_decompress(decodedBuffer, CNBufferSize, compressedBuffer, cSize));
900 DISPLAYLEVEL(3, "OK \n");
901
902 DISPLAYLEVEL(3, "test%3i : ZSTD_compressStream2() ZSTD_c_stableInBuffer modify buffer : ", testNb++);
903 in.pos = out.pos = 0;
904 out.size = cSize / 4;
905 CHECK_Z(ZSTD_compressStream2(cctx, &out, &in, ZSTD_e_end));
906 in.src = (char const*)in.src + in.pos;
907 in.size -= in.pos;
908 in.pos = 0;
909 { size_t const ret = ZSTD_compressStream2(cctx, &out, &in, ZSTD_e_end);
910 CHECK(!ZSTD_isError(ret), "Must error");
Elliott Hughes44aba642023-09-12 20:18:59 +0000911 CHECK(!(ZSTD_getErrorCode(ret) == ZSTD_error_stabilityCondition_notRespected), "Must be this error");
Nick Terrell2ebf6d52020-10-12 18:40:14 -0700912 }
913 DISPLAYLEVEL(3, "OK \n");
914
Elliott Hughes44aba642023-09-12 20:18:59 +0000915 /* stableSrc + streaming */
916 DISPLAYLEVEL(3, "test%3i : ZSTD_c_stableInBuffer compatibility with compressStream, flushStream and endStream : ", testNb++);
917 CHECK_Z( ZSTD_initCStream(cctx, 1) );
918 CHECK_Z( ZSTD_CCtx_setParameter(cctx, ZSTD_c_stableInBuffer, 1) );
919 { ZSTD_inBuffer inBuf;
920 ZSTD_outBuffer outBuf;
921 const size_t nonZeroStartPos = 18;
922 const size_t inputSize = 500;
923 inBuf.src = CNBuffer;
924 inBuf.size = 100;
925 inBuf.pos = nonZeroStartPos;
926 outBuf.dst = (char*)(compressedBuffer)+cSize;
927 outBuf.size = ZSTD_compressBound(inputSize);
928 outBuf.pos = 0;
929 CHECK_Z( ZSTD_compressStream(cctx, &outBuf, &inBuf) );
930 inBuf.size = 200;
931 CHECK_Z( ZSTD_compressStream(cctx, &outBuf, &inBuf) );
932 CHECK_Z( ZSTD_flushStream(cctx, &outBuf) );
933 inBuf.size = nonZeroStartPos + inputSize;
934 CHECK_Z( ZSTD_compressStream(cctx, &outBuf, &inBuf) );
935 CHECK(ZSTD_endStream(cctx, &outBuf) != 0, "compression should be successful and fully flushed");
936 { const void* const realSrcStart = (const char*)inBuf.src + nonZeroStartPos;
937 void* const verifBuf = (char*)outBuf.dst + outBuf.pos;
938 const size_t decSize = ZSTD_decompress(verifBuf, inputSize, outBuf.dst, outBuf.pos);
939 CHECK_Z(decSize);
940 CHECK(decSize != inputSize, "regenerated %zu bytes, instead of %zu", decSize, inputSize);
941 CHECK(memcmp(realSrcStart, verifBuf, inputSize) != 0, "regenerated data different from original");
942 } }
Nick Terrell2ebf6d52020-10-12 18:40:14 -0700943 DISPLAYLEVEL(3, "OK \n");
944
Elliott Hughes44aba642023-09-12 20:18:59 +0000945 /* stableSrc + streaming */
946 DISPLAYLEVEL(3, "test%3i : ZSTD_c_stableInBuffer compatibility with compressStream2, using different end directives : ", testNb++);
947 CHECK_Z( ZSTD_initCStream(cctx, 1) );
948 CHECK_Z( ZSTD_CCtx_setParameter(cctx, ZSTD_c_stableInBuffer, 1) );
949 { ZSTD_inBuffer inBuf;
950 ZSTD_outBuffer outBuf;
951 const size_t nonZeroStartPos = 18;
952 const size_t inputSize = 500;
953 inBuf.src = CNBuffer;
954 inBuf.size = 100;
955 inBuf.pos = nonZeroStartPos;
956 outBuf.dst = (char*)(compressedBuffer)+cSize;
957 outBuf.size = ZSTD_compressBound(inputSize);
958 outBuf.pos = 0;
959 CHECK_Z( ZSTD_compressStream2(cctx, &outBuf, &inBuf, ZSTD_e_continue) );
960 inBuf.size = 200;
961 CHECK_Z( ZSTD_compressStream2(cctx, &outBuf, &inBuf, ZSTD_e_continue) );
962 CHECK_Z( ZSTD_compressStream2(cctx, &outBuf, &inBuf, ZSTD_e_flush) );
963 inBuf.size = nonZeroStartPos + inputSize;
964 CHECK_Z( ZSTD_compressStream2(cctx, &outBuf, &inBuf, ZSTD_e_continue) );
965 CHECK( ZSTD_compressStream2(cctx, &outBuf, &inBuf, ZSTD_e_end) != 0, "compression should be successful and fully flushed");
966 { const void* const realSrcStart = (const char*)inBuf.src + nonZeroStartPos;
967 void* const verifBuf = (char*)outBuf.dst + outBuf.pos;
968 const size_t decSize = ZSTD_decompress(verifBuf, inputSize, outBuf.dst, outBuf.pos);
969 CHECK_Z(decSize);
970 CHECK(decSize != inputSize, "regenerated %zu bytes, instead of %zu", decSize, inputSize);
971 CHECK(memcmp(realSrcStart, verifBuf, inputSize) != 0, "regenerated data different from original");
972 } }
973 DISPLAYLEVEL(3, "OK \n");
974
975 DISPLAYLEVEL(3, "test%3i : ZSTD_compressStream2() with ZSTD_c_stableInBuffer: context size : ", testNb++);
Nick Terrell2ebf6d52020-10-12 18:40:14 -0700976 { size_t const cctxSize = ZSTD_sizeof_CCtx(cctx);
Elliott Hughes44aba642023-09-12 20:18:59 +0000977 DISPLAYLEVEL(4, "cctxSize1=%zu; cctxSize=%zu; cctxSize2=%zu : ", cctxSize1, cctxSize, cctxSize2);
Nick Terrell2ebf6d52020-10-12 18:40:14 -0700978 CHECK(!(cctxSize1 < cctxSize), "Must be bigger than single-pass");
979 CHECK(!(cctxSize < cctxSize2), "Must be smaller than streaming");
980 cctxSize1 = cctxSize;
981 }
982 DISPLAYLEVEL(3, "OK \n");
983
984 DISPLAYLEVEL(3, "test%3i : ZSTD_compressStream2() with ZSTD_c_stableOutBuffer only : ", testNb++);
985 CHECK_Z(ZSTD_CCtx_reset(cctx, ZSTD_reset_session_and_parameters));
986 CHECK_Z(ZSTD_CCtx_setParameter(cctx, ZSTD_c_checksumFlag, 1));
987 CHECK_Z(ZSTD_CCtx_setParameter(cctx, ZSTD_c_stableOutBuffer, 1));
Elliott Hughes44aba642023-09-12 20:18:59 +0000988 in.src = CNBuffer;
Nick Terrell2ebf6d52020-10-12 18:40:14 -0700989 in.pos = out.pos = 0;
990 in.size = MIN(CNBufferSize, 10);
Elliott Hughes44aba642023-09-12 20:18:59 +0000991 out.size = compressedBufferSize;
Nick Terrell2ebf6d52020-10-12 18:40:14 -0700992 CHECK_Z(ZSTD_compressStream2(cctx, &out, &in, ZSTD_e_flush));
993 in.pos = 0;
994 in.size = CNBufferSize - in.size;
995 CHECK(!(ZSTD_compressStream2(cctx, &out, &in, ZSTD_e_end) == 0), "Not finished");
W. Felix Handte168d0a32021-09-13 16:35:58 -0400996 CHECK_Z(ZSTD_decompress(decodedBuffer, CNBufferSize, compressedBuffer, out.pos));
Nick Terrell2ebf6d52020-10-12 18:40:14 -0700997 DISPLAYLEVEL(3, "OK \n");
998
999 DISPLAYLEVEL(3, "test%3i : ZSTD_compressStream2() ZSTD_c_stableOutBuffer modify buffer : ", testNb++);
1000 in.pos = out.pos = 0;
1001 in.size = CNBufferSize;
1002 CHECK_Z(ZSTD_compressStream2(cctx, &out, &in, ZSTD_e_continue));
1003 in.pos = out.pos = 0;
1004 { size_t const ret = ZSTD_compressStream2(cctx, &out, &in, ZSTD_e_continue);
1005 CHECK(!ZSTD_isError(ret), "Must have errored");
Elliott Hughes44aba642023-09-12 20:18:59 +00001006 CHECK(!(ZSTD_getErrorCode(ret) == ZSTD_error_stabilityCondition_notRespected), "Must be this error");
Nick Terrell2ebf6d52020-10-12 18:40:14 -07001007 }
1008 DISPLAYLEVEL(3, "OK \n");
1009
Elliott Hughes44aba642023-09-12 20:18:59 +00001010 DISPLAYLEVEL(3, "test%3i : ZSTD_compressStream2() with ZSTD_c_stableOutBuffer: context size : ", testNb++);
Nick Terrell2ebf6d52020-10-12 18:40:14 -07001011 { size_t const cctxSize = ZSTD_sizeof_CCtx(cctx);
Elliott Hughes44aba642023-09-12 20:18:59 +00001012 DISPLAYLEVEL(4, "cctxSize1=%zu; cctxSize=%zu; cctxSize2=%zu : ", cctxSize1, cctxSize, cctxSize2);
Nick Terrell2ebf6d52020-10-12 18:40:14 -07001013 CHECK(!(cctxSize1 < cctxSize), "Must be bigger than single-pass and stableInBuffer");
1014 CHECK(!(cctxSize < cctxSize2), "Must be smaller than streaming");
1015 }
1016 DISPLAYLEVEL(3, "OK \n");
1017
1018 ZSTD_freeCCtx(cctx);
1019 }
1020
Yann Collet95162342016-10-25 16:19:52 -07001021 /* CDict scenario */
Yann Collet736788f2017-01-19 12:12:50 -08001022 DISPLAYLEVEL(3, "test%3i : digested dictionary : ", testNb++);
Yann Collet2e427422017-06-27 17:09:12 -07001023 { ZSTD_CDict* const cdict = ZSTD_createCDict(dictionary.start, dictionary.filled, 1 /*byRef*/ );
Yann Collet95162342016-10-25 16:19:52 -07001024 size_t const initError = ZSTD_initCStream_usingCDict(zc, cdict);
Yann Colletededcfc2018-12-21 16:19:44 -08001025 DISPLAYLEVEL(5, "ZSTD_initCStream_usingCDict result : %u ", (unsigned)initError);
Yann Collet95162342016-10-25 16:19:52 -07001026 if (ZSTD_isError(initError)) goto _output_error;
Yann Collet95162342016-10-25 16:19:52 -07001027 outBuff.dst = compressedBuffer;
1028 outBuff.size = compressedBufferSize;
1029 outBuff.pos = 0;
1030 inBuff.src = CNBuffer;
1031 inBuff.size = CNBufferSize;
1032 inBuff.pos = 0;
Yann Collet15768ca2017-11-16 15:02:28 -08001033 DISPLAYLEVEL(5, "- starting ZSTD_compressStream ");
Yann Colletd6770f82017-09-28 02:14:48 -07001034 CHECK_Z( ZSTD_compressStream(zc, &outBuff, &inBuff) );
Yann Collet95162342016-10-25 16:19:52 -07001035 if (inBuff.pos != inBuff.size) goto _output_error; /* entire input should be consumed */
Yann Collet15768ca2017-11-16 15:02:28 -08001036 { size_t const r = ZSTD_endStream(zc, &outBuff);
Yann Colletededcfc2018-12-21 16:19:44 -08001037 DISPLAYLEVEL(5, "- ZSTD_endStream result : %u ", (unsigned)r);
Yann Collet15768ca2017-11-16 15:02:28 -08001038 if (r != 0) goto _output_error; /* error, or some data not flushed */
1039 }
Yann Collet95162342016-10-25 16:19:52 -07001040 cSize = outBuff.pos;
1041 ZSTD_freeCDict(cdict);
Yann Colletededcfc2018-12-21 16:19:44 -08001042 DISPLAYLEVEL(3, "OK (%u bytes : %.2f%%)\n", (unsigned)cSize, (double)cSize/CNBufferSize*100);
Yann Collet95162342016-10-25 16:19:52 -07001043 }
1044
Yann Collet736788f2017-01-19 12:12:50 -08001045 DISPLAYLEVEL(3, "test%3i : check CStream size : ", testNb++);
Yann Collet12083a42016-09-06 15:01:51 +02001046 { size_t const s = ZSTD_sizeof_CStream(zc);
1047 if (ZSTD_isError(s)) goto _output_error;
Yann Colletededcfc2018-12-21 16:19:44 -08001048 DISPLAYLEVEL(3, "OK (%u bytes) \n", (unsigned)s);
Yann Collet12083a42016-09-06 15:01:51 +02001049 }
1050
Yann Collet33fce032017-01-16 19:46:22 -08001051 DISPLAYLEVEL(4, "test%3i : check Dictionary ID : ", testNb++);
1052 { unsigned const dID = ZSTD_getDictID_fromFrame(compressedBuffer, cSize);
1053 if (dID != dictID) goto _output_error;
1054 DISPLAYLEVEL(4, "OK (%u) \n", dID);
1055 }
1056
Yann Collet335ad5d2016-10-25 17:47:02 -07001057 /* DDict scenario */
Yann Colletededcfc2018-12-21 16:19:44 -08001058 DISPLAYLEVEL(3, "test%3i : decompress %u bytes with digested dictionary : ", testNb++, (unsigned)CNBufferSize);
Yann Collet33fce032017-01-16 19:46:22 -08001059 { ZSTD_DDict* const ddict = ZSTD_createDDict(dictionary.start, dictionary.filled);
Yann Collet335ad5d2016-10-25 17:47:02 -07001060 size_t const initError = ZSTD_initDStream_usingDDict(zd, ddict);
1061 if (ZSTD_isError(initError)) goto _output_error;
Yann Collet8a104fd2017-12-12 12:51:49 -08001062 outBuff.dst = decodedBuffer;
1063 outBuff.size = CNBufferSize;
1064 outBuff.pos = 0;
Yann Collet03832b72017-12-12 14:01:54 -08001065 inBuff.src = compressedBuffer;
1066 inBuff.size = cSize;
1067 inBuff.pos = 0;
Yann Collet335ad5d2016-10-25 17:47:02 -07001068 { size_t const r = ZSTD_decompressStream(zd, &outBuff, &inBuff);
1069 if (r != 0) goto _output_error; } /* should reach end of frame == 0; otherwise, some data left, or an error */
1070 if (outBuff.pos != CNBufferSize) goto _output_error; /* should regenerate the same amount */
1071 if (inBuff.pos != inBuff.size) goto _output_error; /* should have read the entire frame */
1072 ZSTD_freeDDict(ddict);
Yann Collet736788f2017-01-19 12:12:50 -08001073 DISPLAYLEVEL(3, "OK \n");
Yann Collet335ad5d2016-10-25 17:47:02 -07001074 }
1075
Yann Collet17e482e2016-08-23 16:58:10 +02001076 /* Memory restriction */
Yann Collet736788f2017-01-19 12:12:50 -08001077 DISPLAYLEVEL(3, "test%3i : maxWindowSize < frame requirement : ", testNb++);
Yann Collet30ab64e2017-05-10 11:30:19 -07001078 ZSTD_initDStream_usingDict(zd, CNBuffer, dictSize);
Yann Collet3e042d52018-12-04 17:30:58 -08001079 CHECK_Z( ZSTD_DCtx_setParameter(zd, ZSTD_d_windowLogMax, 10) ); /* too small limit */
Yann Collet8a104fd2017-12-12 12:51:49 -08001080 outBuff.dst = decodedBuffer;
1081 outBuff.size = CNBufferSize;
1082 outBuff.pos = 0;
Yann Collet03832b72017-12-12 14:01:54 -08001083 inBuff.src = compressedBuffer;
1084 inBuff.size = cSize;
1085 inBuff.pos = 0;
Yann Collet17e482e2016-08-23 16:58:10 +02001086 { size_t const r = ZSTD_decompressStream(zd, &outBuff, &inBuff);
1087 if (!ZSTD_isError(r)) goto _output_error; /* must fail : frame requires > 100 bytes */
Yann Collet736788f2017-01-19 12:12:50 -08001088 DISPLAYLEVEL(3, "OK (%s)\n", ZSTD_getErrorName(r)); }
Yann Collet5c686392018-11-15 16:12:39 -08001089 ZSTD_DCtx_reset(zd, ZSTD_reset_session_and_parameters); /* leave zd in good shape for next tests */
Yann Collet17e482e2016-08-23 16:58:10 +02001090
Nick Terrellab3346a2018-01-30 13:30:30 -08001091 DISPLAYLEVEL(3, "test%3i : dictionary source size and level : ", testNb++);
1092 { ZSTD_DCtx* const dctx = ZSTD_createDCtx();
Yann Collet6cda8c92018-03-20 16:16:13 -07001093 int const maxLevel = 16; /* first level with zstd_opt */
Nick Terrellab3346a2018-01-30 13:30:30 -08001094 int level;
Yann Collet2af41592018-03-20 15:59:25 -07001095 assert(maxLevel < ZSTD_maxCLevel());
1096 CHECK_Z( ZSTD_DCtx_loadDictionary_byReference(dctx, dictionary.start, dictionary.filled) );
Nick Terrellab3346a2018-01-30 13:30:30 -08001097 for (level = 1; level <= maxLevel; ++level) {
1098 ZSTD_CDict* const cdict = ZSTD_createCDict(dictionary.start, dictionary.filled, level);
Yann Collet2af41592018-03-20 15:59:25 -07001099 size_t const maxSize = MIN(1 MB, CNBufferSize);
1100 size_t size;
Nick Terrellab3346a2018-01-30 13:30:30 -08001101 for (size = 512; size <= maxSize; size <<= 1) {
Yann Collet2af41592018-03-20 15:59:25 -07001102 U64 const crcOrig = XXH64(CNBuffer, size, 0);
Nick Terrellab3346a2018-01-30 13:30:30 -08001103 ZSTD_CCtx* const cctx = ZSTD_createCCtx();
Nick Terrellca778222018-04-25 16:32:29 -07001104 ZSTD_parameters savedParams;
1105 getCCtxParams(cctx, &savedParams);
Nick Terrellab3346a2018-01-30 13:30:30 -08001106 outBuff.dst = compressedBuffer;
1107 outBuff.size = compressedBufferSize;
1108 outBuff.pos = 0;
1109 inBuff.src = CNBuffer;
1110 inBuff.size = size;
1111 inBuff.pos = 0;
1112 CHECK_Z(ZSTD_CCtx_refCDict(cctx, cdict));
Yann Colletd8e215c2018-11-30 11:16:26 -08001113 CHECK_Z(ZSTD_compressStream2(cctx, &outBuff, &inBuff, ZSTD_e_end));
Nick Terrellca778222018-04-25 16:32:29 -07001114 CHECK(badParameters(cctx, savedParams), "Bad CCtx params");
Nick Terrellab3346a2018-01-30 13:30:30 -08001115 if (inBuff.pos != inBuff.size) goto _output_error;
Yann Collet2af41592018-03-20 15:59:25 -07001116 { ZSTD_outBuffer decOut = {decodedBuffer, size, 0};
1117 ZSTD_inBuffer decIn = {outBuff.dst, outBuff.pos, 0};
Yann Collet34e146f2018-12-04 10:28:36 -08001118 CHECK_Z( ZSTD_decompressStream(dctx, &decOut, &decIn) );
Yann Collet2af41592018-03-20 15:59:25 -07001119 if (decIn.pos != decIn.size) goto _output_error;
1120 if (decOut.pos != size) goto _output_error;
1121 { U64 const crcDec = XXH64(decOut.dst, decOut.pos, 0);
1122 if (crcDec != crcOrig) goto _output_error;
1123 } }
Nick Terrellab3346a2018-01-30 13:30:30 -08001124 ZSTD_freeCCtx(cctx);
1125 }
1126 ZSTD_freeCDict(cdict);
1127 }
Nick Terrellab3346a2018-01-30 13:30:30 -08001128 ZSTD_freeDCtx(dctx);
1129 }
1130 DISPLAYLEVEL(3, "OK\n");
1131
Nick Terrell50b9c412019-04-10 12:34:21 -07001132 ZSTD_CCtx_reset(zc, ZSTD_reset_session_and_parameters);
1133 CHECK_Z( ZSTD_CCtx_loadDictionary(zc, dictionary.start, dictionary.filled) );
1134 cSize = ZSTD_compress2(zc, compressedBuffer, compressedBufferSize, CNBuffer, MIN(CNBufferSize, 100 KB));
1135 CHECK_Z(cSize);
1136 DISPLAYLEVEL(3, "test%3i : ZSTD_decompressStream() with dictionary : ", testNb++);
1137 {
1138 ZSTD_DCtx* dctx = ZSTD_createDCtx();
1139 /* We should fail to decompress without a dictionary. */
1140 ZSTD_DCtx_reset(dctx, ZSTD_reset_session_and_parameters);
1141 { ZSTD_outBuffer out = {decodedBuffer, decodedBufferSize, 0};
1142 ZSTD_inBuffer in = {compressedBuffer, cSize, 0};
1143 size_t const ret = ZSTD_decompressStream(dctx, &out, &in);
1144 if (!ZSTD_isError(ret)) goto _output_error;
1145 }
1146 /* We should succeed to decompress with the dictionary. */
1147 ZSTD_DCtx_reset(dctx, ZSTD_reset_session_and_parameters);
1148 CHECK_Z( ZSTD_DCtx_loadDictionary(dctx, dictionary.start, dictionary.filled) );
1149 { ZSTD_outBuffer out = {decodedBuffer, decodedBufferSize, 0};
1150 ZSTD_inBuffer in = {compressedBuffer, cSize, 0};
1151 if (ZSTD_decompressStream(dctx, &out, &in) != 0) goto _output_error;
1152 if (in.pos != in.size) goto _output_error;
1153 }
Dimitris Apostolouebbd6752021-11-13 10:04:04 +02001154 /* The dictionary should persist across calls. */
Nick Terrell50b9c412019-04-10 12:34:21 -07001155 { ZSTD_outBuffer out = {decodedBuffer, decodedBufferSize, 0};
1156 ZSTD_inBuffer in = {compressedBuffer, cSize, 0};
1157 if (ZSTD_decompressStream(dctx, &out, &in) != 0) goto _output_error;
1158 if (in.pos != in.size) goto _output_error;
1159 }
1160 /* The dictionary should not be cleared by ZSTD_reset_session_only. */
1161 ZSTD_DCtx_reset(dctx, ZSTD_reset_session_only);
1162 { ZSTD_outBuffer out = {decodedBuffer, decodedBufferSize, 0};
1163 ZSTD_inBuffer in = {compressedBuffer, cSize, 0};
1164 if (ZSTD_decompressStream(dctx, &out, &in) != 0) goto _output_error;
1165 if (in.pos != in.size) goto _output_error;
1166 }
1167 /* When we reset the context the dictionary is cleared. */
1168 ZSTD_DCtx_reset(dctx, ZSTD_reset_session_and_parameters);
1169 { ZSTD_outBuffer out = {decodedBuffer, decodedBufferSize, 0};
1170 ZSTD_inBuffer in = {compressedBuffer, cSize, 0};
1171 size_t const ret = ZSTD_decompressStream(dctx, &out, &in);
1172 if (!ZSTD_isError(ret)) goto _output_error;
1173 }
1174 ZSTD_freeDCtx(dctx);
1175 }
1176 DISPLAYLEVEL(3, "OK \n");
1177
Josh Sorefa880ca22019-04-12 14:18:11 -04001178 DISPLAYLEVEL(3, "test%3i : ZSTD_resetDStream() with dictionary : ", testNb++);
Nick Terrell50b9c412019-04-10 12:34:21 -07001179 {
1180 ZSTD_DCtx* dctx = ZSTD_createDCtx();
1181 /* We should succeed to decompress with the dictionary. */
1182 ZSTD_resetDStream(dctx);
1183 CHECK_Z( ZSTD_DCtx_loadDictionary(dctx, dictionary.start, dictionary.filled) );
1184 { ZSTD_outBuffer out = {decodedBuffer, decodedBufferSize, 0};
1185 ZSTD_inBuffer in = {compressedBuffer, cSize, 0};
1186 if (ZSTD_decompressStream(dctx, &out, &in) != 0) goto _output_error;
1187 if (in.pos != in.size) goto _output_error;
1188 }
1189 /* The dictionary should not be cleared by ZSTD_resetDStream(). */
1190 ZSTD_resetDStream(dctx);
1191 { ZSTD_outBuffer out = {decodedBuffer, decodedBufferSize, 0};
1192 ZSTD_inBuffer in = {compressedBuffer, cSize, 0};
1193 if (ZSTD_decompressStream(dctx, &out, &in) != 0) goto _output_error;
1194 if (in.pos != in.size) goto _output_error;
1195 }
1196 /* The dictionary should be cleared by ZSTD_initDStream(). */
1197 CHECK_Z( ZSTD_initDStream(dctx) );
1198 { ZSTD_outBuffer out = {decodedBuffer, decodedBufferSize, 0};
1199 ZSTD_inBuffer in = {compressedBuffer, cSize, 0};
1200 size_t const ret = ZSTD_decompressStream(dctx, &out, &in);
1201 if (!ZSTD_isError(ret)) goto _output_error;
1202 }
1203 ZSTD_freeDCtx(dctx);
1204 }
1205 DISPLAYLEVEL(3, "OK \n");
1206
1207 DISPLAYLEVEL(3, "test%3i : ZSTD_decompressStream() with ddict : ", testNb++);
1208 {
1209 ZSTD_DCtx* dctx = ZSTD_createDCtx();
1210 ZSTD_DDict* ddict = ZSTD_createDDict(dictionary.start, dictionary.filled);
1211 /* We should succeed to decompress with the ddict. */
1212 ZSTD_DCtx_reset(dctx, ZSTD_reset_session_and_parameters);
1213 CHECK_Z( ZSTD_DCtx_refDDict(dctx, ddict) );
1214 { ZSTD_outBuffer out = {decodedBuffer, decodedBufferSize, 0};
1215 ZSTD_inBuffer in = {compressedBuffer, cSize, 0};
1216 if (ZSTD_decompressStream(dctx, &out, &in) != 0) goto _output_error;
1217 if (in.pos != in.size) goto _output_error;
1218 }
Dimitris Apostolouebbd6752021-11-13 10:04:04 +02001219 /* The ddict should persist across calls. */
Nick Terrell50b9c412019-04-10 12:34:21 -07001220 { ZSTD_outBuffer out = {decodedBuffer, decodedBufferSize, 0};
1221 ZSTD_inBuffer in = {compressedBuffer, cSize, 0};
1222 if (ZSTD_decompressStream(dctx, &out, &in) != 0) goto _output_error;
1223 if (in.pos != in.size) goto _output_error;
1224 }
1225 /* When we reset the context the ddict is cleared. */
1226 ZSTD_DCtx_reset(dctx, ZSTD_reset_session_and_parameters);
1227 { ZSTD_outBuffer out = {decodedBuffer, decodedBufferSize, 0};
1228 ZSTD_inBuffer in = {compressedBuffer, cSize, 0};
1229 size_t const ret = ZSTD_decompressStream(dctx, &out, &in);
1230 if (!ZSTD_isError(ret)) goto _output_error;
1231 }
1232 ZSTD_freeDCtx(dctx);
1233 ZSTD_freeDDict(ddict);
1234 }
1235 DISPLAYLEVEL(3, "OK \n");
1236
1237 DISPLAYLEVEL(3, "test%3i : ZSTD_decompressDCtx() with prefix : ", testNb++);
1238 {
1239 ZSTD_DCtx* dctx = ZSTD_createDCtx();
1240 /* We should succeed to decompress with the prefix. */
1241 ZSTD_DCtx_reset(dctx, ZSTD_reset_session_and_parameters);
1242 CHECK_Z( ZSTD_DCtx_refPrefix_advanced(dctx, dictionary.start, dictionary.filled, ZSTD_dct_auto) );
1243 { ZSTD_outBuffer out = {decodedBuffer, decodedBufferSize, 0};
1244 ZSTD_inBuffer in = {compressedBuffer, cSize, 0};
1245 if (ZSTD_decompressStream(dctx, &out, &in) != 0) goto _output_error;
1246 if (in.pos != in.size) goto _output_error;
1247 }
1248 /* The prefix should be cleared after the first compression. */
1249 { ZSTD_outBuffer out = {decodedBuffer, decodedBufferSize, 0};
1250 ZSTD_inBuffer in = {compressedBuffer, cSize, 0};
1251 size_t const ret = ZSTD_decompressStream(dctx, &out, &in);
1252 if (!ZSTD_isError(ret)) goto _output_error;
1253 }
1254 ZSTD_freeDCtx(dctx);
1255 }
1256 DISPLAYLEVEL(3, "OK \n");
1257
1258 DISPLAYLEVEL(3, "test%3i : ZSTD_initDStream*() with dictionary : ", testNb++);
1259 {
1260 ZSTD_DCtx* dctx = ZSTD_createDCtx();
1261 ZSTD_DDict* ddict = ZSTD_createDDict(dictionary.start, dictionary.filled);
1262 size_t ret;
1263 /* We should succeed to decompress with the dictionary. */
1264 CHECK_Z( ZSTD_initDStream_usingDict(dctx, dictionary.start, dictionary.filled) );
1265 CHECK_Z( ZSTD_decompressDCtx(dctx, decodedBuffer, decodedBufferSize, compressedBuffer, cSize) );
Dimitris Apostolouebbd6752021-11-13 10:04:04 +02001266 /* The dictionary should persist across calls. */
Nick Terrell50b9c412019-04-10 12:34:21 -07001267 CHECK_Z( ZSTD_decompressDCtx(dctx, decodedBuffer, decodedBufferSize, compressedBuffer, cSize) );
1268 /* We should succeed to decompress with the ddict. */
1269 CHECK_Z( ZSTD_initDStream_usingDDict(dctx, ddict) );
1270 CHECK_Z( ZSTD_decompressDCtx(dctx, decodedBuffer, decodedBufferSize, compressedBuffer, cSize) );
Dimitris Apostolouebbd6752021-11-13 10:04:04 +02001271 /* The ddict should persist across calls. */
Nick Terrell50b9c412019-04-10 12:34:21 -07001272 CHECK_Z( ZSTD_decompressDCtx(dctx, decodedBuffer, decodedBufferSize, compressedBuffer, cSize) );
1273 /* When we reset the context the ddict is cleared. */
1274 CHECK_Z( ZSTD_initDStream(dctx) );
1275 ret = ZSTD_decompressDCtx(dctx, decodedBuffer, decodedBufferSize, compressedBuffer, cSize);
1276 if (!ZSTD_isError(ret)) goto _output_error;
1277 ZSTD_freeDCtx(dctx);
1278 ZSTD_freeDDict(ddict);
1279 }
1280 DISPLAYLEVEL(3, "OK \n");
1281
Yann Collet7d283cd2017-04-27 14:48:34 -07001282 DISPLAYLEVEL(3, "test%3i : ZSTD_initCStream_usingCDict_advanced with masked dictID : ", testNb++);
1283 { ZSTD_compressionParameters const cParams = ZSTD_getCParams(1, CNBufferSize, dictionary.filled);
1284 ZSTD_frameParameters const fParams = { 1 /* contentSize */, 1 /* checksum */, 1 /* noDictID */};
Yann Collet6873fec2018-03-20 15:13:14 -07001285 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 -07001286 size_t const initError = ZSTD_initCStream_usingCDict_advanced(zc, cdict, fParams, CNBufferSize);
Yann Collet7d283cd2017-04-27 14:48:34 -07001287 if (ZSTD_isError(initError)) goto _output_error;
Nick Terrell62ecad32017-04-03 20:56:39 -07001288 outBuff.dst = compressedBuffer;
1289 outBuff.size = compressedBufferSize;
1290 outBuff.pos = 0;
1291 inBuff.src = CNBuffer;
1292 inBuff.size = CNBufferSize;
1293 inBuff.pos = 0;
Yann Colletd6770f82017-09-28 02:14:48 -07001294 CHECK_Z( ZSTD_compressStream(zc, &outBuff, &inBuff) );
Yann Collet8c910d22017-06-03 01:15:02 -07001295 if (inBuff.pos != inBuff.size) goto _output_error; /* entire input should be consumed */
Nick Terrell62ecad32017-04-03 20:56:39 -07001296 { size_t const r = ZSTD_endStream(zc, &outBuff);
1297 if (r != 0) goto _output_error; } /* error, or some data not flushed */
1298 cSize = outBuff.pos;
1299 ZSTD_freeCDict(cdict);
Yann Colletededcfc2018-12-21 16:19:44 -08001300 DISPLAYLEVEL(3, "OK (%u bytes : %.2f%%)\n", (unsigned)cSize, (double)cSize/CNBufferSize*100);
Yann Collet4ee6b152017-04-11 11:59:44 -07001301 }
Nick Terrell62ecad32017-04-03 20:56:39 -07001302
Yann Colleta92cbb72017-04-27 15:08:56 -07001303 DISPLAYLEVEL(3, "test%3i : try retrieving dictID from frame : ", testNb++);
1304 { U32 const did = ZSTD_getDictID_fromFrame(compressedBuffer, cSize);
1305 if (did != 0) goto _output_error;
1306 }
1307 DISPLAYLEVEL(3, "OK (not detected) \n");
1308
Yann Collet4ee6b152017-04-11 11:59:44 -07001309 DISPLAYLEVEL(3, "test%3i : decompress without dictionary : ", testNb++);
1310 { size_t const r = ZSTD_decompress(decodedBuffer, CNBufferSize, compressedBuffer, cSize);
1311 if (!ZSTD_isError(r)) goto _output_error; /* must fail : dictionary not used */
1312 DISPLAYLEVEL(3, "OK (%s)\n", ZSTD_getErrorName(r));
Nick Terrell62ecad32017-04-03 20:56:39 -07001313 }
1314
Yann Collet62f7efc2017-06-28 16:25:13 -07001315 DISPLAYLEVEL(3, "test%3i : compress with ZSTD_CCtx_refPrefix : ", testNb++);
Yann Colletd6770f82017-09-28 02:14:48 -07001316 CHECK_Z( ZSTD_CCtx_refPrefix(zc, dictionary.start, dictionary.filled) );
Yann Collet62f7efc2017-06-28 16:25:13 -07001317 outBuff.dst = compressedBuffer;
1318 outBuff.size = compressedBufferSize;
1319 outBuff.pos = 0;
1320 inBuff.src = CNBuffer;
1321 inBuff.size = CNBufferSize;
1322 inBuff.pos = 0;
Yann Colletd8e215c2018-11-30 11:16:26 -08001323 CHECK_Z( ZSTD_compressStream2(zc, &outBuff, &inBuff, ZSTD_e_end) );
Yann Collet62f7efc2017-06-28 16:25:13 -07001324 if (inBuff.pos != inBuff.size) goto _output_error; /* entire input should be consumed */
1325 cSize = outBuff.pos;
Yann Colletededcfc2018-12-21 16:19:44 -08001326 DISPLAYLEVEL(3, "OK (%u bytes : %.2f%%)\n", (unsigned)cSize, (double)cSize/CNBufferSize*100);
Yann Collet62f7efc2017-06-28 16:25:13 -07001327
Yann Collet6cda8c92018-03-20 16:16:13 -07001328 DISPLAYLEVEL(3, "test%3i : decompress with ZSTD_DCtx_refPrefix : ", testNb++);
1329 CHECK_Z( ZSTD_DCtx_refPrefix(zd, dictionary.start, dictionary.filled) );
1330 outBuff.dst = decodedBuffer;
1331 outBuff.size = CNBufferSize;
1332 outBuff.pos = 0;
1333 inBuff.src = compressedBuffer;
1334 inBuff.size = cSize;
1335 inBuff.pos = 0;
Yann Collet34e146f2018-12-04 10:28:36 -08001336 CHECK_Z( ZSTD_decompressStream(zd, &outBuff, &inBuff) );
Yann Collet6cda8c92018-03-20 16:16:13 -07001337 if (inBuff.pos != inBuff.size) goto _output_error; /* entire input should be consumed */
1338 if (outBuff.pos != CNBufferSize) goto _output_error; /* must regenerate whole input */
1339 DISPLAYLEVEL(3, "OK \n");
Yann Collet62f7efc2017-06-28 16:25:13 -07001340
1341 DISPLAYLEVEL(3, "test%3i : decompress without dictionary (should fail): ", testNb++);
1342 { size_t const r = ZSTD_decompress(decodedBuffer, CNBufferSize, compressedBuffer, cSize);
1343 if (!ZSTD_isError(r)) goto _output_error; /* must fail : dictionary not used */
1344 DISPLAYLEVEL(3, "OK (%s)\n", ZSTD_getErrorName(r));
1345 }
1346
Yann Colletd8e215c2018-11-30 11:16:26 -08001347 DISPLAYLEVEL(3, "test%3i : compress again with ZSTD_compressStream2 : ", testNb++);
Yann Collet62f7efc2017-06-28 16:25:13 -07001348 outBuff.dst = compressedBuffer;
1349 outBuff.size = compressedBufferSize;
1350 outBuff.pos = 0;
1351 inBuff.src = CNBuffer;
1352 inBuff.size = CNBufferSize;
1353 inBuff.pos = 0;
Yann Colletd8e215c2018-11-30 11:16:26 -08001354 CHECK_Z( ZSTD_compressStream2(zc, &outBuff, &inBuff, ZSTD_e_end) );
Yann Collet62f7efc2017-06-28 16:25:13 -07001355 if (inBuff.pos != inBuff.size) goto _output_error; /* entire input should be consumed */
1356 cSize = outBuff.pos;
Yann Colletededcfc2018-12-21 16:19:44 -08001357 DISPLAYLEVEL(3, "OK (%u bytes : %.2f%%)\n", (unsigned)cSize, (double)cSize/CNBufferSize*100);
Yann Collet62f7efc2017-06-28 16:25:13 -07001358
1359 DISPLAYLEVEL(3, "test%3i : decompress without dictionary (should work): ", testNb++);
Yann Colletd6770f82017-09-28 02:14:48 -07001360 CHECK_Z( ZSTD_decompress(decodedBuffer, CNBufferSize, compressedBuffer, cSize) );
1361 DISPLAYLEVEL(3, "OK \n");
Yann Collet62f7efc2017-06-28 16:25:13 -07001362
Yann Collet0bb381d2017-04-18 15:08:52 -07001363 /* Empty srcSize */
1364 DISPLAYLEVEL(3, "test%3i : ZSTD_initCStream_advanced with pledgedSrcSize=0 and dict : ", testNb++);
1365 { ZSTD_parameters params = ZSTD_getParams(5, 0, 0);
1366 params.fParams.contentSizeFlag = 1;
Yann Collet213ef3b2017-10-13 19:01:58 -07001367 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 -07001368 } /* cstream advanced shall write content size = 0 */
Yann Collet8a104fd2017-12-12 12:51:49 -08001369 outBuff.dst = compressedBuffer;
1370 outBuff.size = compressedBufferSize;
1371 outBuff.pos = 0;
Yann Collet03832b72017-12-12 14:01:54 -08001372 inBuff.src = CNBuffer;
1373 inBuff.size = 0;
1374 inBuff.pos = 0;
Yann Colletd6770f82017-09-28 02:14:48 -07001375 CHECK_Z( ZSTD_compressStream(zc, &outBuff, &inBuff) );
Yann Collet0bb381d2017-04-18 15:08:52 -07001376 if (ZSTD_endStream(zc, &outBuff) != 0) goto _output_error;
1377 cSize = outBuff.pos;
1378 if (ZSTD_findDecompressedSize(compressedBuffer, cSize) != 0) goto _output_error;
1379 DISPLAYLEVEL(3, "OK \n");
1380
sen698f2612021-05-06 17:59:32 -04001381 DISPLAYLEVEL(3, "test%3i : pledgedSrcSize == 0 behaves properly with ZSTD_initCStream_advanced : ", testNb++);
Sean Purcell2db72492017-02-09 10:50:43 -08001382 { ZSTD_parameters params = ZSTD_getParams(5, 0, 0);
1383 params.fParams.contentSizeFlag = 1;
Yann Colletd6770f82017-09-28 02:14:48 -07001384 CHECK_Z( ZSTD_initCStream_advanced(zc, NULL, 0, params, 0) );
Yann Collet4ee6b152017-04-11 11:59:44 -07001385 } /* cstream advanced shall write content size = 0 */
Sean Purcell2db72492017-02-09 10:50:43 -08001386 inBuff.src = CNBuffer;
1387 inBuff.size = 0;
1388 inBuff.pos = 0;
1389 outBuff.dst = compressedBuffer;
1390 outBuff.size = compressedBufferSize;
1391 outBuff.pos = 0;
Yann Colletd6770f82017-09-28 02:14:48 -07001392 CHECK_Z( ZSTD_compressStream(zc, &outBuff, &inBuff) );
Sean Purcell2db72492017-02-09 10:50:43 -08001393 if (ZSTD_endStream(zc, &outBuff) != 0) goto _output_error;
1394 cSize = outBuff.pos;
1395 if (ZSTD_findDecompressedSize(compressedBuffer, cSize) != 0) goto _output_error;
1396
sen698f2612021-05-06 17:59:32 -04001397 CHECK_Z( ZSTD_CCtx_reset(zc, ZSTD_reset_session_only) );
1398 CHECK_Z( ZSTD_CCtx_setPledgedSrcSize(zc, ZSTD_CONTENTSIZE_UNKNOWN) );
Yann Collet8a104fd2017-12-12 12:51:49 -08001399 outBuff.dst = compressedBuffer;
1400 outBuff.size = compressedBufferSize;
1401 outBuff.pos = 0;
Yann Collet03832b72017-12-12 14:01:54 -08001402 inBuff.src = CNBuffer;
1403 inBuff.size = 0;
1404 inBuff.pos = 0;
Yann Colletd6770f82017-09-28 02:14:48 -07001405 CHECK_Z( ZSTD_compressStream(zc, &outBuff, &inBuff) );
Sean Purcell2db72492017-02-09 10:50:43 -08001406 if (ZSTD_endStream(zc, &outBuff) != 0) goto _output_error;
1407 cSize = outBuff.pos;
1408 if (ZSTD_findDecompressedSize(compressedBuffer, cSize) != ZSTD_CONTENTSIZE_UNKNOWN) goto _output_error;
1409 DISPLAYLEVEL(3, "OK \n");
Yann Collet17e482e2016-08-23 16:58:10 +02001410
Stella Lau90a31bf2017-08-30 14:36:54 -07001411 /* Basic multithreading compression test */
1412 DISPLAYLEVEL(3, "test%3i : compress %u bytes with multiple threads : ", testNb++, COMPRESSIBLE_NOISE_LENGTH);
Nick Terrellc51a9e72020-10-01 18:47:54 -07001413 { int jobSize;
1414 CHECK_Z( ZSTD_CCtx_getParameter(mtctx, ZSTD_c_jobSize, &jobSize));
Nick Terrellb426bcc2018-06-25 15:21:08 -07001415 CHECK(jobSize != 0, "job size non-zero");
Nick Terrellc51a9e72020-10-01 18:47:54 -07001416 CHECK_Z( ZSTD_CCtx_getParameter(mtctx, ZSTD_c_jobSize, &jobSize));
Nick Terrellb426bcc2018-06-25 15:21:08 -07001417 CHECK(jobSize != 0, "job size non-zero");
Yann Colletd6770f82017-09-28 02:14:48 -07001418 }
Yann Collet03832b72017-12-12 14:01:54 -08001419 outBuff.dst = compressedBuffer;
Stella Lau90a31bf2017-08-30 14:36:54 -07001420 outBuff.size = compressedBufferSize;
1421 outBuff.pos = 0;
1422 inBuff.src = CNBuffer;
1423 inBuff.size = CNBufferSize;
1424 inBuff.pos = 0;
Nick Terrellc51a9e72020-10-01 18:47:54 -07001425 { size_t const compressResult = ZSTD_compressStream2(mtctx, &outBuff, &inBuff, ZSTD_e_end);
Yann Collet67113962018-01-19 22:11:11 -08001426 if (compressResult != 0) goto _output_error; /* compression must be completed in a single round */
1427 }
Stella Lau90a31bf2017-08-30 14:36:54 -07001428 if (inBuff.pos != inBuff.size) goto _output_error; /* entire input should be consumed */
Yann Collet67113962018-01-19 22:11:11 -08001429 { size_t const compressedSize = ZSTD_findFrameCompressedSize(compressedBuffer, outBuff.pos);
1430 if (compressedSize != outBuff.pos) goto _output_error; /* must be a full valid frame */
1431 }
Stella Lau90a31bf2017-08-30 14:36:54 -07001432 DISPLAYLEVEL(3, "OK \n");
1433
Yann Collet03832b72017-12-12 14:01:54 -08001434 /* Complex multithreading + dictionary test */
Yann Collet209df522018-02-01 19:29:30 -08001435 { U32 const nbWorkers = 2;
Yann Collet03832b72017-12-12 14:01:54 -08001436 size_t const jobSize = 4 * 1 MB;
Yann Collet209df522018-02-01 19:29:30 -08001437 size_t const srcSize = jobSize * nbWorkers; /* we want each job to have predictable size */
Yann Collet03832b72017-12-12 14:01:54 -08001438 size_t const segLength = 2 KB;
1439 size_t const offset = 600 KB; /* must be larger than window defined in cdict */
1440 size_t const start = jobSize + (offset-1);
1441 const BYTE* const srcToCopy = (const BYTE*)CNBuffer + start;
1442 BYTE* const dst = (BYTE*)CNBuffer + start - offset;
Yann Colletededcfc2018-12-21 16:19:44 -08001443 DISPLAYLEVEL(3, "test%3i : compress %u bytes with multiple threads + dictionary : ", testNb++, (unsigned)srcSize);
Yann Collet3583d192018-12-05 17:26:02 -08001444 CHECK_Z( ZSTD_CCtx_setParameter(zc, ZSTD_c_compressionLevel, 3) );
1445 CHECK_Z( ZSTD_CCtx_setParameter(zc, ZSTD_c_nbWorkers, nbWorkers) );
1446 CHECK_Z( ZSTD_CCtx_setParameter(zc, ZSTD_c_jobSize, jobSize) );
Yann Collet03832b72017-12-12 14:01:54 -08001447 assert(start > offset);
1448 assert(start + segLength < COMPRESSIBLE_NOISE_LENGTH);
1449 memcpy(dst, srcToCopy, segLength); /* create a long repetition at long distance for job 2 */
1450 outBuff.dst = compressedBuffer;
1451 outBuff.size = compressedBufferSize;
1452 outBuff.pos = 0;
1453 inBuff.src = CNBuffer;
1454 inBuff.size = srcSize; assert(srcSize < COMPRESSIBLE_NOISE_LENGTH);
1455 inBuff.pos = 0;
1456 }
Josh Sorefa880ca22019-04-12 14:18:11 -04001457 { 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 -07001458 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 -08001459 DISPLAYLEVEL(5, "cParams.windowLog = %u : ", cParams.windowLog);
Yann Colletd23eb9a2017-12-13 15:35:49 -08001460 CHECK_Z( ZSTD_CCtx_refCDict(zc, cdict) );
Yann Colletd8e215c2018-11-30 11:16:26 -08001461 CHECK_Z( ZSTD_compressStream2(zc, &outBuff, &inBuff, ZSTD_e_end) );
Yann Colletd23eb9a2017-12-13 15:35:49 -08001462 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 -08001463 ZSTD_freeCDict(cdict);
1464 }
1465 if (inBuff.pos != inBuff.size) goto _output_error; /* entire input should be consumed */
1466 cSize = outBuff.pos;
1467 DISPLAYLEVEL(3, "OK \n");
1468
1469 DISPLAYLEVEL(3, "test%3i : decompress large frame created from multiple threads + dictionary : ", testNb++);
1470 { ZSTD_DStream* const dstream = ZSTD_createDCtx();
1471 ZSTD_frameHeader zfh;
1472 ZSTD_getFrameHeader(&zfh, compressedBuffer, cSize);
Yann Colletededcfc2018-12-21 16:19:44 -08001473 DISPLAYLEVEL(5, "frame windowsize = %u : ", (unsigned)zfh.windowSize);
Yann Collet03832b72017-12-12 14:01:54 -08001474 outBuff.dst = decodedBuffer;
1475 outBuff.size = CNBufferSize;
1476 outBuff.pos = 0;
1477 inBuff.src = compressedBuffer;
1478 inBuff.pos = 0;
1479 CHECK_Z( ZSTD_initDStream_usingDict(dstream, dictionary.start, dictionary.filled) );
1480 inBuff.size = 1; /* avoid shortcut to single-pass mode */
1481 CHECK_Z( ZSTD_decompressStream(dstream, &outBuff, &inBuff) );
1482 inBuff.size = cSize;
1483 CHECK_Z( ZSTD_decompressStream(dstream, &outBuff, &inBuff) );
1484 if (inBuff.pos != inBuff.size) goto _output_error; /* entire input should be consumed */
1485 ZSTD_freeDStream(dstream);
1486 }
1487 DISPLAYLEVEL(3, "OK \n");
1488
Nick Terrelle600b5d2017-10-16 17:18:43 -07001489 DISPLAYLEVEL(3, "test%3i : check dictionary FSE tables can represent every code : ", testNb++);
1490 { unsigned const kMaxWindowLog = 24;
1491 unsigned value;
1492 ZSTD_compressionParameters cParams = ZSTD_getCParams(3, 1U << kMaxWindowLog, 1024);
1493 ZSTD_CDict* cdict;
1494 ZSTD_DDict* ddict;
1495 SEQ_stream seq = SEQ_initStream(0x87654321);
1496 SEQ_gen_type type;
1497 XXH64_state_t xxh;
1498
1499 XXH64_reset(&xxh, 0);
1500 cParams.windowLog = kMaxWindowLog;
Yann Collet6873fec2018-03-20 15:13:14 -07001501 cdict = ZSTD_createCDict_advanced(dictionary.start, dictionary.filled, ZSTD_dlm_byRef, ZSTD_dct_fullDict, cParams, ZSTD_defaultCMem);
Nick Terrelle600b5d2017-10-16 17:18:43 -07001502 ddict = ZSTD_createDDict(dictionary.start, dictionary.filled);
1503
1504 if (!cdict || !ddict) goto _output_error;
1505
Yann Collet5c686392018-11-15 16:12:39 -08001506 ZSTD_CCtx_reset(zc, ZSTD_reset_session_only);
Nick Terrelle600b5d2017-10-16 17:18:43 -07001507 ZSTD_resetDStream(zd);
1508 CHECK_Z(ZSTD_CCtx_refCDict(zc, cdict));
1509 CHECK_Z(ZSTD_initDStream_usingDDict(zd, ddict));
Yann Collet3e042d52018-12-04 17:30:58 -08001510 CHECK_Z(ZSTD_DCtx_setParameter(zd, ZSTD_d_windowLogMax, kMaxWindowLog));
Nick Terrelle600b5d2017-10-16 17:18:43 -07001511 /* Test all values < 300 */
1512 for (value = 0; value < 300; ++value) {
1513 for (type = (SEQ_gen_type)0; type < SEQ_gen_max; ++type) {
1514 CHECK_Z(SEQ_generateRoundTrip(zc, zd, &xxh, &seq, type, value));
1515 }
1516 }
1517 /* Test values 2^8 to 2^17 */
1518 for (value = (1 << 8); value < (1 << 17); value <<= 1) {
1519 for (type = (SEQ_gen_type)0; type < SEQ_gen_max; ++type) {
1520 CHECK_Z(SEQ_generateRoundTrip(zc, zd, &xxh, &seq, type, value));
1521 CHECK_Z(SEQ_generateRoundTrip(zc, zd, &xxh, &seq, type, value + (value >> 2)));
1522 }
1523 }
1524 /* Test offset values up to the max window log */
1525 for (value = 8; value <= kMaxWindowLog; ++value) {
1526 CHECK_Z(SEQ_generateRoundTrip(zc, zd, &xxh, &seq, SEQ_gen_of, (1U << value) - 1));
1527 }
1528
1529 CHECK_Z(SEQ_roundTrip(zc, zd, &xxh, NULL, 0, ZSTD_e_end));
1530 CHECK(SEQ_digest(&seq) != XXH64_digest(&xxh), "SEQ XXH64 does not match");
1531
1532 ZSTD_freeCDict(cdict);
1533 ZSTD_freeDDict(ddict);
1534 }
1535 DISPLAYLEVEL(3, "OK \n");
Stella Lau90a31bf2017-08-30 14:36:54 -07001536
Nick Terrell6d222c42018-07-12 17:56:58 -07001537 DISPLAYLEVEL(3, "test%3i : ZSTD_initCStream_srcSize sets requestedParams : ", testNb++);
Yann Colletd4d4e102018-11-21 15:37:26 -08001538 { int level;
Nick Terrell6d222c42018-07-12 17:56:58 -07001539 CHECK_Z(ZSTD_initCStream_srcSize(zc, 11, ZSTD_CONTENTSIZE_UNKNOWN));
Yann Collet3583d192018-12-05 17:26:02 -08001540 CHECK_Z(ZSTD_CCtx_getParameter(zc, ZSTD_c_compressionLevel, &level));
Nick Terrell6d222c42018-07-12 17:56:58 -07001541 CHECK(level != 11, "Compression level does not match");
sen698f2612021-05-06 17:59:32 -04001542 CHECK_Z( ZSTD_CCtx_reset(zc, ZSTD_reset_session_only) );
1543 CHECK_Z( ZSTD_CCtx_setPledgedSrcSize(zc, ZSTD_CONTENTSIZE_UNKNOWN) );
Yann Collet3583d192018-12-05 17:26:02 -08001544 CHECK_Z(ZSTD_CCtx_getParameter(zc, ZSTD_c_compressionLevel, &level));
Nick Terrell6d222c42018-07-12 17:56:58 -07001545 CHECK(level != 11, "Compression level does not match");
1546 }
1547 DISPLAYLEVEL(3, "OK \n");
1548
1549 DISPLAYLEVEL(3, "test%3i : ZSTD_initCStream_advanced sets requestedParams : ", testNb++);
1550 { ZSTD_parameters const params = ZSTD_getParams(9, 0, 0);
1551 CHECK_Z(ZSTD_initCStream_advanced(zc, NULL, 0, params, ZSTD_CONTENTSIZE_UNKNOWN));
1552 CHECK(badParameters(zc, params), "Compression parameters do not match");
sen698f2612021-05-06 17:59:32 -04001553 CHECK_Z( ZSTD_CCtx_reset(zc, ZSTD_reset_session_only) );
1554 CHECK_Z( ZSTD_CCtx_setPledgedSrcSize(zc, ZSTD_CONTENTSIZE_UNKNOWN) );
Nick Terrell6d222c42018-07-12 17:56:58 -07001555 CHECK(badParameters(zc, params), "Compression parameters do not match");
1556 }
1557 DISPLAYLEVEL(3, "OK \n");
1558
Nick Terrell51990242019-09-18 11:05:08 -07001559 DISPLAYLEVEL(3, "test%3i : ZSTD_c_srcSizeHint bounds : ", testNb++);
1560 ZSTD_CCtx_reset(zc, ZSTD_reset_session_and_parameters);
1561 CHECK_Z(ZSTD_CCtx_setParameter(zc, ZSTD_c_srcSizeHint, INT_MAX));
1562 { int srcSizeHint;
1563 CHECK_Z(ZSTD_CCtx_getParameter(zc, ZSTD_c_srcSizeHint, &srcSizeHint));
1564 CHECK(!(srcSizeHint == INT_MAX), "srcSizeHint doesn't match");
1565 }
1566 CHECK(!ZSTD_isError(ZSTD_CCtx_setParameter(zc, ZSTD_c_srcSizeHint, -1)), "Out of range doesn't error");
1567 DISPLAYLEVEL(3, "OK \n");
1568
Elliott Hughes44aba642023-09-12 20:18:59 +00001569 DISPLAYLEVEL(3, "test%3i : ZSTD_lazy compress with hashLog = 29 and searchLog = 4 : ", testNb++);
1570 if (MEM_64bits()) {
1571 ZSTD_outBuffer out = { compressedBuffer, compressedBufferSize, 0 };
1572 ZSTD_inBuffer in = { CNBuffer, CNBufferSize, 0 };
1573 CHECK_Z(ZSTD_CCtx_reset(zc, ZSTD_reset_session_and_parameters));
1574 CHECK_Z(ZSTD_CCtx_setParameter(zc, ZSTD_c_strategy, ZSTD_lazy));
1575 /* Force enable the row based match finder */
1576 CHECK_Z(ZSTD_CCtx_setParameter(zc, ZSTD_c_useRowMatchFinder, ZSTD_ps_enable));
1577 CHECK_Z(ZSTD_CCtx_setParameter(zc, ZSTD_c_searchLog, 4));
1578 /* Set windowLog to 29 so the hashLog doesn't get sized down */
1579 CHECK_Z(ZSTD_CCtx_setParameter(zc, ZSTD_c_windowLog, 29));
1580 CHECK_Z(ZSTD_CCtx_setParameter(zc, ZSTD_c_hashLog, 29));
1581 CHECK_Z(ZSTD_CCtx_setParameter(zc, ZSTD_c_checksumFlag, 1));
1582 /* Compress with continue first so the hashLog doesn't get sized down */
1583 CHECK_Z(ZSTD_compressStream2(zc, &out, &in, ZSTD_e_continue));
1584 CHECK_Z(ZSTD_compressStream2(zc, &out, &in, ZSTD_e_end));
1585 cSize = out.pos;
1586 CHECK_Z(ZSTD_decompress(decodedBuffer, CNBufferSize, compressedBuffer, cSize));
1587 }
1588 DISPLAYLEVEL(3, "OK \n");
1589
1590 DISPLAYLEVEL(3, "test%3i : Test offset == windowSize : ", testNb++);
1591 {
1592 int windowLog;
1593 int const kMaxWindowLog = bigTests ? 29 : 26;
1594 size_t const kNbSequences = 10000;
1595 size_t const kMaxSrcSize = (1u << kMaxWindowLog) + 10 * kNbSequences;
1596 char* src = calloc(kMaxSrcSize, 1);
1597 ZSTD_Sequence* sequences = malloc(sizeof(ZSTD_Sequence) * kNbSequences);
1598 for (windowLog = ZSTD_WINDOWLOG_MIN; windowLog <= kMaxWindowLog; ++windowLog) {
1599 size_t const srcSize = ((size_t)1 << windowLog) + 10 * (kNbSequences - 1);
1600
1601 sequences[0].offset = 32;
1602 sequences[0].litLength = 32;
1603 sequences[0].matchLength = (1u << windowLog) - 32;
1604 sequences[0].rep = 0;
1605 {
1606 size_t i;
1607 for (i = 1; i < kNbSequences; ++i) {
1608 sequences[i].offset = (1u << windowLog) - (FUZ_rand(&seed) % 8);
1609 sequences[i].litLength = FUZ_rand(&seed) & 7;
1610 sequences[i].matchLength = 10 - sequences[i].litLength;
1611 sequences[i].rep = 0;
1612 }
1613 }
1614
1615 CHECK_Z(ZSTD_CCtx_reset(zc, ZSTD_reset_session_and_parameters));
1616 CHECK_Z(ZSTD_CCtx_setParameter(zc, ZSTD_c_checksumFlag, 1));
1617 CHECK_Z(ZSTD_CCtx_setParameter(zc, ZSTD_c_minMatch, 3));
1618 CHECK_Z(ZSTD_CCtx_setParameter(zc, ZSTD_c_validateSequences, 1));
1619 CHECK_Z(ZSTD_CCtx_setParameter(zc, ZSTD_c_windowLog, windowLog));
1620 assert(srcSize <= kMaxSrcSize);
1621 cSize = ZSTD_compressSequences(zc, compressedBuffer, compressedBufferSize, sequences, kNbSequences, src, srcSize);
1622 CHECK_Z(cSize);
1623 CHECK_Z(ZSTD_DCtx_reset(zd, ZSTD_reset_session_and_parameters));
1624 CHECK_Z(ZSTD_DCtx_setParameter(zd, ZSTD_d_windowLogMax, windowLog))
1625 {
1626 ZSTD_inBuffer in = {compressedBuffer, cSize, 0};
1627 size_t decompressedBytes = 0;
1628 for (;;) {
1629 ZSTD_outBuffer out = {decodedBuffer, decodedBufferSize, 0};
1630 size_t const ret = ZSTD_decompressStream(zd, &out, &in);
1631 CHECK_Z(ret);
1632 CHECK(decompressedBytes + out.pos > srcSize, "Output too large");
1633 CHECK(memcmp(out.dst, src + decompressedBytes, out.pos), "Corrupted");
1634 decompressedBytes += out.pos;
1635 if (ret == 0) {
1636 break;
1637 }
1638 }
1639 CHECK(decompressedBytes != srcSize, "Output wrong size");
1640 }
1641 }
1642 free(sequences);
1643 free(src);
1644 }
1645 DISPLAYLEVEL(3, "OK \n");
1646
Sean Purcell887eaa92017-02-15 16:43:45 -08001647 /* Overlen overwriting window data bug */
1648 DISPLAYLEVEL(3, "test%3i : wildcopy doesn't overwrite potential match data : ", testNb++);
Sean Purcell0ed39012017-02-16 13:29:47 -08001649 { /* This test has a window size of 1024 bytes and consists of 3 blocks:
1650 1. 'a' repeated 517 times
1651 2. 'b' repeated 516 times
1652 3. a compressed block with no literals and 3 sequence commands:
1653 litlength = 0, offset = 24, match length = 24
1654 litlength = 0, offset = 24, match length = 3 (this one creates an overlength write of length 2*WILDCOPY_OVERLENGTH - 3)
1655 litlength = 0, offset = 1021, match length = 3 (this one will try to read from overwritten data if the buffer is too small) */
1656
1657 const char* testCase =
1658 "\x28\xB5\x2F\xFD\x04\x00\x4C\x00\x00\x10\x61\x61\x01\x00\x00\x2A"
1659 "\x80\x05\x44\x00\x00\x08\x62\x01\x00\x00\x2A\x20\x04\x5D\x00\x00"
1660 "\x00\x03\x40\x00\x00\x64\x60\x27\xB0\xE0\x0C\x67\x62\xCE\xE0";
Yann Colletd6770f82017-09-28 02:14:48 -07001661 ZSTD_DStream* const zds = ZSTD_createDStream();
1662 if (zds==NULL) goto _output_error;
Sean Purcell887eaa92017-02-15 16:43:45 -08001663
Yann Colletd6770f82017-09-28 02:14:48 -07001664 CHECK_Z( ZSTD_initDStream(zds) );
Sean Purcell887eaa92017-02-15 16:43:45 -08001665 inBuff.src = testCase;
Sean Purcell0ed39012017-02-16 13:29:47 -08001666 inBuff.size = 47;
Sean Purcell887eaa92017-02-15 16:43:45 -08001667 inBuff.pos = 0;
1668 outBuff.dst = decodedBuffer;
1669 outBuff.size = CNBufferSize;
1670 outBuff.pos = 0;
1671
1672 while (inBuff.pos < inBuff.size) {
Yann Colletd6770f82017-09-28 02:14:48 -07001673 CHECK_Z( ZSTD_decompressStream(zds, &outBuff, &inBuff) );
Sean Purcell887eaa92017-02-15 16:43:45 -08001674 }
Przemyslaw Skibinski684858e2017-02-21 18:17:24 +01001675
1676 ZSTD_freeDStream(zds);
Sean Purcell887eaa92017-02-15 16:43:45 -08001677 }
1678 DISPLAYLEVEL(3, "OK \n");
1679
Ephraim Park01e83842019-06-27 17:27:29 -07001680 /* Small Sequence Section bug */
1681 DISPLAYLEVEL(3, "test%3i : decompress blocks with small sequences section : ", testNb++);
1682 { /* This test consists of 3 blocks. Each block has one sequence.
1683 The sequence has literal length of 10, match length of 10 and offset of 10.
1684 The sequence value and compression mode for the blocks are following:
1685 The order of values are ll, ml, of.
1686 - First block : (10, 7, 13) (rle, rle, rle)
1687 - size of sequences section: 6 bytes (1 byte for nbSeq, 1 byte for encoding mode, 3 bytes for rle, 1 byte bitstream)
1688 - Second block : (10, 7, 1) (repeat, repeat, rle)
1689 - size of sequences section: 4 bytes (1 byte for nbSeq, 1 byte for encoding mode, 1 bytes for rle, 1 byte bitstream)
1690 - Third block : (10, 7, 1) (repeat, repeat, repeat)
1691 - size of sequences section: 3 bytes (1 byte for nbSeq, 1 byte for encoding mode, 1 byte bitstream) */
1692
1693 unsigned char compressed[] = {
1694 0x28, 0xb5, 0x2f, 0xfd, 0x24, 0x3c, 0x35, 0x01, 0x00, 0xf0, 0x85, 0x08,
1695 0xc2, 0xc4, 0x70, 0xcf, 0xd7, 0xc0, 0x96, 0x7e, 0x4c, 0x6b, 0xa9, 0x8b,
1696 0xbc, 0xc5, 0xb6, 0xd9, 0x7f, 0x4c, 0xf1, 0x05, 0xa6, 0x54, 0xef, 0xac,
1697 0x69, 0x94, 0x89, 0x1c, 0x03, 0x44, 0x0a, 0x07, 0x00, 0xb4, 0x04, 0x80,
1698 0x40, 0x0a, 0xa4
1699 };
1700 unsigned int compressedSize = 51;
1701 unsigned char decompressed[] = {
1702 0x85, 0x08, 0xc2, 0xc4, 0x70, 0xcf, 0xd7, 0xc0, 0x96, 0x7e, 0x85, 0x08,
1703 0xc2, 0xc4, 0x70, 0xcf, 0xd7, 0xc0, 0x96, 0x7e, 0x4c, 0x6b, 0xa9, 0x8b,
1704 0xbc, 0xc5, 0xb6, 0xd9, 0x7f, 0x4c, 0x4c, 0x6b, 0xa9, 0x8b, 0xbc, 0xc5,
1705 0xb6, 0xd9, 0x7f, 0x4c, 0xf1, 0x05, 0xa6, 0x54, 0xef, 0xac, 0x69, 0x94,
1706 0x89, 0x1c, 0xf1, 0x05, 0xa6, 0x54, 0xef, 0xac, 0x69, 0x94, 0x89, 0x1c
1707 };
1708 unsigned int decompressedSize = 60;
1709
1710 ZSTD_DStream* const zds = ZSTD_createDStream();
1711 if (zds==NULL) goto _output_error;
1712
1713 CHECK_Z( ZSTD_initDStream(zds) );
1714 inBuff.src = compressed;
1715 inBuff.size = compressedSize;
1716 inBuff.pos = 0;
1717 outBuff.dst = decodedBuffer;
1718 outBuff.size = CNBufferSize;
1719 outBuff.pos = 0;
1720
Ephraim Park28309522019-07-01 10:17:30 -07001721 CHECK(ZSTD_decompressStream(zds, &outBuff, &inBuff) != 0,
1722 "Decompress did not reach the end of frame");
1723 CHECK(inBuff.pos != inBuff.size, "Decompress did not fully consume input");
1724 CHECK(outBuff.pos != decompressedSize, "Decompressed size does not match");
1725 CHECK(memcmp(outBuff.dst, decompressed, decompressedSize) != 0,
1726 "Decompressed data does not match");
Ephraim Park01e83842019-06-27 17:27:29 -07001727
1728 ZSTD_freeDStream(zds);
1729 }
1730 DISPLAYLEVEL(3, "OK \n");
1731
Nick Terrell036b30b2020-01-10 18:02:11 -08001732 DISPLAYLEVEL(3, "test%3i : raw block can be streamed: ", testNb++);
1733 { size_t const inputSize = 10000;
1734 size_t const compCapacity = ZSTD_compressBound(inputSize);
1735 BYTE* const input = (BYTE*)malloc(inputSize);
1736 BYTE* const comp = (BYTE*)malloc(compCapacity);
1737 BYTE* const decomp = (BYTE*)malloc(inputSize);
1738
1739 CHECK(input == NULL || comp == NULL || decomp == NULL, "failed to alloc buffers");
1740
1741 RDG_genBuffer(input, inputSize, 0.0, 0.0, seed);
1742 { size_t const compSize = ZSTD_compress(comp, compCapacity, input, inputSize, -(int)inputSize);
1743 ZSTD_inBuffer in = { comp, 0, 0 };
1744 ZSTD_outBuffer out = { decomp, 0, 0 };
1745 CHECK_Z(compSize);
1746 CHECK_Z( ZSTD_DCtx_reset(zd, ZSTD_reset_session_and_parameters) );
1747 while (in.size < compSize) {
1748 in.size = MIN(in.size + 100, compSize);
1749 while (in.pos < in.size) {
1750 size_t const outPos = out.pos;
1751 if (out.pos == out.size) {
1752 out.size = MIN(out.size + 10, inputSize);
1753 }
1754 CHECK_Z( ZSTD_decompressStream(zd, &out, &in) );
1755 CHECK(!(out.pos > outPos), "We are not streaming (no output generated)");
1756 }
1757 }
1758 CHECK(in.pos != compSize, "Not all input consumed!");
1759 CHECK(out.pos != inputSize, "Not all output produced!");
1760 }
1761 CHECK(memcmp(input, decomp, inputSize), "round trip failed!");
1762
1763 free(input);
1764 free(comp);
1765 free(decomp);
1766 }
1767 DISPLAYLEVEL(3, "OK \n");
1768
W. Felix Handtedb4c8d02018-08-24 14:30:21 -07001769 DISPLAYLEVEL(3, "test%3i : dictionary + uncompressible block + reusing tables checks offset table validity: ", testNb++);
1770 { ZSTD_CDict* const cdict = ZSTD_createCDict_advanced(
1771 dictionary.start, dictionary.filled,
1772 ZSTD_dlm_byRef, ZSTD_dct_fullDict,
1773 ZSTD_getCParams(3, 0, dictionary.filled),
1774 ZSTD_defaultCMem);
1775 const size_t inbufsize = 2 * 128 * 1024; /* 2 blocks */
1776 const size_t outbufsize = ZSTD_compressBound(inbufsize);
1777 size_t inbufpos = 0;
1778 size_t cursegmentlen;
1779 BYTE *inbuf = (BYTE *)malloc(inbufsize);
1780 BYTE *outbuf = (BYTE *)malloc(outbufsize);
1781 BYTE *checkbuf = (BYTE *)malloc(inbufsize);
1782 size_t ret;
1783
1784 CHECK(cdict == NULL, "failed to alloc cdict");
1785 CHECK(inbuf == NULL, "failed to alloc input buffer");
Yann Colletd195eec2018-09-13 12:29:52 -07001786
W. Felix Handtedb4c8d02018-08-24 14:30:21 -07001787 /* first block is uncompressible */
1788 cursegmentlen = 128 * 1024;
1789 RDG_genBuffer(inbuf + inbufpos, cursegmentlen, 0., 0., seed);
1790 inbufpos += cursegmentlen;
1791
1792 /* second block is compressible */
1793 cursegmentlen = 128 * 1024 - 256;
1794 RDG_genBuffer(inbuf + inbufpos, cursegmentlen, 0.05, 0., seed);
1795 inbufpos += cursegmentlen;
1796
1797 /* and includes a very long backref */
1798 cursegmentlen = 128;
W. Felix Handtedacbcd22020-05-01 12:24:51 -04001799 memcpy(inbuf + inbufpos, (BYTE*)dictionary.start + 256, cursegmentlen);
W. Felix Handtedb4c8d02018-08-24 14:30:21 -07001800 inbufpos += cursegmentlen;
1801
1802 /* and includes a very long backref */
1803 cursegmentlen = 128;
W. Felix Handtedacbcd22020-05-01 12:24:51 -04001804 memcpy(inbuf + inbufpos, (BYTE*)dictionary.start + 128, cursegmentlen);
W. Felix Handtedb4c8d02018-08-24 14:30:21 -07001805 inbufpos += cursegmentlen;
1806
1807 ret = ZSTD_compress_usingCDict(zc, outbuf, outbufsize, inbuf, inbufpos, cdict);
1808 CHECK_Z(ret);
1809
1810 ret = ZSTD_decompress_usingDict(zd, checkbuf, inbufsize, outbuf, ret, dictionary.start, dictionary.filled);
1811 CHECK_Z(ret);
1812
1813 CHECK(memcmp(inbuf, checkbuf, inbufpos), "start and finish buffers don't match");
1814
1815 ZSTD_freeCDict(cdict);
1816 free(inbuf);
1817 free(outbuf);
1818 free(checkbuf);
1819 }
1820 DISPLAYLEVEL(3, "OK \n");
1821
Nick Terrell146049a2018-09-28 12:09:14 -07001822 DISPLAYLEVEL(3, "test%3i : dictionary + small blocks + reusing tables checks offset table validity: ", testNb++);
1823 { ZSTD_CDict* const cdict = ZSTD_createCDict_advanced(
1824 dictionary.start, dictionary.filled,
1825 ZSTD_dlm_byRef, ZSTD_dct_fullDict,
1826 ZSTD_getCParams(3, 0, dictionary.filled),
1827 ZSTD_defaultCMem);
1828 ZSTD_outBuffer out = {compressedBuffer, compressedBufferSize, 0};
1829 int remainingInput = 256 * 1024;
Nick Terrelleb4423e2018-09-28 14:24:38 -07001830 int offset;
Nick Terrell146049a2018-09-28 12:09:14 -07001831
Yann Collet5c686392018-11-15 16:12:39 -08001832 CHECK_Z(ZSTD_CCtx_reset(zc, ZSTD_reset_session_and_parameters));
Nick Terrell146049a2018-09-28 12:09:14 -07001833 CHECK_Z(ZSTD_CCtx_refCDict(zc, cdict));
Yann Collet3583d192018-12-05 17:26:02 -08001834 CHECK_Z(ZSTD_CCtx_setParameter(zc, ZSTD_c_checksumFlag, 1));
Nick Terrell146049a2018-09-28 12:09:14 -07001835 /* Write a bunch of 6 byte blocks */
1836 while (remainingInput > 0) {
Nick Terrell0e7a7f12018-09-28 12:14:24 -07001837 char testBuffer[6] = "\xAA\xAA\xAA\xAA\xAA\xAA";
1838 const size_t kSmallBlockSize = sizeof(testBuffer);
Nick Terrell146049a2018-09-28 12:09:14 -07001839 ZSTD_inBuffer in = {testBuffer, kSmallBlockSize, 0};
1840
Yann Colletd8e215c2018-11-30 11:16:26 -08001841 CHECK_Z(ZSTD_compressStream2(zc, &out, &in, ZSTD_e_flush));
Nick Terrell146049a2018-09-28 12:09:14 -07001842 CHECK(in.pos != in.size, "input not fully consumed");
1843 remainingInput -= kSmallBlockSize;
1844 }
1845 /* Write several very long offset matches into the dictionary */
Nick Terrelleb4423e2018-09-28 14:24:38 -07001846 for (offset = 1024; offset >= 0; offset -= 128) {
W. Felix Handtedacbcd22020-05-01 12:24:51 -04001847 ZSTD_inBuffer in = {(BYTE*)dictionary.start + offset, 128, 0};
Nick Terrell146049a2018-09-28 12:09:14 -07001848 ZSTD_EndDirective flush = offset > 0 ? ZSTD_e_continue : ZSTD_e_end;
Yann Colletd8e215c2018-11-30 11:16:26 -08001849 CHECK_Z(ZSTD_compressStream2(zc, &out, &in, flush));
Nick Terrell146049a2018-09-28 12:09:14 -07001850 CHECK(in.pos != in.size, "input not fully consumed");
1851 }
1852 /* Ensure decompression works */
1853 CHECK_Z(ZSTD_decompress_usingDict(zd, decodedBuffer, CNBufferSize, out.dst, out.pos, dictionary.start, dictionary.filled));
1854
1855 ZSTD_freeCDict(cdict);
1856 }
1857 DISPLAYLEVEL(3, "OK \n");
1858
Elliott Hughes44aba642023-09-12 20:18:59 +00001859 DISPLAYLEVEL(3, "test%3i : Block-Level External Sequence Producer API: ", testNb++);
1860 {
1861 size_t const dstBufSize = ZSTD_compressBound(CNBufferSize);
1862 BYTE* const dstBuf = (BYTE*)malloc(ZSTD_compressBound(dstBufSize));
1863 size_t const checkBufSize = CNBufferSize;
1864 BYTE* const checkBuf = (BYTE*)malloc(checkBufSize);
1865 int enableFallback;
1866 EMF_testCase sequenceProducerState;
1867
1868 CHECK(dstBuf == NULL || checkBuf == NULL, "allocation failed");
1869
1870 CHECK_Z(ZSTD_CCtx_reset(zc, ZSTD_reset_session_and_parameters));
1871
1872 /* Reference external matchfinder outside the test loop to
1873 * check that the reference is preserved across compressions */
1874 ZSTD_registerSequenceProducer(zc, &sequenceProducerState, zstreamSequenceProducer);
1875
1876 for (enableFallback = 0; enableFallback <= 1; enableFallback++) {
1877 size_t testCaseId;
1878 size_t const numTestCases = 9;
1879
1880 EMF_testCase const testCases[] = {
1881 EMF_ONE_BIG_SEQ,
1882 EMF_LOTS_OF_SEQS,
1883 EMF_ZERO_SEQS,
1884 EMF_BIG_ERROR,
1885 EMF_SMALL_ERROR,
1886 EMF_INVALID_OFFSET,
1887 EMF_INVALID_MATCHLEN,
1888 EMF_INVALID_LITLEN,
1889 EMF_INVALID_LAST_LITS
1890 };
1891
1892 ZSTD_ErrorCode const errorCodes[] = {
1893 ZSTD_error_no_error,
1894 ZSTD_error_no_error,
1895 ZSTD_error_sequenceProducer_failed,
1896 ZSTD_error_sequenceProducer_failed,
1897 ZSTD_error_sequenceProducer_failed,
1898 ZSTD_error_externalSequences_invalid,
1899 ZSTD_error_externalSequences_invalid,
1900 ZSTD_error_externalSequences_invalid,
1901 ZSTD_error_externalSequences_invalid
1902 };
1903
1904 for (testCaseId = 0; testCaseId < numTestCases; testCaseId++) {
1905 size_t res;
1906
1907 int const compressionShouldSucceed = (
1908 (errorCodes[testCaseId] == ZSTD_error_no_error) ||
1909 (enableFallback && errorCodes[testCaseId] == ZSTD_error_sequenceProducer_failed)
1910 );
1911
1912 int const testWithSequenceValidation = (
1913 testCases[testCaseId] == EMF_INVALID_OFFSET
1914 );
1915
1916 sequenceProducerState = testCases[testCaseId];
1917
1918 ZSTD_CCtx_reset(zc, ZSTD_reset_session_only);
1919 CHECK_Z(ZSTD_CCtx_setParameter(zc, ZSTD_c_validateSequences, testWithSequenceValidation));
1920 CHECK_Z(ZSTD_CCtx_setParameter(zc, ZSTD_c_enableSeqProducerFallback, enableFallback));
1921 res = ZSTD_compress2(zc, dstBuf, dstBufSize, CNBuffer, CNBufferSize);
1922
1923 if (compressionShouldSucceed) {
1924 CHECK(ZSTD_isError(res), "EMF: Compression error: %s", ZSTD_getErrorName(res));
1925 CHECK_Z(ZSTD_decompress(checkBuf, checkBufSize, dstBuf, res));
1926 CHECK(memcmp(CNBuffer, checkBuf, CNBufferSize) != 0, "EMF: Corruption!");
1927 } else {
1928 CHECK(!ZSTD_isError(res), "EMF: Should have raised an error!");
1929 CHECK(
1930 ZSTD_getErrorCode(res) != errorCodes[testCaseId],
1931 "EMF: Wrong error code: %s", ZSTD_getErrorName(res)
1932 );
1933 }
1934 }
1935
1936 /* Test compression with external matchfinder + empty src buffer */
1937 {
1938 size_t res;
1939 sequenceProducerState = EMF_ZERO_SEQS;
1940 ZSTD_CCtx_reset(zc, ZSTD_reset_session_only);
1941 CHECK_Z(ZSTD_CCtx_setParameter(zc, ZSTD_c_enableSeqProducerFallback, enableFallback));
1942 res = ZSTD_compress2(zc, dstBuf, dstBufSize, CNBuffer, 0);
1943 CHECK(ZSTD_isError(res), "EMF: Compression error: %s", ZSTD_getErrorName(res));
1944 CHECK(ZSTD_decompress(checkBuf, checkBufSize, dstBuf, res) != 0, "EMF: Empty src round trip failed!");
1945 }
1946 }
1947
1948 /* Test that reset clears the external matchfinder */
1949 CHECK_Z(ZSTD_CCtx_reset(zc, ZSTD_reset_session_and_parameters));
1950 sequenceProducerState = EMF_BIG_ERROR; /* ensure zstd will fail if the matchfinder wasn't cleared */
1951 CHECK_Z(ZSTD_CCtx_setParameter(zc, ZSTD_c_enableSeqProducerFallback, 0));
1952 CHECK_Z(ZSTD_compress2(zc, dstBuf, dstBufSize, CNBuffer, CNBufferSize));
1953
1954 /* Test that registering mFinder == NULL clears the external matchfinder */
1955 ZSTD_CCtx_reset(zc, ZSTD_reset_session_and_parameters);
1956 ZSTD_registerSequenceProducer(zc, &sequenceProducerState, zstreamSequenceProducer);
1957 sequenceProducerState = EMF_BIG_ERROR; /* ensure zstd will fail if the matchfinder wasn't cleared */
1958 CHECK_Z(ZSTD_CCtx_setParameter(zc, ZSTD_c_enableSeqProducerFallback, 0));
1959 ZSTD_registerSequenceProducer(zc, NULL, NULL); /* clear the external matchfinder */
1960 CHECK_Z(ZSTD_compress2(zc, dstBuf, dstBufSize, CNBuffer, CNBufferSize));
1961
1962 /* Test that external matchfinder doesn't interact with older APIs */
1963 ZSTD_CCtx_reset(zc, ZSTD_reset_session_and_parameters);
1964 ZSTD_registerSequenceProducer(zc, &sequenceProducerState, zstreamSequenceProducer);
1965 sequenceProducerState = EMF_BIG_ERROR; /* ensure zstd will fail if the matchfinder is used */
1966 CHECK_Z(ZSTD_CCtx_setParameter(zc, ZSTD_c_enableSeqProducerFallback, 0));
1967 CHECK_Z(ZSTD_compressCCtx(zc, dstBuf, dstBufSize, CNBuffer, CNBufferSize, 3));
1968
1969 /* Test that compression returns the correct error with LDM */
1970 CHECK_Z(ZSTD_CCtx_reset(zc, ZSTD_reset_session_and_parameters));
1971 {
1972 size_t res;
1973 ZSTD_registerSequenceProducer(zc, &sequenceProducerState, zstreamSequenceProducer);
1974 CHECK_Z(ZSTD_CCtx_setParameter(zc, ZSTD_c_enableLongDistanceMatching, ZSTD_ps_enable));
1975 res = ZSTD_compress2(zc, dstBuf, dstBufSize, CNBuffer, CNBufferSize);
1976 CHECK(!ZSTD_isError(res), "EMF: Should have raised an error!");
1977 CHECK(
1978 ZSTD_getErrorCode(res) != ZSTD_error_parameter_combination_unsupported,
1979 "EMF: Wrong error code: %s", ZSTD_getErrorName(res)
1980 );
1981 }
1982
1983#ifdef ZSTD_MULTITHREAD
1984 /* Test that compression returns the correct error with nbWorkers > 0 */
1985 CHECK_Z(ZSTD_CCtx_reset(zc, ZSTD_reset_session_and_parameters));
1986 {
1987 size_t res;
1988 ZSTD_registerSequenceProducer(zc, &sequenceProducerState, zstreamSequenceProducer);
1989 CHECK_Z(ZSTD_CCtx_setParameter(zc, ZSTD_c_nbWorkers, 1));
1990 res = ZSTD_compress2(zc, dstBuf, dstBufSize, CNBuffer, CNBufferSize);
1991 CHECK(!ZSTD_isError(res), "EMF: Should have raised an error!");
1992 CHECK(
1993 ZSTD_getErrorCode(res) != ZSTD_error_parameter_combination_unsupported,
1994 "EMF: Wrong error code: %s", ZSTD_getErrorName(res)
1995 );
1996 }
1997#endif
1998
1999 free(dstBuf);
2000 free(checkBuf);
2001 }
2002 DISPLAYLEVEL(3, "OK \n");
2003
2004
2005 /* Test maxBlockSize cctx param functionality */
2006 DISPLAYLEVEL(3, "test%3i : Testing maxBlockSize PR#3418: ", testNb++);
2007 {
2008 ZSTD_CCtx* cctx = ZSTD_createCCtx();
2009
2010 /* Quick test to make sure maxBlockSize bounds are enforced */
2011 assert(ZSTD_isError(ZSTD_CCtx_setParameter(cctx, ZSTD_c_maxBlockSize, ZSTD_BLOCKSIZE_MAX_MIN - 1)));
2012 assert(ZSTD_isError(ZSTD_CCtx_setParameter(cctx, ZSTD_c_maxBlockSize, ZSTD_BLOCKSIZE_MAX + 1)));
2013
2014 /* Test maxBlockSize < windowSize and windowSize < maxBlockSize*/
2015 {
2016 size_t srcSize = 2 << 10;
2017 void* const src = CNBuffer;
2018 size_t dstSize = ZSTD_compressBound(srcSize);
2019 void* const dst1 = compressedBuffer;
2020 void* const dst2 = (BYTE*)compressedBuffer + dstSize;
2021 size_t size1, size2;
2022 void* const checkBuf = malloc(srcSize);
2023 memset(src, 'x', srcSize);
2024
2025 /* maxBlockSize = 1KB */
2026 CHECK_Z(ZSTD_CCtx_setParameter(cctx, ZSTD_c_maxBlockSize, 1u << 10));
2027 size1 = ZSTD_compress2(cctx, dst1, dstSize, src, srcSize);
2028
2029 if (ZSTD_isError(size1)) goto _output_error;
2030 CHECK_Z(ZSTD_decompress(checkBuf, srcSize, dst1, size1));
2031 CHECK(memcmp(src, checkBuf, srcSize) != 0, "Corruption!");
2032
2033 /* maxBlockSize = 3KB */
2034 CHECK_Z(ZSTD_CCtx_setParameter(cctx, ZSTD_c_maxBlockSize, 3u << 10));
2035 size2 = ZSTD_compress2(cctx, dst2, dstSize, src, srcSize);
2036
2037 if (ZSTD_isError(size2)) goto _output_error;
2038 CHECK_Z(ZSTD_decompress(checkBuf, srcSize, dst2, size2));
2039 CHECK(memcmp(src, checkBuf, srcSize) != 0, "Corruption!");
2040
2041 assert(size1 - size2 == 4); /* We add another RLE block with header + character */
2042 assert(memcmp(dst1, dst2, size2) != 0); /* Compressed output should not be equal */
2043
2044 /* maxBlockSize = 1KB, windowLog = 10 */
2045 CHECK_Z(ZSTD_CCtx_setParameter(cctx, ZSTD_c_maxBlockSize, 1u << 10));
2046 CHECK_Z(ZSTD_CCtx_setParameter(cctx, ZSTD_c_windowLog, 10));
2047 size1 = ZSTD_compress2(cctx, dst1, dstSize, src, srcSize);
2048
2049 if (ZSTD_isError(size1)) goto _output_error;
2050 CHECK_Z(ZSTD_decompress(checkBuf, srcSize, dst1, size1));
2051 CHECK(memcmp(src, checkBuf, srcSize) != 0, "Corruption!");
2052
2053 /* maxBlockSize = 3KB, windowLog = 10 */
2054 CHECK_Z(ZSTD_CCtx_setParameter(cctx, ZSTD_c_maxBlockSize, 3u << 10));
2055 CHECK_Z(ZSTD_CCtx_setParameter(cctx, ZSTD_c_windowLog, 10));
2056 size2 = ZSTD_compress2(cctx, dst2, dstSize, src, srcSize);
2057
2058 if (ZSTD_isError(size2)) goto _output_error;
2059 CHECK_Z(ZSTD_decompress(checkBuf, srcSize, dst2, size2));
2060 CHECK(memcmp(src, checkBuf, srcSize) != 0, "Corruption!");
2061
2062 assert(size1 == size2);
2063 assert(memcmp(dst1, dst2, size1) == 0); /* Compressed output should be equal */
2064
2065 free(checkBuf);
2066 }
2067
2068 ZSTD_CCtx_reset(cctx, ZSTD_reset_session_and_parameters);
2069
2070 /* Test maxBlockSize = 0 is valid */
2071 { size_t srcSize = 256 << 10;
2072 void* const src = CNBuffer;
2073 size_t dstSize = ZSTD_compressBound(srcSize);
2074 void* const dst1 = compressedBuffer;
2075 void* const dst2 = (BYTE*)compressedBuffer + dstSize;
2076 size_t size1, size2;
2077 void* const checkBuf = malloc(srcSize);
2078
2079 /* maxBlockSize = 0 */
2080 CHECK_Z(ZSTD_CCtx_setParameter(cctx, ZSTD_c_maxBlockSize, 0));
2081 size1 = ZSTD_compress2(cctx, dst1, dstSize, src, srcSize);
2082
2083 if (ZSTD_isError(size1)) goto _output_error;
2084 CHECK_Z(ZSTD_decompress(checkBuf, srcSize, dst1, size1));
2085 CHECK(memcmp(src, checkBuf, srcSize) != 0, "Corruption!");
2086
2087 /* maxBlockSize = ZSTD_BLOCKSIZE_MAX */
2088 CHECK_Z(ZSTD_CCtx_setParameter(cctx, ZSTD_c_maxBlockSize, ZSTD_BLOCKSIZE_MAX));
2089 size2 = ZSTD_compress2(cctx, dst2, dstSize, src, srcSize);
2090
2091 if (ZSTD_isError(size2)) goto _output_error;
2092 CHECK_Z(ZSTD_decompress(checkBuf, srcSize, dst2, size2));
2093 CHECK(memcmp(src, checkBuf, srcSize) != 0, "Corruption!");
2094
2095 assert(size1 == size2);
2096 assert(memcmp(dst1, dst2, size1) == 0); /* Compressed output should be equal */
2097 free(checkBuf);
2098 }
2099 ZSTD_freeCCtx(cctx);
2100 }
2101 DISPLAYLEVEL(3, "OK \n");
2102
2103 /* Test Sequence Validation */
2104 DISPLAYLEVEL(3, "test%3i : Testing sequence validation: ", testNb++);
2105 {
2106 ZSTD_CCtx* cctx = ZSTD_createCCtx();
2107
2108 /* Test minMatch >= 4, matchLength < 4 */
2109 {
2110 size_t srcSize = 11;
2111 void* const src = CNBuffer;
2112 size_t dstSize = ZSTD_compressBound(srcSize);
2113 void* const dst = compressedBuffer;
2114 size_t const kNbSequences = 4;
2115 ZSTD_Sequence* sequences = malloc(sizeof(ZSTD_Sequence) * kNbSequences);
2116
2117 memset(src, 'x', srcSize);
2118
2119 sequences[0] = (ZSTD_Sequence) {1, 1, 3, 0};
2120 sequences[1] = (ZSTD_Sequence) {1, 0, 3, 0};
2121 sequences[2] = (ZSTD_Sequence) {1, 0, 3, 0};
2122 sequences[3] = (ZSTD_Sequence) {0, 1, 0, 0};
2123
2124 /* Test with sequence validation */
2125 CHECK_Z(ZSTD_CCtx_setParameter(cctx, ZSTD_c_minMatch, 5));
2126 CHECK_Z(ZSTD_CCtx_setParameter(cctx, ZSTD_c_blockDelimiters, ZSTD_sf_explicitBlockDelimiters));
2127 CHECK_Z(ZSTD_CCtx_setParameter(cctx, ZSTD_c_validateSequences, 1));
2128
2129 cSize = ZSTD_compressSequences(cctx, dst, dstSize,
2130 sequences, kNbSequences,
2131 src, srcSize);
2132
2133 CHECK(!ZSTD_isError(cSize), "Should throw an error"); /* maxNbSeq is too small and an assert will fail */
2134 CHECK(ZSTD_getErrorCode(cSize) != ZSTD_error_externalSequences_invalid, "Wrong error code: %s", ZSTD_getErrorName(cSize)); /* fails sequence validation */
2135
2136 ZSTD_CCtx_reset(cctx, ZSTD_reset_session_and_parameters);
2137
2138 /* Test without sequence validation */
2139 CHECK_Z(ZSTD_CCtx_setParameter(cctx, ZSTD_c_minMatch, 5));
2140 CHECK_Z(ZSTD_CCtx_setParameter(cctx, ZSTD_c_blockDelimiters, ZSTD_sf_explicitBlockDelimiters));
2141 CHECK_Z(ZSTD_CCtx_setParameter(cctx, ZSTD_c_validateSequences, 0));
2142
2143 cSize = ZSTD_compressSequences(cctx, dst, dstSize,
2144 sequences, kNbSequences,
2145 src, srcSize);
2146
2147 CHECK(!ZSTD_isError(cSize), "Should throw an error"); /* maxNbSeq is too small and an assert will fail */
2148 CHECK(ZSTD_getErrorCode(cSize) != ZSTD_error_externalSequences_invalid, "Wrong error code: %s", ZSTD_getErrorName(cSize)); /* fails sequence validation */
2149
2150 free(sequences);
2151 }
2152
2153 ZSTD_CCtx_reset(cctx, ZSTD_reset_session_and_parameters);
2154
2155
2156 /* Test with no block delim */
2157 {
2158 size_t srcSize = 4;
2159 void* const src = CNBuffer;
2160 size_t dstSize = ZSTD_compressBound(srcSize);
2161 void* const dst = compressedBuffer;
2162 size_t const kNbSequences = 1;
2163 ZSTD_Sequence* sequences = malloc(sizeof(ZSTD_Sequence) * kNbSequences);
2164 void* const checkBuf = malloc(srcSize);
2165
2166 memset(src, 'x', srcSize);
2167
2168 sequences[0] = (ZSTD_Sequence) {1, 1, 3, 0};
2169
2170 /* Test with sequence validation */
2171 CHECK_Z(ZSTD_CCtx_setParameter(cctx, ZSTD_c_minMatch, 3));
2172 CHECK_Z(ZSTD_CCtx_setParameter(cctx, ZSTD_c_blockDelimiters, ZSTD_sf_noBlockDelimiters));
2173 CHECK_Z(ZSTD_CCtx_setParameter(cctx, ZSTD_c_validateSequences, 1));
2174
2175 cSize = ZSTD_compressSequences(cctx, dst, dstSize,
2176 sequences, kNbSequences,
2177 src, srcSize);
2178
2179 CHECK(ZSTD_isError(cSize), "Should not throw an error");
2180 CHECK_Z(ZSTD_decompress(checkBuf, srcSize, dst, cSize));
2181 CHECK(memcmp(src, checkBuf, srcSize) != 0, "Corruption!");
2182
2183 free(sequences);
2184 free(checkBuf);
2185 }
2186
2187 ZSTD_CCtx_reset(cctx, ZSTD_reset_session_and_parameters);
2188
2189 { /* Test case with two additional sequences */
2190 size_t srcSize = 19;
2191 void* const src = CNBuffer;
2192 size_t dstSize = ZSTD_compressBound(srcSize);
2193 void* const dst = compressedBuffer;
2194 size_t const kNbSequences = 7;
2195 ZSTD_Sequence* sequences = malloc(sizeof(ZSTD_Sequence) * kNbSequences);
2196
2197 memset(src, 'x', srcSize);
2198
2199 sequences[0] = (ZSTD_Sequence) {1, 1, 3, 0};
2200 sequences[1] = (ZSTD_Sequence) {1, 0, 3, 0};
2201 sequences[2] = (ZSTD_Sequence) {1, 0, 3, 0};
2202 sequences[3] = (ZSTD_Sequence) {1, 0, 3, 0};
2203 sequences[4] = (ZSTD_Sequence) {1, 0, 3, 0};
2204 sequences[5] = (ZSTD_Sequence) {1, 0, 3, 0};
2205 sequences[6] = (ZSTD_Sequence) {0, 0, 0, 0};
2206
2207 CHECK_Z(ZSTD_CCtx_setParameter(cctx, ZSTD_c_minMatch, 5));
2208 CHECK_Z(ZSTD_CCtx_setParameter(cctx, ZSTD_c_blockDelimiters, ZSTD_sf_explicitBlockDelimiters));
2209 CHECK_Z(ZSTD_CCtx_setParameter(cctx, ZSTD_c_validateSequences, 1));
2210
2211 cSize = ZSTD_compressSequences(cctx, dst, dstSize,
2212 sequences, kNbSequences,
2213 src, srcSize);
2214
2215 CHECK(!ZSTD_isError(cSize), "Should throw an error"); /* maxNbSeq is too small and an assert will fail */
2216 CHECK(ZSTD_getErrorCode(cSize) != ZSTD_error_externalSequences_invalid, "Wrong error code: %s", ZSTD_getErrorName(cSize)); /* fails sequence validation */
2217
2218 ZSTD_CCtx_reset(cctx, ZSTD_reset_session_and_parameters);
2219
2220 /* Test without sequence validation */
2221 CHECK_Z(ZSTD_CCtx_setParameter(cctx, ZSTD_c_minMatch, 5));
2222 CHECK_Z(ZSTD_CCtx_setParameter(cctx, ZSTD_c_blockDelimiters, ZSTD_sf_explicitBlockDelimiters));
2223 CHECK_Z(ZSTD_CCtx_setParameter(cctx, ZSTD_c_validateSequences, 0));
2224
2225 cSize = ZSTD_compressSequences(cctx, dst, dstSize,
2226 sequences, kNbSequences,
2227 src, srcSize);
2228
2229 CHECK(!ZSTD_isError(cSize), "Should throw an error"); /* maxNbSeq is too small and an assert will fail */
2230 CHECK(ZSTD_getErrorCode(cSize) != ZSTD_error_externalSequences_invalid, "Wrong error code: %s", ZSTD_getErrorName(cSize)); /* fails sequence validation */
2231
2232 free(sequences);
2233 }
2234 ZSTD_freeCCtx(cctx);
2235 }
2236 DISPLAYLEVEL(3, "OK \n");
2237
2238
2239 DISPLAYLEVEL(3, "test%3i : Testing large offset with small window size: ", testNb++);
2240 {
2241 ZSTD_CCtx* cctx = ZSTD_createCCtx();
2242 ZSTD_DCtx* dctx = ZSTD_createDCtx();
2243
2244 /* Test large offset, small window size*/
2245 {
2246 size_t srcSize = 21;
2247 void* const src = CNBuffer;
2248 size_t dstSize = ZSTD_compressBound(srcSize);
2249 void* const dst = compressedBuffer;
2250 size_t const kNbSequences = 4;
2251 ZSTD_Sequence* sequences = malloc(sizeof(ZSTD_Sequence) * kNbSequences);
2252 void* const checkBuf = malloc(srcSize);
2253 const size_t largeDictSize = 1 << 25;
2254 ZSTD_CDict* cdict = NULL;
2255 ZSTD_DDict* ddict = NULL;
2256
2257 /* Generate large dictionary */
2258 void* dictBuffer = calloc(largeDictSize, 1);
2259 ZSTD_compressionParameters cParams = ZSTD_getCParams(1, srcSize, largeDictSize);
2260 cParams.minMatch = ZSTD_MINMATCH_MIN;
2261 cParams.hashLog = ZSTD_HASHLOG_MIN;
2262 cParams.chainLog = ZSTD_CHAINLOG_MIN;
2263
2264 cdict = ZSTD_createCDict_advanced(dictBuffer, largeDictSize, ZSTD_dlm_byRef, ZSTD_dct_rawContent, cParams, ZSTD_defaultCMem);
2265 ddict = ZSTD_createDDict_advanced(dictBuffer, largeDictSize, ZSTD_dlm_byRef, ZSTD_dct_rawContent, ZSTD_defaultCMem);
2266
2267 ZSTD_CCtx_refCDict(cctx, cdict);
2268 ZSTD_DCtx_refDDict(dctx, ddict);
2269
2270 sequences[0] = (ZSTD_Sequence) {3, 3, 3, 0};
2271 sequences[1] = (ZSTD_Sequence) {1 << 25, 0, 3, 0};
2272 sequences[2] = (ZSTD_Sequence) {1 << 25, 0, 9, 0};
2273 sequences[3] = (ZSTD_Sequence) {3, 0, 3, 0};
2274
2275 cSize = ZSTD_compressSequences(cctx, dst, dstSize,
2276 sequences, kNbSequences,
2277 src, srcSize);
2278
2279 CHECK(ZSTD_isError(cSize), "Should not throw an error");
2280
2281 {
2282 size_t dSize = ZSTD_decompressDCtx(dctx, checkBuf, srcSize, dst, cSize);
2283 CHECK(ZSTD_isError(dSize), "Should not throw an error");
2284 CHECK(memcmp(src, checkBuf, srcSize) != 0, "Corruption!");
2285 }
2286
2287 free(sequences);
2288 free(checkBuf);
2289 free(dictBuffer);
2290 ZSTD_freeCDict(cdict);
2291 ZSTD_freeDDict(ddict);
2292 }
2293 ZSTD_freeCCtx(cctx);
2294 ZSTD_freeDCtx(dctx);
2295 }
2296 DISPLAYLEVEL(3, "OK \n");
2297
Yann Colletd7883a22016-08-12 16:48:02 +02002298_end:
Yann Collet33fce032017-01-16 19:46:22 -08002299 FUZ_freeDictionary(dictionary);
Yann Colletd7883a22016-08-12 16:48:02 +02002300 ZSTD_freeCStream(zc);
2301 ZSTD_freeDStream(zd);
Nick Terrellc51a9e72020-10-01 18:47:54 -07002302 ZSTD_freeCCtx(mtctx);
Yann Colletd7883a22016-08-12 16:48:02 +02002303 free(CNBuffer);
2304 free(compressedBuffer);
2305 free(decodedBuffer);
2306 return testResult;
2307
2308_output_error:
2309 testResult = 1;
2310 DISPLAY("Error detected in Unit tests ! \n");
2311 goto _end;
2312}
2313
2314
Yann Collet3ecbe6a2016-09-14 17:26:59 +02002315/* ====== Fuzzer tests ====== */
2316
Yann Colletd7883a22016-08-12 16:48:02 +02002317static size_t findDiff(const void* buf1, const void* buf2, size_t max)
2318{
2319 const BYTE* b1 = (const BYTE*)buf1;
2320 const BYTE* b2 = (const BYTE*)buf2;
2321 size_t u;
2322 for (u=0; u<max; u++) {
2323 if (b1[u] != b2[u]) break;
2324 }
Yann Collet940634a2018-01-19 13:19:59 -08002325 if (u==max) {
Yann Colletededcfc2018-12-21 16:19:44 -08002326 DISPLAY("=> No difference detected within %u bytes \n", (unsigned)max);
Yann Collet940634a2018-01-19 13:19:59 -08002327 return u;
2328 }
Yann Colletededcfc2018-12-21 16:19:44 -08002329 DISPLAY("Error at position %u / %u \n", (unsigned)u, (unsigned)max);
Yann Colletdc696232018-01-19 12:41:56 -08002330 if (u>=3)
2331 DISPLAY(" %02X %02X %02X ",
2332 b1[u-3], b1[u-2], b1[u-1]);
2333 DISPLAY(" :%02X: %02X %02X %02X %02X %02X \n",
2334 b1[u], b1[u+1], b1[u+2], b1[u+3], b1[u+4], b1[u+5]);
2335 if (u>=3)
2336 DISPLAY(" %02X %02X %02X ",
2337 b2[u-3], b2[u-2], b2[u-1]);
2338 DISPLAY(" :%02X: %02X %02X %02X %02X %02X \n",
2339 b2[u], b2[u+1], b2[u+2], b2[u+3], b2[u+4], b2[u+5]);
Yann Colletd7883a22016-08-12 16:48:02 +02002340 return u;
2341}
2342
2343static size_t FUZ_rLogLength(U32* seed, U32 logLength)
2344{
2345 size_t const lengthMask = ((size_t)1 << logLength) - 1;
2346 return (lengthMask+1) + (FUZ_rand(seed) & lengthMask);
2347}
2348
2349static size_t FUZ_randomLength(U32* seed, U32 maxLog)
2350{
2351 U32 const logLength = FUZ_rand(seed) % maxLog;
2352 return FUZ_rLogLength(seed, logLength);
2353}
2354
Stella Lau9e406022017-09-06 08:39:46 -07002355/* Return value in range minVal <= v <= maxVal */
2356static U32 FUZ_randomClampedLength(U32* seed, U32 minVal, U32 maxVal)
2357{
2358 U32 const mod = maxVal < minVal ? 1 : (maxVal + 1) - minVal;
2359 return (U32)((FUZ_rand(seed) % mod) + minVal);
2360}
2361
Yann Colletededcfc2018-12-21 16:19:44 -08002362static int fuzzerTests(U32 seed, unsigned nbTests, unsigned startTest, double compressibility, int bigTests)
Yann Colletd7883a22016-08-12 16:48:02 +02002363{
Yann Colletf99c2c12017-06-21 23:35:58 -07002364 U32 const maxSrcLog = bigTests ? 24 : 22;
Yann Colletd7883a22016-08-12 16:48:02 +02002365 static const U32 maxSampleLog = 19;
Yann Collet58d5dfe2016-09-25 01:34:03 +02002366 size_t const srcBufferSize = (size_t)1<<maxSrcLog;
Yann Colletd7883a22016-08-12 16:48:02 +02002367 BYTE* cNoiseBuffer[5];
Yann Colletbc32b402017-09-27 17:27:38 -07002368 size_t const copyBufferSize = srcBufferSize + (1<<maxSampleLog);
Yann Collet58d5dfe2016-09-25 01:34:03 +02002369 BYTE* const copyBuffer = (BYTE*)malloc (copyBufferSize);
Yann Colletbc32b402017-09-27 17:27:38 -07002370 size_t const cBufferSize = ZSTD_compressBound(srcBufferSize);
Yann Collet58d5dfe2016-09-25 01:34:03 +02002371 BYTE* const cBuffer = (BYTE*)malloc (cBufferSize);
2372 size_t const dstBufferSize = srcBufferSize;
2373 BYTE* const dstBuffer = (BYTE*)malloc (dstBufferSize);
Yann Colletd7883a22016-08-12 16:48:02 +02002374 U32 result = 0;
Yann Colletededcfc2018-12-21 16:19:44 -08002375 unsigned testNb = 0;
Yann Colletd7883a22016-08-12 16:48:02 +02002376 U32 coreSeed = seed;
Yann Colletbc32b402017-09-27 17:27:38 -07002377 ZSTD_CStream* zc = ZSTD_createCStream(); /* will be re-created sometimes */
2378 ZSTD_DStream* zd = ZSTD_createDStream(); /* will be re-created sometimes */
Yann Collet58d5dfe2016-09-25 01:34:03 +02002379 ZSTD_DStream* const zd_noise = ZSTD_createDStream();
Nick Terrell9a2f6f42017-11-29 19:11:12 -08002380 UTIL_time_t const startClock = UTIL_getTime();
Yann Colletbc32b402017-09-27 17:27:38 -07002381 const BYTE* dict = NULL; /* can keep same dict on 2 consecutive tests */
Yann Colletcf409a72016-09-26 16:41:05 +02002382 size_t dictSize = 0;
2383 U32 oldTestLog = 0;
Yann Collet49f84592017-06-21 18:43:39 -07002384 U32 const cLevelMax = bigTests ? (U32)ZSTD_maxCLevel() : g_cLevelMax_smallTests;
Yann Colletd7883a22016-08-12 16:48:02 +02002385
2386 /* allocations */
Yann Colletd7883a22016-08-12 16:48:02 +02002387 cNoiseBuffer[0] = (BYTE*)malloc (srcBufferSize);
2388 cNoiseBuffer[1] = (BYTE*)malloc (srcBufferSize);
2389 cNoiseBuffer[2] = (BYTE*)malloc (srcBufferSize);
2390 cNoiseBuffer[3] = (BYTE*)malloc (srcBufferSize);
2391 cNoiseBuffer[4] = (BYTE*)malloc (srcBufferSize);
Yann Colletd7883a22016-08-12 16:48:02 +02002392 CHECK (!cNoiseBuffer[0] || !cNoiseBuffer[1] || !cNoiseBuffer[2] || !cNoiseBuffer[3] || !cNoiseBuffer[4] ||
Yann Collet58d5dfe2016-09-25 01:34:03 +02002393 !copyBuffer || !dstBuffer || !cBuffer || !zc || !zd || !zd_noise ,
Yann Colletd7883a22016-08-12 16:48:02 +02002394 "Not enough memory, fuzzer tests cancelled");
2395
2396 /* Create initial samples */
2397 RDG_genBuffer(cNoiseBuffer[0], srcBufferSize, 0.00, 0., coreSeed); /* pure noise */
2398 RDG_genBuffer(cNoiseBuffer[1], srcBufferSize, 0.05, 0., coreSeed); /* barely compressible */
2399 RDG_genBuffer(cNoiseBuffer[2], srcBufferSize, compressibility, 0., coreSeed);
2400 RDG_genBuffer(cNoiseBuffer[3], srcBufferSize, 0.95, 0., coreSeed); /* highly compressible */
2401 RDG_genBuffer(cNoiseBuffer[4], srcBufferSize, 1.00, 0., coreSeed); /* sparse content */
2402 memset(copyBuffer, 0x65, copyBufferSize); /* make copyBuffer considered initialized */
Yann Collet58d5dfe2016-09-25 01:34:03 +02002403 ZSTD_initDStream_usingDict(zd, NULL, 0); /* ensure at least one init */
Yann Colletd7883a22016-08-12 16:48:02 +02002404
2405 /* catch up testNb */
2406 for (testNb=1; testNb < startTest; testNb++)
2407 FUZ_rand(&coreSeed);
2408
2409 /* test loop */
Nick Terrell9a2f6f42017-11-29 19:11:12 -08002410 for ( ; (testNb <= nbTests) || (UTIL_clockSpanMicro(startClock) < g_clockTime) ; testNb++ ) {
Yann Colletd7883a22016-08-12 16:48:02 +02002411 U32 lseed;
2412 const BYTE* srcBuffer;
Yann Collet58d5dfe2016-09-25 01:34:03 +02002413 size_t totalTestSize, totalGenSize, cSize;
Yann Colletd7883a22016-08-12 16:48:02 +02002414 XXH64_state_t xxhState;
2415 U64 crcOrig;
Yann Collet58d5dfe2016-09-25 01:34:03 +02002416 U32 resetAllowed = 1;
Yann Colletcf409a72016-09-26 16:41:05 +02002417 size_t maxTestSize;
Yann Colletd7883a22016-08-12 16:48:02 +02002418
2419 /* init */
Yann Colletd7883a22016-08-12 16:48:02 +02002420 FUZ_rand(&coreSeed);
Yann Collet33fce032017-01-16 19:46:22 -08002421 lseed = coreSeed ^ prime32;
Yann Collet3ad7d492018-01-19 17:35:08 -08002422 if (nbTests >= testNb) {
Yann Collet9c40ae72018-01-26 17:48:33 -08002423 DISPLAYUPDATE(2, "\r%6u/%6u ", testNb, nbTests);
Yann Collet3ad7d492018-01-19 17:35:08 -08002424 } else {
Yann Collet9c40ae72018-01-26 17:48:33 -08002425 DISPLAYUPDATE(2, "\r%6u ", testNb);
Yann Collet3ad7d492018-01-19 17:35:08 -08002426 }
Yann Colletd7883a22016-08-12 16:48:02 +02002427
Yann Collet3ecbe6a2016-09-14 17:26:59 +02002428 /* states full reset (deliberately not synchronized) */
2429 /* some issues can only happen when reusing states */
Yann Colleted1d0392017-06-19 11:07:33 -07002430 if ((FUZ_rand(&lseed) & 0xFF) == 131) {
2431 ZSTD_freeCStream(zc);
2432 zc = ZSTD_createCStream();
Yann Colletdce78922017-06-21 15:53:42 -07002433 CHECK(zc==NULL, "ZSTD_createCStream : allocation error");
Yann Colleted1d0392017-06-19 11:07:33 -07002434 resetAllowed=0;
2435 }
2436 if ((FUZ_rand(&lseed) & 0xFF) == 132) {
2437 ZSTD_freeDStream(zd);
2438 zd = ZSTD_createDStream();
Yann Colletdce78922017-06-21 15:53:42 -07002439 CHECK(zd==NULL, "ZSTD_createDStream : allocation error");
2440 CHECK_Z( ZSTD_initDStream_usingDict(zd, NULL, 0) ); /* ensure at least one init */
Yann Colleted1d0392017-06-19 11:07:33 -07002441 }
Yann Colletd7883a22016-08-12 16:48:02 +02002442
2443 /* srcBuffer selection [0-4] */
2444 { U32 buffNb = FUZ_rand(&lseed) & 0x7F;
2445 if (buffNb & 7) buffNb=2; /* most common : compressible (P) */
2446 else {
2447 buffNb >>= 3;
2448 if (buffNb & 7) {
2449 const U32 tnb[2] = { 1, 3 }; /* barely/highly compressible */
2450 buffNb = tnb[buffNb >> 3];
2451 } else {
2452 const U32 tnb[2] = { 0, 4 }; /* not compressible / sparse */
2453 buffNb = tnb[buffNb >> 3];
2454 } }
2455 srcBuffer = cNoiseBuffer[buffNb];
2456 }
2457
2458 /* compression init */
Yann Colletcf409a72016-09-26 16:41:05 +02002459 if ((FUZ_rand(&lseed)&1) /* at beginning, to keep same nb of rand */
2460 && oldTestLog /* at least one test happened */ && resetAllowed) {
2461 maxTestSize = FUZ_randomLength(&lseed, oldTestLog+2);
Yann Colletbc32b402017-09-27 17:27:38 -07002462 maxTestSize = MIN(maxTestSize, srcBufferSize-16);
Nick Terrell91f58912021-12-01 11:49:58 -08002463 { U64 const pledgedSrcSize = (FUZ_rand(&lseed) & 3) ? ZSTD_CONTENTSIZE_UNKNOWN : maxTestSize;
sen698f2612021-05-06 17:59:32 -04002464 CHECK_Z( ZSTD_CCtx_reset(zc, ZSTD_reset_session_only) );
2465 CHECK_Z( ZSTD_CCtx_setPledgedSrcSize(zc, pledgedSrcSize) );
Yann Colletcf409a72016-09-26 16:41:05 +02002466 }
Yann Collet58d5dfe2016-09-25 01:34:03 +02002467 } else {
2468 U32 const testLog = FUZ_rand(&lseed) % maxSrcLog;
Sean Purcellf5e50512017-03-15 15:04:54 -07002469 U32 const dictLog = FUZ_rand(&lseed) % maxSrcLog;
Yann Colletbfc2f002017-06-21 17:57:14 -07002470 U32 const cLevelCandidate = ( FUZ_rand(&lseed) %
Sean Purcell7ebf2de2017-03-20 11:25:00 -07002471 (ZSTD_maxCLevel() -
Yann Colletbfc2f002017-06-21 17:57:14 -07002472 (MAX(testLog, dictLog) / 3)))
Yann Colletce800982017-04-05 16:34:09 -07002473 + 1;
Yann Colletbfc2f002017-06-21 17:57:14 -07002474 U32 const cLevel = MIN(cLevelCandidate, cLevelMax);
Yann Colletd7883a22016-08-12 16:48:02 +02002475 maxTestSize = FUZ_rLogLength(&lseed, testLog);
Yann Colletcf409a72016-09-26 16:41:05 +02002476 oldTestLog = testLog;
Yann Colletd7883a22016-08-12 16:48:02 +02002477 /* random dictionary selection */
Yann Colletf99c2c12017-06-21 23:35:58 -07002478 dictSize = ((FUZ_rand(&lseed)&7)==1) ? FUZ_rLogLength(&lseed, dictLog) : 0;
Yann Colletd7883a22016-08-12 16:48:02 +02002479 { size_t const dictStart = FUZ_rand(&lseed) % (srcBufferSize - dictSize);
2480 dict = srcBuffer + dictStart;
2481 }
Yann Collet213ef3b2017-10-13 19:01:58 -07002482 { U64 const pledgedSrcSize = (FUZ_rand(&lseed) & 3) ? ZSTD_CONTENTSIZE_UNKNOWN : maxTestSize;
sen698f2612021-05-06 17:59:32 -04002483 CHECK_Z( ZSTD_CCtx_reset(zc, ZSTD_reset_session_only) );
2484 CHECK_Z( ZSTD_CCtx_setParameter(zc, ZSTD_c_compressionLevel, cLevel) );
2485 CHECK_Z( ZSTD_CCtx_setParameter(zc, ZSTD_c_checksumFlag, FUZ_rand(&lseed) & 1) );
2486 CHECK_Z( ZSTD_CCtx_setParameter(zc, ZSTD_c_contentSizeFlag, FUZ_rand(&lseed) & 1) );
2487 CHECK_Z( ZSTD_CCtx_setParameter(zc, ZSTD_c_dictIDFlag, FUZ_rand(&lseed) & 1) );
2488 CHECK_Z( ZSTD_CCtx_setPledgedSrcSize(zc, pledgedSrcSize) );
2489 CHECK_Z( ZSTD_CCtx_loadDictionary(zc, dict, dictSize) );
Yann Collet01743a32017-06-16 17:56:41 -07002490 } }
Yann Colletd7883a22016-08-12 16:48:02 +02002491
2492 /* multi-segments compression test */
2493 XXH64_reset(&xxhState, 0);
Yann Collet2f263942016-09-26 14:06:08 +02002494 { ZSTD_outBuffer outBuff = { cBuffer, cBufferSize, 0 } ;
Elliott Hughes44aba642023-09-12 20:18:59 +00002495 cSize=0;
2496 totalTestSize=0;
2497 while(totalTestSize < maxTestSize) {
Yann Collete795c8a2016-12-13 16:39:36 +01002498 /* compress random chunks into randomly sized dst buffers */
Yann Collet2f263942016-09-26 14:06:08 +02002499 { size_t const randomSrcSize = FUZ_randomLength(&lseed, maxSampleLog);
Yann Collet150354c2017-11-01 16:57:48 -07002500 size_t const srcSize = MIN(maxTestSize-totalTestSize, randomSrcSize);
Yann Collet2f263942016-09-26 14:06:08 +02002501 size_t const srcStart = FUZ_rand(&lseed) % (srcBufferSize - srcSize);
Yann Colletd7883a22016-08-12 16:48:02 +02002502 size_t const randomDstSize = FUZ_randomLength(&lseed, maxSampleLog);
2503 size_t const dstBuffSize = MIN(cBufferSize - cSize, randomDstSize);
Yann Collet2f263942016-09-26 14:06:08 +02002504 ZSTD_inBuffer inBuff = { srcBuffer+srcStart, srcSize, 0 };
Yann Collet53e17fb2016-08-17 01:39:22 +02002505 outBuff.size = outBuff.pos + dstBuffSize;
Yann Colletd7883a22016-08-12 16:48:02 +02002506
Yann Colleted1d0392017-06-19 11:07:33 -07002507 CHECK_Z( ZSTD_compressStream(zc, &outBuff, &inBuff) );
Yann Colletd7883a22016-08-12 16:48:02 +02002508
Yann Collet53e17fb2016-08-17 01:39:22 +02002509 XXH64_update(&xxhState, srcBuffer+srcStart, inBuff.pos);
2510 memcpy(copyBuffer+totalTestSize, srcBuffer+srcStart, inBuff.pos);
2511 totalTestSize += inBuff.pos;
Yann Colletd7883a22016-08-12 16:48:02 +02002512 }
2513
2514 /* random flush operation, to mess around */
2515 if ((FUZ_rand(&lseed) & 15) == 0) {
2516 size_t const randomDstSize = FUZ_randomLength(&lseed, maxSampleLog);
Yann Collet53e17fb2016-08-17 01:39:22 +02002517 size_t const adjustedDstSize = MIN(cBufferSize - cSize, randomDstSize);
2518 outBuff.size = outBuff.pos + adjustedDstSize;
Yann Colleted1d0392017-06-19 11:07:33 -07002519 CHECK_Z( ZSTD_flushStream(zc, &outBuff) );
2520 } }
Yann Colletd7883a22016-08-12 16:48:02 +02002521
2522 /* final frame epilogue */
2523 { size_t remainingToFlush = (size_t)(-1);
2524 while (remainingToFlush) {
2525 size_t const randomDstSize = FUZ_randomLength(&lseed, maxSampleLog);
2526 size_t const adjustedDstSize = MIN(cBufferSize - cSize, randomDstSize);
Yann Collet53e17fb2016-08-17 01:39:22 +02002527 outBuff.size = outBuff.pos + adjustedDstSize;
2528 remainingToFlush = ZSTD_endStream(zc, &outBuff);
Yann Collet009d6042017-05-19 10:17:59 -07002529 CHECK (ZSTD_isError(remainingToFlush), "end error : %s", ZSTD_getErrorName(remainingToFlush));
Yann Colletd7883a22016-08-12 16:48:02 +02002530 } }
2531 crcOrig = XXH64_digest(&xxhState);
Yann Collet53e17fb2016-08-17 01:39:22 +02002532 cSize = outBuff.pos;
Yann Colletd7883a22016-08-12 16:48:02 +02002533 }
2534
2535 /* multi - fragments decompression test */
Yann Collet58d5dfe2016-09-25 01:34:03 +02002536 if (!dictSize /* don't reset if dictionary : could be different */ && (FUZ_rand(&lseed) & 1)) {
Yann Colletdce78922017-06-21 15:53:42 -07002537 CHECK_Z ( ZSTD_resetDStream(zd) );
Yann Collet9ffbeea2016-12-02 18:37:38 -08002538 } else {
Yann Colletdce78922017-06-21 15:53:42 -07002539 CHECK_Z ( ZSTD_initDStream_usingDict(zd, dict, dictSize) );
Yann Collet9ffbeea2016-12-02 18:37:38 -08002540 }
Yann Colletd7883a22016-08-12 16:48:02 +02002541 { size_t decompressionResult = 1;
Yann Collet53e17fb2016-08-17 01:39:22 +02002542 ZSTD_inBuffer inBuff = { cBuffer, cSize, 0 };
2543 ZSTD_outBuffer outBuff= { dstBuffer, dstBufferSize, 0 };
2544 for (totalGenSize = 0 ; decompressionResult ; ) {
Yann Colletd7883a22016-08-12 16:48:02 +02002545 size_t const readCSrcSize = FUZ_randomLength(&lseed, maxSampleLog);
2546 size_t const randomDstSize = FUZ_randomLength(&lseed, maxSampleLog);
2547 size_t const dstBuffSize = MIN(dstBufferSize - totalGenSize, randomDstSize);
Yann Collet53e17fb2016-08-17 01:39:22 +02002548 inBuff.size = inBuff.pos + readCSrcSize;
Yann Colletca306c12017-09-27 00:39:41 -07002549 outBuff.size = outBuff.pos + dstBuffSize;
Yann Collet53e17fb2016-08-17 01:39:22 +02002550 decompressionResult = ZSTD_decompressStream(zd, &outBuff, &inBuff);
Yann Colletb3f33cc2017-09-09 14:37:28 -07002551 if (ZSTD_getErrorCode(decompressionResult) == ZSTD_error_checksum_wrong) {
2552 DISPLAY("checksum error : \n");
2553 findDiff(copyBuffer, dstBuffer, totalTestSize);
2554 }
2555 CHECK( ZSTD_isError(decompressionResult), "decompression error : %s",
2556 ZSTD_getErrorName(decompressionResult) );
Yann Colletd7883a22016-08-12 16:48:02 +02002557 }
2558 CHECK (decompressionResult != 0, "frame not fully decoded");
Yann Colletb3f33cc2017-09-09 14:37:28 -07002559 CHECK (outBuff.pos != totalTestSize, "decompressed data : wrong size (%u != %u)",
Yann Colletededcfc2018-12-21 16:19:44 -08002560 (unsigned)outBuff.pos, (unsigned)totalTestSize);
Yann Collet53e17fb2016-08-17 01:39:22 +02002561 CHECK (inBuff.pos != cSize, "compressed data should be fully read")
Yann Colletd7883a22016-08-12 16:48:02 +02002562 { U64 const crcDest = XXH64(dstBuffer, totalTestSize, 0);
2563 if (crcDest!=crcOrig) findDiff(copyBuffer, dstBuffer, totalTestSize);
2564 CHECK (crcDest!=crcOrig, "decompressed data corrupted");
2565 } }
2566
2567 /*===== noisy/erroneous src decompression test =====*/
2568
2569 /* add some noise */
2570 { U32 const nbNoiseChunks = (FUZ_rand(&lseed) & 7) + 2;
2571 U32 nn; for (nn=0; nn<nbNoiseChunks; nn++) {
2572 size_t const randomNoiseSize = FUZ_randomLength(&lseed, maxSampleLog);
2573 size_t const noiseSize = MIN((cSize/3) , randomNoiseSize);
2574 size_t const noiseStart = FUZ_rand(&lseed) % (srcBufferSize - noiseSize);
2575 size_t const cStart = FUZ_rand(&lseed) % (cSize - noiseSize);
2576 memcpy(cBuffer+cStart, srcBuffer+noiseStart, noiseSize);
2577 } }
2578
2579 /* try decompression on noisy data */
Yann Colletdce78922017-06-21 15:53:42 -07002580 CHECK_Z( ZSTD_initDStream(zd_noise) ); /* note : no dictionary */
Yann Collet53e17fb2016-08-17 01:39:22 +02002581 { ZSTD_inBuffer inBuff = { cBuffer, cSize, 0 };
2582 ZSTD_outBuffer outBuff= { dstBuffer, dstBufferSize, 0 };
2583 while (outBuff.pos < dstBufferSize) {
Yann Colletd7883a22016-08-12 16:48:02 +02002584 size_t const randomCSrcSize = FUZ_randomLength(&lseed, maxSampleLog);
2585 size_t const randomDstSize = FUZ_randomLength(&lseed, maxSampleLog);
Yann Collet53e17fb2016-08-17 01:39:22 +02002586 size_t const adjustedDstSize = MIN(dstBufferSize - outBuff.pos, randomDstSize);
Yann Collet64bf8ff2017-01-27 17:25:07 -08002587 size_t const adjustedCSrcSize = MIN(cSize - inBuff.pos, randomCSrcSize);
Yann Collet53e17fb2016-08-17 01:39:22 +02002588 outBuff.size = outBuff.pos + adjustedDstSize;
Yann Collet64bf8ff2017-01-27 17:25:07 -08002589 inBuff.size = inBuff.pos + adjustedCSrcSize;
Yann Collet53e17fb2016-08-17 01:39:22 +02002590 { size_t const decompressError = ZSTD_decompressStream(zd, &outBuff, &inBuff);
Yann Colletd7883a22016-08-12 16:48:02 +02002591 if (ZSTD_isError(decompressError)) break; /* error correctly detected */
Yann Collet64bf8ff2017-01-27 17:25:07 -08002592 /* No forward progress possible */
2593 if (outBuff.pos < outBuff.size && inBuff.pos == cSize) break;
Yann Colletd7883a22016-08-12 16:48:02 +02002594 } } } }
2595 DISPLAY("\r%u fuzzer tests completed \n", testNb);
2596
2597_cleanup:
2598 ZSTD_freeCStream(zc);
2599 ZSTD_freeDStream(zd);
Yann Collet58d5dfe2016-09-25 01:34:03 +02002600 ZSTD_freeDStream(zd_noise);
Yann Colletd7883a22016-08-12 16:48:02 +02002601 free(cNoiseBuffer[0]);
2602 free(cNoiseBuffer[1]);
2603 free(cNoiseBuffer[2]);
2604 free(cNoiseBuffer[3]);
2605 free(cNoiseBuffer[4]);
2606 free(copyBuffer);
2607 free(cBuffer);
2608 free(dstBuffer);
2609 return result;
2610
2611_output_error:
2612 result = 1;
2613 goto _cleanup;
2614}
2615
Stella Lau73c73bf2017-08-21 12:41:19 -07002616/** If useOpaqueAPI, sets param in cctxParams.
2617 * Otherwise, sets the param in zc. */
2618static size_t setCCtxParameter(ZSTD_CCtx* zc, ZSTD_CCtx_params* cctxParams,
2619 ZSTD_cParameter param, unsigned value,
Yann Colletc9e8ee92018-06-18 19:20:37 -07002620 int useOpaqueAPI)
Stella Lau73c73bf2017-08-21 12:41:19 -07002621{
2622 if (useOpaqueAPI) {
Nick Terrell7ad7ba32019-02-19 17:41:56 -08002623 return ZSTD_CCtxParams_setParameter(cctxParams, param, value);
Stella Lau73c73bf2017-08-21 12:41:19 -07002624 } else {
2625 return ZSTD_CCtx_setParameter(zc, param, value);
2626 }
2627}
Yann Collet736788f2017-01-19 12:12:50 -08002628
Yann Colletd7a3bff2017-06-19 11:53:01 -07002629/* Tests for ZSTD_compress_generic() API */
Yann Colletededcfc2018-12-21 16:19:44 -08002630static int fuzzerTests_newAPI(U32 seed, int nbTests, int startTest,
Yann Colletc9e8ee92018-06-18 19:20:37 -07002631 double compressibility, int bigTests)
Yann Collet01743a32017-06-16 17:56:41 -07002632{
Yann Colletf99c2c12017-06-21 23:35:58 -07002633 U32 const maxSrcLog = bigTests ? 24 : 22;
Yann Collet01743a32017-06-16 17:56:41 -07002634 static const U32 maxSampleLog = 19;
2635 size_t const srcBufferSize = (size_t)1<<maxSrcLog;
2636 BYTE* cNoiseBuffer[5];
2637 size_t const copyBufferSize= srcBufferSize + (1<<maxSampleLog);
2638 BYTE* const copyBuffer = (BYTE*)malloc (copyBufferSize);
2639 size_t const cBufferSize = ZSTD_compressBound(srcBufferSize);
2640 BYTE* const cBuffer = (BYTE*)malloc (cBufferSize);
2641 size_t const dstBufferSize = srcBufferSize;
2642 BYTE* const dstBuffer = (BYTE*)malloc (dstBufferSize);
2643 U32 result = 0;
Yann Colletededcfc2018-12-21 16:19:44 -08002644 int testNb = 0;
Yann Collet01743a32017-06-16 17:56:41 -07002645 U32 coreSeed = seed;
2646 ZSTD_CCtx* zc = ZSTD_createCCtx(); /* will be reset sometimes */
2647 ZSTD_DStream* zd = ZSTD_createDStream(); /* will be reset sometimes */
2648 ZSTD_DStream* const zd_noise = ZSTD_createDStream();
Nick Terrell9a2f6f42017-11-29 19:11:12 -08002649 UTIL_time_t const startClock = UTIL_getTime();
Yann Colletd7a3bff2017-06-19 11:53:01 -07002650 const BYTE* dict = NULL; /* can keep same dict on 2 consecutive tests */
Yann Collet01743a32017-06-16 17:56:41 -07002651 size_t dictSize = 0;
2652 U32 oldTestLog = 0;
Yann Colletaa800c42017-09-27 18:00:15 -07002653 U32 windowLogMalus = 0; /* can survive between 2 loops */
2654 U32 const cLevelMax = bigTests ? (U32)ZSTD_maxCLevel()-1 : g_cLevelMax_smallTests;
2655 U32 const nbThreadsMax = bigTests ? 4 : 2;
Stella Lau023b24e2017-08-20 22:55:07 -07002656 ZSTD_CCtx_params* cctxParams = ZSTD_createCCtxParams();
Yann Collet01743a32017-06-16 17:56:41 -07002657
2658 /* allocations */
2659 cNoiseBuffer[0] = (BYTE*)malloc (srcBufferSize);
2660 cNoiseBuffer[1] = (BYTE*)malloc (srcBufferSize);
2661 cNoiseBuffer[2] = (BYTE*)malloc (srcBufferSize);
2662 cNoiseBuffer[3] = (BYTE*)malloc (srcBufferSize);
2663 cNoiseBuffer[4] = (BYTE*)malloc (srcBufferSize);
2664 CHECK (!cNoiseBuffer[0] || !cNoiseBuffer[1] || !cNoiseBuffer[2] || !cNoiseBuffer[3] || !cNoiseBuffer[4] ||
2665 !copyBuffer || !dstBuffer || !cBuffer || !zc || !zd || !zd_noise ,
2666 "Not enough memory, fuzzer tests cancelled");
2667
2668 /* Create initial samples */
2669 RDG_genBuffer(cNoiseBuffer[0], srcBufferSize, 0.00, 0., coreSeed); /* pure noise */
2670 RDG_genBuffer(cNoiseBuffer[1], srcBufferSize, 0.05, 0., coreSeed); /* barely compressible */
2671 RDG_genBuffer(cNoiseBuffer[2], srcBufferSize, compressibility, 0., coreSeed);
2672 RDG_genBuffer(cNoiseBuffer[3], srcBufferSize, 0.95, 0., coreSeed); /* highly compressible */
2673 RDG_genBuffer(cNoiseBuffer[4], srcBufferSize, 1.00, 0., coreSeed); /* sparse content */
2674 memset(copyBuffer, 0x65, copyBufferSize); /* make copyBuffer considered initialized */
Yann Colletdce78922017-06-21 15:53:42 -07002675 CHECK_Z( ZSTD_initDStream_usingDict(zd, NULL, 0) ); /* ensure at least one init */
Yann Collet01743a32017-06-16 17:56:41 -07002676
2677 /* catch up testNb */
2678 for (testNb=1; testNb < startTest; testNb++)
2679 FUZ_rand(&coreSeed);
2680
2681 /* test loop */
Nick Terrell9a2f6f42017-11-29 19:11:12 -08002682 for ( ; (testNb <= nbTests) || (UTIL_clockSpanMicro(startClock) < g_clockTime) ; testNb++ ) {
Yann Collet01743a32017-06-16 17:56:41 -07002683 U32 lseed;
Yann Colletc9e8ee92018-06-18 19:20:37 -07002684 int opaqueAPI;
Yann Collet01743a32017-06-16 17:56:41 -07002685 const BYTE* srcBuffer;
2686 size_t totalTestSize, totalGenSize, cSize;
2687 XXH64_state_t xxhState;
2688 U64 crcOrig;
2689 U32 resetAllowed = 1;
2690 size_t maxTestSize;
Nick Terrellca778222018-04-25 16:32:29 -07002691 ZSTD_parameters savedParams;
Nick Terrell9ab92292020-10-01 15:02:15 -07002692 int isRefPrefix = 0;
2693 U64 pledgedSrcSize = ZSTD_CONTENTSIZE_UNKNOWN;
Yann Collet01743a32017-06-16 17:56:41 -07002694
2695 /* init */
2696 if (nbTests >= testNb) { DISPLAYUPDATE(2, "\r%6u/%6u ", testNb, nbTests); }
2697 else { DISPLAYUPDATE(2, "\r%6u ", testNb); }
2698 FUZ_rand(&coreSeed);
2699 lseed = coreSeed ^ prime32;
Yann Collet9b5b47a2017-09-28 01:25:40 -07002700 DISPLAYLEVEL(5, " *** Test %u *** \n", testNb);
Yann Colletc9e8ee92018-06-18 19:20:37 -07002701 opaqueAPI = FUZ_rand(&lseed) & 1;
Yann Collet01743a32017-06-16 17:56:41 -07002702
2703 /* states full reset (deliberately not synchronized) */
2704 /* some issues can only happen when reusing states */
2705 if ((FUZ_rand(&lseed) & 0xFF) == 131) {
2706 DISPLAYLEVEL(5, "Creating new context \n");
2707 ZSTD_freeCCtx(zc);
2708 zc = ZSTD_createCCtx();
Yann Collet62469c92018-06-19 20:14:03 -07002709 CHECK(zc == NULL, "ZSTD_createCCtx allocation error");
2710 resetAllowed = 0;
Yann Collet01743a32017-06-16 17:56:41 -07002711 }
2712 if ((FUZ_rand(&lseed) & 0xFF) == 132) {
2713 ZSTD_freeDStream(zd);
2714 zd = ZSTD_createDStream();
Yann Collet62469c92018-06-19 20:14:03 -07002715 CHECK(zd == NULL, "ZSTD_createDStream allocation error");
Yann Collet01743a32017-06-16 17:56:41 -07002716 ZSTD_initDStream_usingDict(zd, NULL, 0); /* ensure at least one init */
2717 }
2718
2719 /* srcBuffer selection [0-4] */
2720 { U32 buffNb = FUZ_rand(&lseed) & 0x7F;
2721 if (buffNb & 7) buffNb=2; /* most common : compressible (P) */
2722 else {
2723 buffNb >>= 3;
2724 if (buffNb & 7) {
2725 const U32 tnb[2] = { 1, 3 }; /* barely/highly compressible */
2726 buffNb = tnb[buffNb >> 3];
2727 } else {
2728 const U32 tnb[2] = { 0, 4 }; /* not compressible / sparse */
2729 buffNb = tnb[buffNb >> 3];
2730 } }
2731 srcBuffer = cNoiseBuffer[buffNb];
2732 }
2733
2734 /* compression init */
Yann Colletb7372932017-06-27 15:49:12 -07002735 CHECK_Z( ZSTD_CCtx_loadDictionary(zc, NULL, 0) ); /* cancel previous dict /*/
Yann Collet01743a32017-06-16 17:56:41 -07002736 if ((FUZ_rand(&lseed)&1) /* at beginning, to keep same nb of rand */
Yann Collet2108dec2018-06-01 15:18:32 -07002737 && oldTestLog /* at least one test happened */
2738 && resetAllowed) {
2739 /* just set a compression level */
Yann Collet01743a32017-06-16 17:56:41 -07002740 maxTestSize = FUZ_randomLength(&lseed, oldTestLog+2);
2741 if (maxTestSize >= srcBufferSize) maxTestSize = srcBufferSize-1;
Yann Collet01743a32017-06-16 17:56:41 -07002742 { int const compressionLevel = (FUZ_rand(&lseed) % 5) + 1;
Yann Collet2108dec2018-06-01 15:18:32 -07002743 DISPLAYLEVEL(5, "t%u : compression level : %i \n", testNb, compressionLevel);
Yann Collet3583d192018-12-05 17:26:02 -08002744 CHECK_Z (setCCtxParameter(zc, cctxParams, ZSTD_c_compressionLevel, compressionLevel, opaqueAPI) );
Yann Collet01743a32017-06-16 17:56:41 -07002745 }
2746 } else {
2747 U32 const testLog = FUZ_rand(&lseed) % maxSrcLog;
2748 U32 const dictLog = FUZ_rand(&lseed) % maxSrcLog;
Yann Colletbfc2f002017-06-21 17:57:14 -07002749 U32 const cLevelCandidate = (FUZ_rand(&lseed) %
Yann Collet01743a32017-06-16 17:56:41 -07002750 (ZSTD_maxCLevel() -
Yann Collet9fe50ed2017-09-28 01:42:06 -07002751 (MAX(testLog, dictLog) / 2))) +
Yann Collet01743a32017-06-16 17:56:41 -07002752 1;
Yann Colletededcfc2018-12-21 16:19:44 -08002753 int const cLevel = MIN(cLevelCandidate, cLevelMax);
2754 DISPLAYLEVEL(5, "t%i: base cLevel : %u \n", testNb, cLevel);
Yann Collet01743a32017-06-16 17:56:41 -07002755 maxTestSize = FUZ_rLogLength(&lseed, testLog);
Yann Colletededcfc2018-12-21 16:19:44 -08002756 DISPLAYLEVEL(5, "t%i: maxTestSize : %u \n", testNb, (unsigned)maxTestSize);
Yann Collet01743a32017-06-16 17:56:41 -07002757 oldTestLog = testLog;
2758 /* random dictionary selection */
2759 dictSize = ((FUZ_rand(&lseed)&63)==1) ? FUZ_rLogLength(&lseed, dictLog) : 0;
2760 { size_t const dictStart = FUZ_rand(&lseed) % (srcBufferSize - dictSize);
2761 dict = srcBuffer + dictStart;
Yann Colletd7a3bff2017-06-19 11:53:01 -07002762 if (!dictSize) dict=NULL;
Yann Collet01743a32017-06-16 17:56:41 -07002763 }
Nick Terrell9ab92292020-10-01 15:02:15 -07002764 pledgedSrcSize = (FUZ_rand(&lseed) & 3) ? ZSTD_CONTENTSIZE_UNKNOWN : maxTestSize;
2765 { ZSTD_compressionParameters cParams = ZSTD_getCParams(cLevel, pledgedSrcSize, dictSize);
Nick Terrell7ee910e2018-09-27 13:55:24 -07002766 const U32 windowLogMax = bigTests ? 24 : 20;
2767 const U32 searchLogMax = bigTests ? 15 : 13;
Yann Collet2108dec2018-06-01 15:18:32 -07002768 if (dictSize)
2769 DISPLAYLEVEL(5, "t%u: with dictionary of size : %zu \n", testNb, dictSize);
Yann Collet01743a32017-06-16 17:56:41 -07002770
2771 /* mess with compression parameters */
2772 cParams.windowLog += (FUZ_rand(&lseed) & 3) - 1;
Nick Terrellc233bdb2017-09-22 14:04:39 -07002773 cParams.windowLog = MIN(windowLogMax, cParams.windowLog);
Yann Collet01743a32017-06-16 17:56:41 -07002774 cParams.hashLog += (FUZ_rand(&lseed) & 3) - 1;
2775 cParams.chainLog += (FUZ_rand(&lseed) & 3) - 1;
2776 cParams.searchLog += (FUZ_rand(&lseed) & 3) - 1;
Nick Terrell7ee910e2018-09-27 13:55:24 -07002777 cParams.searchLog = MIN(searchLogMax, cParams.searchLog);
Yann Collete874dac2018-11-20 14:56:07 -08002778 cParams.minMatch += (FUZ_rand(&lseed) & 3) - 1;
Yann Colletaa800c42017-09-27 18:00:15 -07002779 cParams.targetLength = (U32)((cParams.targetLength + 1 ) * (0.5 + ((double)(FUZ_rand(&lseed) & 127) / 128)));
Yann Collet2108dec2018-06-01 15:18:32 -07002780 cParams = ZSTD_adjustCParams(cParams, pledgedSrcSize, dictSize);
Yann Collet01743a32017-06-16 17:56:41 -07002781
Yann Colletaa800c42017-09-27 18:00:15 -07002782 if (FUZ_rand(&lseed) & 1) {
Yann Colletd3c59ed2017-11-29 16:42:20 -08002783 DISPLAYLEVEL(5, "t%u: windowLog : %u \n", testNb, cParams.windowLog);
Yann Collet3583d192018-12-05 17:26:02 -08002784 CHECK_Z( setCCtxParameter(zc, cctxParams, ZSTD_c_windowLog, cParams.windowLog, opaqueAPI) );
Yann Colletaa800c42017-09-27 18:00:15 -07002785 assert(cParams.windowLog >= ZSTD_WINDOWLOG_MIN); /* guaranteed by ZSTD_adjustCParams() */
2786 windowLogMalus = (cParams.windowLog - ZSTD_WINDOWLOG_MIN) / 5;
2787 }
Yann Collet9b5b47a2017-09-28 01:25:40 -07002788 if (FUZ_rand(&lseed) & 1) {
Yann Collet9b5b47a2017-09-28 01:25:40 -07002789 DISPLAYLEVEL(5, "t%u: hashLog : %u \n", testNb, cParams.hashLog);
Yann Collet3583d192018-12-05 17:26:02 -08002790 CHECK_Z( setCCtxParameter(zc, cctxParams, ZSTD_c_hashLog, cParams.hashLog, opaqueAPI) );
Yann Collet9b5b47a2017-09-28 01:25:40 -07002791 }
2792 if (FUZ_rand(&lseed) & 1) {
Yann Collet9b5b47a2017-09-28 01:25:40 -07002793 DISPLAYLEVEL(5, "t%u: chainLog : %u \n", testNb, cParams.chainLog);
Yann Collet3583d192018-12-05 17:26:02 -08002794 CHECK_Z( setCCtxParameter(zc, cctxParams, ZSTD_c_chainLog, cParams.chainLog, opaqueAPI) );
Yann Collet9b5b47a2017-09-28 01:25:40 -07002795 }
Yann Collet3583d192018-12-05 17:26:02 -08002796 if (FUZ_rand(&lseed) & 1) CHECK_Z( setCCtxParameter(zc, cctxParams, ZSTD_c_searchLog, cParams.searchLog, opaqueAPI) );
2797 if (FUZ_rand(&lseed) & 1) CHECK_Z( setCCtxParameter(zc, cctxParams, ZSTD_c_minMatch, cParams.minMatch, opaqueAPI) );
2798 if (FUZ_rand(&lseed) & 1) CHECK_Z( setCCtxParameter(zc, cctxParams, ZSTD_c_targetLength, cParams.targetLength, opaqueAPI) );
Yann Collet01743a32017-06-16 17:56:41 -07002799
Stella Lau9e406022017-09-06 08:39:46 -07002800 /* mess with long distance matching parameters */
Yann Colletd3c59ed2017-11-29 16:42:20 -08002801 if (bigTests) {
Elliott Hughes44aba642023-09-12 20:18:59 +00002802 if (FUZ_rand(&lseed) & 1) CHECK_Z( setCCtxParameter(zc, cctxParams, ZSTD_c_enableLongDistanceMatching, FUZ_randomClampedLength(&lseed, ZSTD_ps_auto, ZSTD_ps_disable), opaqueAPI) );
Yann Collet3583d192018-12-05 17:26:02 -08002803 if (FUZ_rand(&lseed) & 3) CHECK_Z( setCCtxParameter(zc, cctxParams, ZSTD_c_ldmHashLog, FUZ_randomClampedLength(&lseed, ZSTD_HASHLOG_MIN, 23), opaqueAPI) );
2804 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) );
2805 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) );
2806 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 -07002807 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 -08002808 }
Stella Lau6a546ef2017-07-28 15:51:33 -07002809
Yann Collet01743a32017-06-16 17:56:41 -07002810 /* mess with frame parameters */
Yann Colletebd955e2018-01-23 13:12:40 -08002811 if (FUZ_rand(&lseed) & 1) {
Yann Colletededcfc2018-12-21 16:19:44 -08002812 int const checksumFlag = FUZ_rand(&lseed) & 1;
Yann Colletebd955e2018-01-23 13:12:40 -08002813 DISPLAYLEVEL(5, "t%u: frame checksum : %u \n", testNb, checksumFlag);
Yann Collet3583d192018-12-05 17:26:02 -08002814 CHECK_Z( setCCtxParameter(zc, cctxParams, ZSTD_c_checksumFlag, checksumFlag, opaqueAPI) );
Yann Colletebd955e2018-01-23 13:12:40 -08002815 }
Yann Collet3583d192018-12-05 17:26:02 -08002816 if (FUZ_rand(&lseed) & 1) CHECK_Z( setCCtxParameter(zc, cctxParams, ZSTD_c_dictIDFlag, FUZ_rand(&lseed) & 1, opaqueAPI) );
2817 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 -08002818 if (FUZ_rand(&lseed) & 1) {
Yann Colletededcfc2018-12-21 16:19:44 -08002819 DISPLAYLEVEL(5, "t%u: pledgedSrcSize : %u \n", testNb, (unsigned)pledgedSrcSize);
Yann Colletd3c59ed2017-11-29 16:42:20 -08002820 CHECK_Z( ZSTD_CCtx_setPledgedSrcSize(zc, pledgedSrcSize) );
Nick Terrell9ab92292020-10-01 15:02:15 -07002821 } else {
2822 pledgedSrcSize = ZSTD_CONTENTSIZE_UNKNOWN;
Yann Colletd3c59ed2017-11-29 16:42:20 -08002823 }
Yann Collet01743a32017-06-16 17:56:41 -07002824
Josh Sorefa880ca22019-04-12 14:18:11 -04002825 /* multi-threading parameters. Only adjust occasionally for small tests. */
Nick Terrelld8c73cd2018-09-27 15:49:31 -07002826 if (bigTests || (FUZ_rand(&lseed) & 0xF) == 0xF) {
2827 U32 const nbThreadsCandidate = (FUZ_rand(&lseed) & 4) + 1;
Yann Colletaa800c42017-09-27 18:00:15 -07002828 U32 const nbThreadsAdjusted = (windowLogMalus < nbThreadsCandidate) ? nbThreadsCandidate - windowLogMalus : 1;
Yann Colletededcfc2018-12-21 16:19:44 -08002829 int const nbThreads = MIN(nbThreadsAdjusted, nbThreadsMax);
2830 DISPLAYLEVEL(5, "t%i: nbThreads : %u \n", testNb, nbThreads);
Yann Collet3583d192018-12-05 17:26:02 -08002831 CHECK_Z( setCCtxParameter(zc, cctxParams, ZSTD_c_nbWorkers, nbThreads, opaqueAPI) );
Yann Collet01743a32017-06-16 17:56:41 -07002832 if (nbThreads > 1) {
Yann Colleted1d0392017-06-19 11:07:33 -07002833 U32 const jobLog = FUZ_rand(&lseed) % (testLog+1);
Yann Collet9b784de2018-12-11 16:55:33 -08002834 CHECK_Z( setCCtxParameter(zc, cctxParams, ZSTD_c_overlapLog, FUZ_rand(&lseed) % 10, opaqueAPI) );
Yann Collet3583d192018-12-05 17:26:02 -08002835 CHECK_Z( setCCtxParameter(zc, cctxParams, ZSTD_c_jobSize, (U32)FUZ_rLogLength(&lseed, jobLog), opaqueAPI) );
Stella Lau023b24e2017-08-20 22:55:07 -07002836 }
2837 }
Nick Terrell71fe78c2018-11-14 13:53:14 -08002838 /* Enable rsyncable mode 1 in 4 times. */
Nick Terrellede4f972020-10-05 17:37:19 -07002839 {
2840 int const rsyncable = (FUZ_rand(&lseed) % 4 == 0);
2841 DISPLAYLEVEL(5, "t%u: rsyncable : %d \n", testNb, rsyncable);
2842 setCCtxParameter(zc, cctxParams, ZSTD_c_rsyncable, rsyncable, opaqueAPI);
2843 }
Stella Lau023b24e2017-08-20 22:55:07 -07002844
Yann Collet3583d192018-12-05 17:26:02 -08002845 if (FUZ_rand(&lseed) & 1) CHECK_Z( setCCtxParameter(zc, cctxParams, ZSTD_c_forceMaxWindow, FUZ_rand(&lseed) & 1, opaqueAPI) );
Nick Terrell172b4b62021-05-05 12:18:47 -07002846 if (FUZ_rand(&lseed) & 1) CHECK_Z( setCCtxParameter(zc, cctxParams, ZSTD_c_deterministicRefPrefix, FUZ_rand(&lseed) & 1, opaqueAPI) );
Stella Lau023b24e2017-08-20 22:55:07 -07002847
2848 /* Apply parameters */
Yann Colletc9e8ee92018-06-18 19:20:37 -07002849 if (opaqueAPI) {
Yann Collet2108dec2018-06-01 15:18:32 -07002850 DISPLAYLEVEL(5, "t%u: applying CCtxParams \n", testNb);
Stella Lau82d636b2017-08-29 18:03:06 -07002851 CHECK_Z (ZSTD_CCtx_setParametersUsingCCtxParams(zc, cctxParams) );
Stella Lau73c73bf2017-08-21 12:41:19 -07002852 }
Stella Lau023b24e2017-08-20 22:55:07 -07002853
2854 if (FUZ_rand(&lseed) & 1) {
Stella Laueb7bbab2017-08-25 10:48:07 -07002855 if (FUZ_rand(&lseed) & 1) {
2856 CHECK_Z( ZSTD_CCtx_loadDictionary(zc, dict, dictSize) );
2857 } else {
2858 CHECK_Z( ZSTD_CCtx_loadDictionary_byReference(zc, dict, dictSize) );
2859 }
Stella Lau73c73bf2017-08-21 12:41:19 -07002860 } else {
Nick Terrell9ab92292020-10-01 15:02:15 -07002861 isRefPrefix = 1;
Stella Lau023b24e2017-08-20 22:55:07 -07002862 CHECK_Z( ZSTD_CCtx_refPrefix(zc, dict, dictSize) );
2863 }
2864 } }
Yann Collet01743a32017-06-16 17:56:41 -07002865
Nick Terrellca778222018-04-25 16:32:29 -07002866 CHECK_Z(getCCtxParams(zc, &savedParams));
2867
Yann Collet01743a32017-06-16 17:56:41 -07002868 /* multi-segments compression test */
Nick Terrell9ab92292020-10-01 15:02:15 -07002869 { int iter;
2870 int const startSeed = lseed;
2871 XXH64_hash_t compressedCrcs[2];
2872 for (iter = 0; iter < 2; ++iter, lseed = startSeed) {
2873 ZSTD_outBuffer outBuff = { cBuffer, cBufferSize, 0 } ;
2874 int const singlePass = (FUZ_rand(&lseed) & 3) == 0;
2875 int nbWorkers;
Yann Collet01743a32017-06-16 17:56:41 -07002876
Nick Terrell9ab92292020-10-01 15:02:15 -07002877 XXH64_reset(&xxhState, 0);
Yann Collet01743a32017-06-16 17:56:41 -07002878
Nick Terrell9ab92292020-10-01 15:02:15 -07002879 CHECK_Z( ZSTD_CCtx_setPledgedSrcSize(zc, pledgedSrcSize) );
2880 if (isRefPrefix) {
2881 DISPLAYLEVEL(6, "t%u: Reloading prefix\n", testNb);
2882 /* Need to reload the prefix because it gets dropped after one compression */
2883 CHECK_Z( ZSTD_CCtx_refPrefix(zc, dict, dictSize) );
2884 }
2885
Dimitris Apostolouebbd6752021-11-13 10:04:04 +02002886 /* Adjust number of workers occasionally - result must be deterministic independent of nbWorkers */
Nick Terrell9ab92292020-10-01 15:02:15 -07002887 CHECK_Z(ZSTD_CCtx_getParameter(zc, ZSTD_c_nbWorkers, &nbWorkers));
2888 if (nbWorkers > 0 && (FUZ_rand(&lseed) & 7) == 0) {
2889 DISPLAYLEVEL(6, "t%u: Modify nbWorkers: %d -> %d \n", testNb, nbWorkers, nbWorkers + iter);
2890 CHECK_Z(ZSTD_CCtx_setParameter(zc, ZSTD_c_nbWorkers, nbWorkers + iter));
2891 }
2892
2893 if (singlePass) {
2894 ZSTD_inBuffer inBuff = { srcBuffer, maxTestSize, 0 };
2895 CHECK_Z(ZSTD_compressStream2(zc, &outBuff, &inBuff, ZSTD_e_end));
2896 DISPLAYLEVEL(6, "t%u: Single pass compression: consumed %u bytes ; produced %u bytes \n",
2897 testNb, (unsigned)inBuff.pos, (unsigned)outBuff.pos);
2898 CHECK(inBuff.pos != inBuff.size, "Input not consumed!");
2899 crcOrig = XXH64(srcBuffer, maxTestSize, 0);
2900 totalTestSize = maxTestSize;
2901 } else {
2902 outBuff.size = 0;
2903 for (totalTestSize=0 ; (totalTestSize < maxTestSize) ; ) {
2904 /* compress random chunks into randomly sized dst buffers */
2905 size_t const randomSrcSize = FUZ_randomLength(&lseed, maxSampleLog);
2906 size_t const srcSize = MIN(maxTestSize-totalTestSize, randomSrcSize);
2907 size_t const srcStart = FUZ_rand(&lseed) % (srcBufferSize - srcSize);
2908 ZSTD_EndDirective const flush = (FUZ_rand(&lseed) & 15) ? ZSTD_e_continue : ZSTD_e_flush;
2909 ZSTD_inBuffer inBuff = { srcBuffer+srcStart, srcSize, 0 };
2910 int forwardProgress;
2911 do {
2912 size_t const ipos = inBuff.pos;
2913 size_t const opos = outBuff.pos;
2914 size_t ret;
2915 if (outBuff.pos == outBuff.size) {
2916 size_t const randomDstSize = FUZ_randomLength(&lseed, maxSampleLog+1);
2917 size_t const dstBuffSize = MIN(cBufferSize - outBuff.pos, randomDstSize);
2918 outBuff.size = outBuff.pos + dstBuffSize;
2919 }
2920 CHECK_Z( ret = ZSTD_compressStream2(zc, &outBuff, &inBuff, flush) );
2921 DISPLAYLEVEL(6, "t%u: compress consumed %u bytes (total : %u) ; flush: %u (total : %u) \n",
2922 testNb, (unsigned)inBuff.pos, (unsigned)(totalTestSize + inBuff.pos), (unsigned)flush, (unsigned)outBuff.pos);
2923
2924 /* We've completed the flush */
2925 if (flush == ZSTD_e_flush && ret == 0)
2926 break;
2927
2928 /* Ensure maximal forward progress for determinism */
2929 forwardProgress = (inBuff.pos != ipos) || (outBuff.pos != opos);
2930 } while (forwardProgress);
Nick Terrell4c58cb82020-12-03 20:25:14 -08002931 assert(inBuff.pos == inBuff.size);
Nick Terrell9ab92292020-10-01 15:02:15 -07002932
2933 XXH64_update(&xxhState, srcBuffer+srcStart, inBuff.pos);
2934 memcpy(copyBuffer+totalTestSize, srcBuffer+srcStart, inBuff.pos);
2935 totalTestSize += inBuff.pos;
2936 }
2937
2938 /* final frame epilogue */
2939 { size_t remainingToFlush = 1;
2940 while (remainingToFlush) {
2941 ZSTD_inBuffer inBuff = { NULL, 0, 0 };
2942 size_t const randomDstSize = FUZ_randomLength(&lseed, maxSampleLog+1);
2943 size_t const adjustedDstSize = MIN(cBufferSize - outBuff.pos, randomDstSize);
2944 outBuff.size = outBuff.pos + adjustedDstSize;
2945 DISPLAYLEVEL(6, "t%u: End-flush into dst buffer of size %u \n", testNb, (unsigned)adjustedDstSize);
2946 /* ZSTD_e_end guarantees maximal forward progress */
2947 remainingToFlush = ZSTD_compressStream2(zc, &outBuff, &inBuff, ZSTD_e_end);
2948 DISPLAYLEVEL(6, "t%u: Total flushed so far : %u bytes \n", testNb, (unsigned)outBuff.pos);
2949 CHECK( ZSTD_isError(remainingToFlush),
2950 "ZSTD_compressStream2 w/ ZSTD_e_end error : %s",
2951 ZSTD_getErrorName(remainingToFlush) );
2952 } }
2953 crcOrig = XXH64_digest(&xxhState);
2954 }
2955 cSize = outBuff.pos;
2956 compressedCrcs[iter] = XXH64(cBuffer, cSize, 0);
2957 DISPLAYLEVEL(5, "Frame completed : %zu bytes \n", cSize);
Yann Colleted1d0392017-06-19 11:07:33 -07002958 }
Nick Terrell9ab92292020-10-01 15:02:15 -07002959 CHECK(!(compressedCrcs[0] == compressedCrcs[1]), "Compression is not deterministic!");
Yann Collet01743a32017-06-16 17:56:41 -07002960 }
2961
Nick Terrellca778222018-04-25 16:32:29 -07002962 CHECK(badParameters(zc, savedParams), "CCtx params are wrong");
2963
Yann Collet01743a32017-06-16 17:56:41 -07002964 /* multi - fragments decompression test */
Elliott Hughes44aba642023-09-12 20:18:59 +00002965 if (FUZ_rand(&lseed) & 1) {
2966 CHECK_Z(ZSTD_DCtx_reset(zd, ZSTD_reset_session_and_parameters));
2967 }
Yann Collet01743a32017-06-16 17:56:41 -07002968 if (!dictSize /* don't reset if dictionary : could be different */ && (FUZ_rand(&lseed) & 1)) {
Nick Terrell91f58912021-12-01 11:49:58 -08002969 DISPLAYLEVEL(5, "resetting DCtx (dict:%p) \n", (void const*)dict);
Yann Colletdce78922017-06-21 15:53:42 -07002970 CHECK_Z( ZSTD_resetDStream(zd) );
Yann Collet01743a32017-06-16 17:56:41 -07002971 } else {
Yann Collet2108dec2018-06-01 15:18:32 -07002972 if (dictSize)
2973 DISPLAYLEVEL(5, "using dictionary of size %zu \n", dictSize);
Yann Colletdce78922017-06-21 15:53:42 -07002974 CHECK_Z( ZSTD_initDStream_usingDict(zd, dict, dictSize) );
Yann Collet01743a32017-06-16 17:56:41 -07002975 }
Elliott Hughes44aba642023-09-12 20:18:59 +00002976 if (FUZ_rand(&lseed) & 1) {
2977 CHECK_Z(ZSTD_DCtx_setParameter(zd, ZSTD_d_disableHuffmanAssembly, FUZ_rand(&lseed) & 1));
2978 }
Yann Collet01743a32017-06-16 17:56:41 -07002979 { size_t decompressionResult = 1;
2980 ZSTD_inBuffer inBuff = { cBuffer, cSize, 0 };
2981 ZSTD_outBuffer outBuff= { dstBuffer, dstBufferSize, 0 };
2982 for (totalGenSize = 0 ; decompressionResult ; ) {
2983 size_t const readCSrcSize = FUZ_randomLength(&lseed, maxSampleLog);
2984 size_t const randomDstSize = FUZ_randomLength(&lseed, maxSampleLog);
2985 size_t const dstBuffSize = MIN(dstBufferSize - totalGenSize, randomDstSize);
2986 inBuff.size = inBuff.pos + readCSrcSize;
Yann Colletbfabd1d2017-09-27 01:01:11 -07002987 outBuff.size = outBuff.pos + dstBuffSize;
Yann Collet4f7c8962018-01-23 18:00:51 -08002988 DISPLAYLEVEL(6, "decompression presented %u new bytes (pos:%u/%u)\n",
Yann Colletededcfc2018-12-21 16:19:44 -08002989 (unsigned)readCSrcSize, (unsigned)inBuff.pos, (unsigned)cSize);
Yann Collet01743a32017-06-16 17:56:41 -07002990 decompressionResult = ZSTD_decompressStream(zd, &outBuff, &inBuff);
Yann Collet4f7c8962018-01-23 18:00:51 -08002991 DISPLAYLEVEL(6, "so far: consumed = %u, produced = %u \n",
Yann Colletededcfc2018-12-21 16:19:44 -08002992 (unsigned)inBuff.pos, (unsigned)outBuff.pos);
Yann Colletebd955e2018-01-23 13:12:40 -08002993 if (ZSTD_isError(decompressionResult)) {
2994 DISPLAY("ZSTD_decompressStream error : %s \n", ZSTD_getErrorName(decompressionResult));
2995 findDiff(copyBuffer, dstBuffer, totalTestSize);
2996 }
Yann Collet01743a32017-06-16 17:56:41 -07002997 CHECK (ZSTD_isError(decompressionResult), "decompression error : %s", ZSTD_getErrorName(decompressionResult));
Yann Colletededcfc2018-12-21 16:19:44 -08002998 CHECK (inBuff.pos > cSize, "ZSTD_decompressStream consumes too much input : %u > %u ", (unsigned)inBuff.pos, (unsigned)cSize);
Yann Collet01743a32017-06-16 17:56:41 -07002999 }
Yann Colletededcfc2018-12-21 16:19:44 -08003000 CHECK (inBuff.pos != cSize, "compressed data should be fully read (%u != %u)", (unsigned)inBuff.pos, (unsigned)cSize);
3001 CHECK (outBuff.pos != totalTestSize, "decompressed data : wrong size (%u != %u)", (unsigned)outBuff.pos, (unsigned)totalTestSize);
Yann Collet01743a32017-06-16 17:56:41 -07003002 { U64 const crcDest = XXH64(dstBuffer, totalTestSize, 0);
3003 if (crcDest!=crcOrig) findDiff(copyBuffer, dstBuffer, totalTestSize);
3004 CHECK (crcDest!=crcOrig, "decompressed data corrupted");
3005 } }
3006
3007 /*===== noisy/erroneous src decompression test =====*/
3008
3009 /* add some noise */
3010 { U32 const nbNoiseChunks = (FUZ_rand(&lseed) & 7) + 2;
3011 U32 nn; for (nn=0; nn<nbNoiseChunks; nn++) {
3012 size_t const randomNoiseSize = FUZ_randomLength(&lseed, maxSampleLog);
3013 size_t const noiseSize = MIN((cSize/3) , randomNoiseSize);
3014 size_t const noiseStart = FUZ_rand(&lseed) % (srcBufferSize - noiseSize);
3015 size_t const cStart = FUZ_rand(&lseed) % (cSize - noiseSize);
3016 memcpy(cBuffer+cStart, srcBuffer+noiseStart, noiseSize);
3017 } }
3018
3019 /* try decompression on noisy data */
Elliott Hughes44aba642023-09-12 20:18:59 +00003020 if (FUZ_rand(&lseed) & 1) {
3021 CHECK_Z(ZSTD_DCtx_reset(zd_noise, ZSTD_reset_session_and_parameters));
3022 } else {
3023 CHECK_Z(ZSTD_DCtx_reset(zd_noise, ZSTD_reset_session_only));
3024 }
3025 if (FUZ_rand(&lseed) & 1) {
3026 CHECK_Z(ZSTD_DCtx_setParameter(zd_noise, ZSTD_d_disableHuffmanAssembly, FUZ_rand(&lseed) & 1));
3027 }
Yann Collet01743a32017-06-16 17:56:41 -07003028 { ZSTD_inBuffer inBuff = { cBuffer, cSize, 0 };
3029 ZSTD_outBuffer outBuff= { dstBuffer, dstBufferSize, 0 };
3030 while (outBuff.pos < dstBufferSize) {
3031 size_t const randomCSrcSize = FUZ_randomLength(&lseed, maxSampleLog);
3032 size_t const randomDstSize = FUZ_randomLength(&lseed, maxSampleLog);
3033 size_t const adjustedDstSize = MIN(dstBufferSize - outBuff.pos, randomDstSize);
3034 size_t const adjustedCSrcSize = MIN(cSize - inBuff.pos, randomCSrcSize);
3035 outBuff.size = outBuff.pos + adjustedDstSize;
3036 inBuff.size = inBuff.pos + adjustedCSrcSize;
3037 { size_t const decompressError = ZSTD_decompressStream(zd, &outBuff, &inBuff);
3038 if (ZSTD_isError(decompressError)) break; /* error correctly detected */
Yann Colleted1d0392017-06-19 11:07:33 -07003039 /* Good so far, but no more progress possible */
Yann Collet01743a32017-06-16 17:56:41 -07003040 if (outBuff.pos < outBuff.size && inBuff.pos == cSize) break;
3041 } } } }
Yann Collet8dee0ec2017-06-18 23:25:15 -07003042 DISPLAY("\r%u fuzzer tests completed \n", testNb-1);
Yann Collet01743a32017-06-16 17:56:41 -07003043
3044_cleanup:
3045 ZSTD_freeCCtx(zc);
3046 ZSTD_freeDStream(zd);
3047 ZSTD_freeDStream(zd_noise);
Stella Lau023b24e2017-08-20 22:55:07 -07003048 ZSTD_freeCCtxParams(cctxParams);
Yann Collet01743a32017-06-16 17:56:41 -07003049 free(cNoiseBuffer[0]);
3050 free(cNoiseBuffer[1]);
3051 free(cNoiseBuffer[2]);
3052 free(cNoiseBuffer[3]);
3053 free(cNoiseBuffer[4]);
3054 free(copyBuffer);
3055 free(cBuffer);
3056 free(dstBuffer);
3057 return result;
3058
3059_output_error:
3060 result = 1;
3061 goto _cleanup;
3062}
3063
Yann Colletd7883a22016-08-12 16:48:02 +02003064/*-*******************************************************
3065* Command line
3066*********************************************************/
Nick Terrellf2d6db42018-09-27 15:13:43 -07003067static int FUZ_usage(const char* programName)
Yann Colletd7883a22016-08-12 16:48:02 +02003068{
3069 DISPLAY( "Usage :\n");
3070 DISPLAY( " %s [args]\n", programName);
3071 DISPLAY( "\n");
3072 DISPLAY( "Arguments :\n");
Taylor Braun-Jones3cbc3d32020-03-23 17:46:56 -04003073 DISPLAY( " -i# : Number of tests (default:%u)\n", nbTestsDefault);
3074 DISPLAY( " -T# : Max duration to run for. Overrides number of tests. (e.g. -T1m or -T60s for one minute)\n");
Yann Colletd7883a22016-08-12 16:48:02 +02003075 DISPLAY( " -s# : Select seed (default:prompt user)\n");
3076 DISPLAY( " -t# : Select starting test number (default:0)\n");
3077 DISPLAY( " -P# : Select compressibility in %% (default:%i%%)\n", FUZ_COMPRESSIBILITY_DEFAULT);
3078 DISPLAY( " -v : verbose\n");
3079 DISPLAY( " -p : pause at the end\n");
3080 DISPLAY( " -h : display help and exit\n");
3081 return 0;
3082}
3083
Nick Terrellc51a9e72020-10-01 18:47:54 -07003084typedef enum { simple_api, advanced_api } e_api;
Yann Colletd7883a22016-08-12 16:48:02 +02003085
3086int main(int argc, const char** argv)
3087{
Yann Colletbd88f632017-11-27 12:15:23 -08003088 U32 seed = 0;
3089 int seedset = 0;
Yann Colletd7883a22016-08-12 16:48:02 +02003090 int nbTests = nbTestsDefault;
3091 int testNb = 0;
3092 int proba = FUZ_COMPRESSIBILITY_DEFAULT;
Yann Colletbd88f632017-11-27 12:15:23 -08003093 int result = 0;
Yann Collet19d670b2017-01-19 15:32:07 -08003094 int mainPause = 0;
Yann Colletafb0aca2017-06-29 18:19:09 -07003095 int bigTests = (sizeof(size_t) == 8);
Yann Collet01743a32017-06-16 17:56:41 -07003096 e_api selected_api = simple_api;
Yann Collet19d670b2017-01-19 15:32:07 -08003097 const char* const programName = argv[0];
Yann Colletbd88f632017-11-27 12:15:23 -08003098 int argNb;
Yann Colletd7883a22016-08-12 16:48:02 +02003099
3100 /* Check command line */
3101 for(argNb=1; argNb<argc; argNb++) {
3102 const char* argument = argv[argNb];
Yann Colletbd88f632017-11-27 12:15:23 -08003103 assert(argument != NULL);
Yann Colletd7883a22016-08-12 16:48:02 +02003104
3105 /* Parsing commands. Aggregated commands are allowed */
3106 if (argument[0]=='-') {
Yann Colletd7883a22016-08-12 16:48:02 +02003107
Yann Collet47c6a952017-09-28 18:27:22 -07003108 if (!strcmp(argument, "--newapi")) { selected_api=advanced_api; testNb += !testNb; continue; }
Sean Purcell7ebf2de2017-03-20 11:25:00 -07003109 if (!strcmp(argument, "--no-big-tests")) { bigTests=0; continue; }
Elliott Hughes44aba642023-09-12 20:18:59 +00003110 if (!strcmp(argument, "--big-tests")) { bigTests=1; continue; }
Yann Collet19d670b2017-01-19 15:32:07 -08003111
3112 argument++;
Yann Colletd7883a22016-08-12 16:48:02 +02003113 while (*argument!=0) {
3114 switch(*argument)
3115 {
3116 case 'h':
3117 return FUZ_usage(programName);
Yann Collet736788f2017-01-19 12:12:50 -08003118
Yann Colletd7883a22016-08-12 16:48:02 +02003119 case 'v':
3120 argument++;
Yann Collet736788f2017-01-19 12:12:50 -08003121 g_displayLevel++;
Yann Colletd7883a22016-08-12 16:48:02 +02003122 break;
Yann Collet736788f2017-01-19 12:12:50 -08003123
Yann Colletd7883a22016-08-12 16:48:02 +02003124 case 'q':
3125 argument++;
3126 g_displayLevel--;
3127 break;
Yann Collet736788f2017-01-19 12:12:50 -08003128
Yann Colletd7883a22016-08-12 16:48:02 +02003129 case 'p': /* pause at the end */
3130 argument++;
3131 mainPause = 1;
3132 break;
3133
Yann Collet736788f2017-01-19 12:12:50 -08003134 case 'i': /* limit tests by nb of iterations (default) */
Yann Colletd7883a22016-08-12 16:48:02 +02003135 argument++;
Yann Colletef9999f2016-09-01 16:44:48 -07003136 nbTests=0; g_clockTime=0;
Yann Colletd7883a22016-08-12 16:48:02 +02003137 while ((*argument>='0') && (*argument<='9')) {
3138 nbTests *= 10;
3139 nbTests += *argument - '0';
3140 argument++;
3141 }
3142 break;
3143
Yann Collet736788f2017-01-19 12:12:50 -08003144 case 'T': /* limit tests by time */
Yann Colletd7883a22016-08-12 16:48:02 +02003145 argument++;
Yann Colletef9999f2016-09-01 16:44:48 -07003146 nbTests=0; g_clockTime=0;
Yann Colletd7883a22016-08-12 16:48:02 +02003147 while ((*argument>='0') && (*argument<='9')) {
Yann Colletef9999f2016-09-01 16:44:48 -07003148 g_clockTime *= 10;
3149 g_clockTime += *argument - '0';
Yann Colletd7883a22016-08-12 16:48:02 +02003150 argument++;
3151 }
Yann Colletbd88f632017-11-27 12:15:23 -08003152 if (*argument=='m') { /* -T1m == -T60 */
3153 g_clockTime *=60, argument++;
3154 if (*argument=='n') argument++; /* -T1mn == -T60 */
3155 } else if (*argument=='s') argument++; /* -T10s == -T10 */
Nick Terrell9a2f6f42017-11-29 19:11:12 -08003156 g_clockTime *= SEC_TO_MICRO;
Yann Colletd7883a22016-08-12 16:48:02 +02003157 break;
3158
Yann Collet736788f2017-01-19 12:12:50 -08003159 case 's': /* manually select seed */
Yann Colletd7883a22016-08-12 16:48:02 +02003160 argument++;
Yann Colletd7883a22016-08-12 16:48:02 +02003161 seedset=1;
Yann Colletbd88f632017-11-27 12:15:23 -08003162 seed=0;
Yann Colletd7883a22016-08-12 16:48:02 +02003163 while ((*argument>='0') && (*argument<='9')) {
3164 seed *= 10;
3165 seed += *argument - '0';
3166 argument++;
3167 }
3168 break;
3169
Yann Collet736788f2017-01-19 12:12:50 -08003170 case 't': /* select starting test number */
Yann Colletd7883a22016-08-12 16:48:02 +02003171 argument++;
3172 testNb=0;
3173 while ((*argument>='0') && (*argument<='9')) {
3174 testNb *= 10;
3175 testNb += *argument - '0';
3176 argument++;
3177 }
3178 break;
3179
3180 case 'P': /* compressibility % */
3181 argument++;
3182 proba=0;
3183 while ((*argument>='0') && (*argument<='9')) {
3184 proba *= 10;
3185 proba += *argument - '0';
3186 argument++;
3187 }
3188 if (proba<0) proba=0;
3189 if (proba>100) proba=100;
3190 break;
3191
3192 default:
3193 return FUZ_usage(programName);
3194 }
3195 } } } /* for(argNb=1; argNb<argc; argNb++) */
3196
3197 /* Get Seed */
Yann Colletbb855812016-08-25 19:11:11 +02003198 DISPLAY("Starting zstream tester (%i-bits, %s)\n", (int)(sizeof(size_t)*8), ZSTD_VERSION_STRING);
Yann Colletd7883a22016-08-12 16:48:02 +02003199
Yann Colletef9999f2016-09-01 16:44:48 -07003200 if (!seedset) {
3201 time_t const t = time(NULL);
3202 U32 const h = XXH32(&t, sizeof(t), 1);
3203 seed = h % 10000;
3204 }
3205
Yann Colletededcfc2018-12-21 16:19:44 -08003206 DISPLAY("Seed = %u\n", (unsigned)seed);
Yann Colletd7883a22016-08-12 16:48:02 +02003207 if (proba!=FUZ_COMPRESSIBILITY_DEFAULT) DISPLAY("Compressibility : %i%%\n", proba);
3208
3209 if (nbTests<=0) nbTests=1;
3210
3211 if (testNb==0) {
Elliott Hughes44aba642023-09-12 20:18:59 +00003212 result = basicUnitTests(0, ((double)proba) / 100, bigTests); /* constant seed for predictability */
Yann Collet4616fad2017-07-10 17:16:41 -07003213 }
Yann Colletd7883a22016-08-12 16:48:02 +02003214
Yann Collet01743a32017-06-16 17:56:41 -07003215 if (!result) {
3216 switch(selected_api)
3217 {
3218 case simple_api :
3219 result = fuzzerTests(seed, nbTests, testNb, ((double)proba) / 100, bigTests);
3220 break;
Yann Collet01743a32017-06-16 17:56:41 -07003221 case advanced_api :
Yann Colletc9e8ee92018-06-18 19:20:37 -07003222 result = fuzzerTests_newAPI(seed, nbTests, testNb, ((double)proba) / 100, bigTests);
Yann Collet01743a32017-06-16 17:56:41 -07003223 break;
3224 default :
3225 assert(0); /* impossible */
3226 }
3227 }
Yann Colletd7883a22016-08-12 16:48:02 +02003228
3229 if (mainPause) {
3230 int unused;
3231 DISPLAY("Press Enter \n");
3232 unused = getchar();
3233 (void)unused;
3234 }
3235 return result;
3236}