blob: 1855b4dec3c5ac82cbb00295c0e2b26fc8f464f8 [file] [log] [blame]
Yann Collet32fb4072017-08-18 16:52:05 -07001/*
Nick Terrellac58c8d2020-03-26 15:19:05 -07002 * Copyright (c) 2016-2020, Yann Collet, Facebook, Inc.
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 */
Yann Collet01743a32017-06-16 17:56:41 -070028#include <assert.h> /* assert */
Lzu Taofb6901b2019-04-12 21:28:17 +070029#include "timefn.h" /* UTIL_time_t, UTIL_getTime */
Yann Colletd7883a22016-08-12 16:48:02 +020030#include "mem.h"
Yann Colleta5ffe3d2017-05-12 16:29:19 -070031#define ZSTD_STATIC_LINKING_ONLY /* ZSTD_maxCLevel, ZSTD_customMem, ZSTD_getDictID_fromFrame */
Yann Colletd7883a22016-08-12 16:48:02 +020032#include "zstd.h" /* ZSTD_compressBound */
Yann Collete795c8a2016-12-13 16:39:36 +010033#include "zstd_errors.h" /* ZSTD_error_srcSize_wrong */
Yann Collet33fce032017-01-16 19:46:22 -080034#include "zdict.h" /* ZDICT_trainFromBuffer */
Yann Colletd7883a22016-08-12 16:48:02 +020035#include "datagen.h" /* RDG_genBuffer */
Yann Colletef9999f2016-09-01 16:44:48 -070036#define XXH_STATIC_LINKING_ONLY /* XXH64_state_t */
Yann Colletd7883a22016-08-12 16:48:02 +020037#include "xxhash.h" /* XXH64_* */
Nick Terrelle600b5d2017-10-16 17:18:43 -070038#include "seqgen.h"
Nick Terrell9a2f6f42017-11-29 19:11:12 -080039#include "util.h"
Yann Collet59a71162019-04-10 12:37:03 -070040#include "timefn.h" /* UTIL_time_t, UTIL_clockSpanMicro, UTIL_getTime */
Yann Colletd7883a22016-08-12 16:48:02 +020041
42
43/*-************************************
Yann Colletc9e8ee92018-06-18 19:20:37 -070044 * Constants
45 **************************************/
Yann Colletd7883a22016-08-12 16:48:02 +020046#define KB *(1U<<10)
47#define MB *(1U<<20)
48#define GB *(1U<<30)
49
Yann Colletededcfc2018-12-21 16:19:44 -080050static const int nbTestsDefault = 10000;
Yann Colletf99c2c12017-06-21 23:35:58 -070051static const U32 g_cLevelMax_smallTests = 10;
Yann Colletd7883a22016-08-12 16:48:02 +020052#define COMPRESSIBLE_NOISE_LENGTH (10 MB)
53#define FUZ_COMPRESSIBILITY_DEFAULT 50
Yann Collet33fce032017-01-16 19:46:22 -080054static const U32 prime32 = 2654435761U;
Yann Colletd7883a22016-08-12 16:48:02 +020055
56
Yann Colletd7883a22016-08-12 16:48:02 +020057/*-************************************
Yann Colletc9e8ee92018-06-18 19:20:37 -070058 * Display Macros
59 **************************************/
Yann Colletd7883a22016-08-12 16:48:02 +020060#define DISPLAY(...) fprintf(stderr, __VA_ARGS__)
Yann Collet0be6fd32017-05-08 16:08:01 -070061#define DISPLAYLEVEL(l, ...) if (g_displayLevel>=l) { \
62 DISPLAY(__VA_ARGS__); \
63 if (g_displayLevel>=4) fflush(stderr); }
Yann Colletd7883a22016-08-12 16:48:02 +020064static U32 g_displayLevel = 2;
65
Nick Terrell9a2f6f42017-11-29 19:11:12 -080066static const U64 g_refreshRate = SEC_TO_MICRO / 6;
67static UTIL_time_t g_displayClock = UTIL_TIME_INITIALIZER;
Yann Colletd7883a22016-08-12 16:48:02 +020068
Nick Terrell9a2f6f42017-11-29 19:11:12 -080069#define DISPLAYUPDATE(l, ...) if (g_displayLevel>=l) { \
70 if ((UTIL_clockSpanMicro(g_displayClock) > g_refreshRate) || (g_displayLevel>=4)) \
71 { g_displayClock = UTIL_getTime(); DISPLAY(__VA_ARGS__); \
72 if (g_displayLevel>=4) fflush(stderr); } }
73
74static U64 g_clockTime = 0;
Yann Colletd7883a22016-08-12 16:48:02 +020075
76
77/*-*******************************************************
Yann Colletc9e8ee92018-06-18 19:20:37 -070078 * Check macros
79 *********************************************************/
Nick Terrell9a2f6f42017-11-29 19:11:12 -080080#undef MIN
81#undef MAX
82#define MIN(a,b) ((a)<(b)?(a):(b))
Yann Colletd7883a22016-08-12 16:48:02 +020083#define MAX(a,b) ((a)>(b)?(a):(b))
Yann Colletd7883a22016-08-12 16:48:02 +020084/*! FUZ_rand() :
85 @return : a 27 bits random value, from a 32-bits `seed`.
86 `seed` is also modified */
Yann Collet95162342016-10-25 16:19:52 -070087#define FUZ_rotl32(x,r) ((x << r) | (x >> (32 - r)))
Yann Colletededcfc2018-12-21 16:19:44 -080088static U32 FUZ_rand(U32* seedPtr)
Yann Colletd7883a22016-08-12 16:48:02 +020089{
Yann Collet33fce032017-01-16 19:46:22 -080090 static const U32 prime2 = 2246822519U;
Yann Colletd7883a22016-08-12 16:48:02 +020091 U32 rand32 = *seedPtr;
Yann Collet33fce032017-01-16 19:46:22 -080092 rand32 *= prime32;
Yann Colletd7883a22016-08-12 16:48:02 +020093 rand32 += prime2;
94 rand32 = FUZ_rotl32(rand32, 13);
95 *seedPtr = rand32;
96 return rand32 >> 5;
97}
98
Nick Terrelle600b5d2017-10-16 17:18:43 -070099#define CHECK(cond, ...) { \
100 if (cond) { \
101 DISPLAY("Error => "); \
102 DISPLAY(__VA_ARGS__); \
Yann Colletebd955e2018-01-23 13:12:40 -0800103 DISPLAY(" (seed %u, test nb %u, line %u) \n", \
Yann Colletededcfc2018-12-21 16:19:44 -0800104 (unsigned)seed, testNb, __LINE__); \
Yann Colletd6770f82017-09-28 02:14:48 -0700105 goto _output_error; \
106} }
107
Nick Terrelle600b5d2017-10-16 17:18:43 -0700108#define CHECK_Z(f) { \
109 size_t const err = f; \
110 CHECK(ZSTD_isError(err), "%s : %s ", \
111 #f, ZSTD_getErrorName(err)); \
112}
113
Nick Terrellca778222018-04-25 16:32:29 -0700114#define CHECK_RET(ret, cond, ...) { \
115 if (cond) { \
116 DISPLAY("Error %llu => ", (unsigned long long)ret); \
117 DISPLAY(__VA_ARGS__); \
118 DISPLAY(" (line %u)\n", __LINE__); \
119 return ret; \
120} }
121
122#define CHECK_RET_Z(f) { \
123 size_t const err = f; \
124 CHECK_RET(err, ZSTD_isError(err), "%s : %s ", \
125 #f, ZSTD_getErrorName(err)); \
126}
127
Yann Colletcb327632016-08-23 00:30:31 +0200128
129/*======================================================
Yann Colletc9e8ee92018-06-18 19:20:37 -0700130 * Basic Unit tests
131 *======================================================*/
Yann Colletcb327632016-08-23 00:30:31 +0200132
Yann Collet33fce032017-01-16 19:46:22 -0800133typedef struct {
134 void* start;
135 size_t size;
136 size_t filled;
137} buffer_t;
138
Yann Colletd195eec2018-09-13 12:29:52 -0700139static const buffer_t kBuffNull = { NULL, 0 , 0 };
140
141static void FUZ_freeDictionary(buffer_t dict)
142{
143 free(dict.start);
144}
Yann Collet33fce032017-01-16 19:46:22 -0800145
146static buffer_t FUZ_createDictionary(const void* src, size_t srcSize, size_t blockSize, size_t requestedDictSize)
147{
Yann Colletd195eec2018-09-13 12:29:52 -0700148 buffer_t dict = kBuffNull;
Yann Collet33fce032017-01-16 19:46:22 -0800149 size_t const nbBlocks = (srcSize + (blockSize-1)) / blockSize;
Yann Colletd195eec2018-09-13 12:29:52 -0700150 size_t* const blockSizes = (size_t*)malloc(nbBlocks * sizeof(size_t));
151 if (!blockSizes) return kBuffNull;
Yann Collet33fce032017-01-16 19:46:22 -0800152 dict.start = malloc(requestedDictSize);
Yann Colletd195eec2018-09-13 12:29:52 -0700153 if (!dict.start) { free(blockSizes); return kBuffNull; }
Yann Collet33fce032017-01-16 19:46:22 -0800154 { size_t nb;
155 for (nb=0; nb<nbBlocks-1; nb++) blockSizes[nb] = blockSize;
156 blockSizes[nbBlocks-1] = srcSize - (blockSize * (nbBlocks-1));
157 }
158 { size_t const dictSize = ZDICT_trainFromBuffer(dict.start, requestedDictSize, src, blockSizes, (unsigned)nbBlocks);
159 free(blockSizes);
Yann Colletd195eec2018-09-13 12:29:52 -0700160 if (ZDICT_isError(dictSize)) { FUZ_freeDictionary(dict); return kBuffNull; }
Yann Collet33fce032017-01-16 19:46:22 -0800161 dict.size = requestedDictSize;
162 dict.filled = dictSize;
Yann Colletd195eec2018-09-13 12:29:52 -0700163 return dict;
Yann Collet33fce032017-01-16 19:46:22 -0800164 }
165}
166
Nick Terrelle600b5d2017-10-16 17:18:43 -0700167/* Round trips data and updates xxh with the decompressed data produced */
168static size_t SEQ_roundTrip(ZSTD_CCtx* cctx, ZSTD_DCtx* dctx,
169 XXH64_state_t* xxh, void* data, size_t size,
170 ZSTD_EndDirective endOp)
171{
172 static BYTE compressed[1024];
173 static BYTE uncompressed[1024];
174
175 ZSTD_inBuffer cin = {data, size, 0};
176 size_t cret;
177
178 do {
Yann Colletd8e215c2018-11-30 11:16:26 -0800179 ZSTD_outBuffer cout = { compressed, sizeof(compressed), 0 };
180 ZSTD_inBuffer din = { compressed, 0, 0 };
181 ZSTD_outBuffer dout = { uncompressed, 0, 0 };
Nick Terrelle600b5d2017-10-16 17:18:43 -0700182
Yann Colletd8e215c2018-11-30 11:16:26 -0800183 cret = ZSTD_compressStream2(cctx, &cout, &cin, endOp);
Nick Terrelle600b5d2017-10-16 17:18:43 -0700184 if (ZSTD_isError(cret))
185 return cret;
186
187 din.size = cout.pos;
188 while (din.pos < din.size || (endOp == ZSTD_e_end && cret == 0)) {
189 size_t dret;
190
191 dout.pos = 0;
192 dout.size = sizeof(uncompressed);
193 dret = ZSTD_decompressStream(dctx, &dout, &din);
194 if (ZSTD_isError(dret))
195 return dret;
196 XXH64_update(xxh, dout.dst, dout.pos);
197 if (dret == 0)
198 break;
199 }
200 } while (cin.pos < cin.size || (endOp != ZSTD_e_continue && cret != 0));
201 return 0;
202}
203
204/* Generates some data and round trips it */
205static size_t SEQ_generateRoundTrip(ZSTD_CCtx* cctx, ZSTD_DCtx* dctx,
206 XXH64_state_t* xxh, SEQ_stream* seq,
207 SEQ_gen_type type, unsigned value)
208{
209 static BYTE data[1024];
210 size_t gen;
211
212 do {
213 SEQ_outBuffer sout = {data, sizeof(data), 0};
214 size_t ret;
215 gen = SEQ_gen(seq, type, value, &sout);
216
217 ret = SEQ_roundTrip(cctx, dctx, xxh, sout.dst, sout.pos, ZSTD_e_continue);
218 if (ZSTD_isError(ret))
219 return ret;
220 } while (gen != 0);
221
222 return 0;
223}
Yann Collet33fce032017-01-16 19:46:22 -0800224
Nick Terrellca778222018-04-25 16:32:29 -0700225static size_t getCCtxParams(ZSTD_CCtx* zc, ZSTD_parameters* savedParams)
226{
Yann Colletd4d4e102018-11-21 15:37:26 -0800227 int value;
Yann Collet3583d192018-12-05 17:26:02 -0800228 CHECK_RET_Z(ZSTD_CCtx_getParameter(zc, ZSTD_c_windowLog, (int*)&savedParams->cParams.windowLog));
229 CHECK_RET_Z(ZSTD_CCtx_getParameter(zc, ZSTD_c_hashLog, (int*)&savedParams->cParams.hashLog));
230 CHECK_RET_Z(ZSTD_CCtx_getParameter(zc, ZSTD_c_chainLog, (int*)&savedParams->cParams.chainLog));
231 CHECK_RET_Z(ZSTD_CCtx_getParameter(zc, ZSTD_c_searchLog, (int*)&savedParams->cParams.searchLog));
232 CHECK_RET_Z(ZSTD_CCtx_getParameter(zc, ZSTD_c_minMatch, (int*)&savedParams->cParams.minMatch));
233 CHECK_RET_Z(ZSTD_CCtx_getParameter(zc, ZSTD_c_targetLength, (int*)&savedParams->cParams.targetLength));
Yann Colletbe9e5612018-12-06 15:00:52 -0800234 CHECK_RET_Z(ZSTD_CCtx_getParameter(zc, ZSTD_c_strategy, &value));
Nick Terrellca778222018-04-25 16:32:29 -0700235 savedParams->cParams.strategy = value;
236
Yann Collet3583d192018-12-05 17:26:02 -0800237 CHECK_RET_Z(ZSTD_CCtx_getParameter(zc, ZSTD_c_checksumFlag, &savedParams->fParams.checksumFlag));
238 CHECK_RET_Z(ZSTD_CCtx_getParameter(zc, ZSTD_c_contentSizeFlag, &savedParams->fParams.contentSizeFlag));
239 CHECK_RET_Z(ZSTD_CCtx_getParameter(zc, ZSTD_c_dictIDFlag, &value));
Nick Terrellca778222018-04-25 16:32:29 -0700240 savedParams->fParams.noDictIDFlag = !value;
241 return 0;
242}
243
244static U32 badParameters(ZSTD_CCtx* zc, ZSTD_parameters const savedParams)
245{
246 ZSTD_parameters params;
247 if (ZSTD_isError(getCCtxParams(zc, &params))) return 10;
248 CHECK_RET(1, params.cParams.windowLog != savedParams.cParams.windowLog, "windowLog");
249 CHECK_RET(2, params.cParams.hashLog != savedParams.cParams.hashLog, "hashLog");
250 CHECK_RET(3, params.cParams.chainLog != savedParams.cParams.chainLog, "chainLog");
251 CHECK_RET(4, params.cParams.searchLog != savedParams.cParams.searchLog, "searchLog");
Yann Collete874dac2018-11-20 14:56:07 -0800252 CHECK_RET(5, params.cParams.minMatch != savedParams.cParams.minMatch, "minMatch");
Nick Terrellca778222018-04-25 16:32:29 -0700253 CHECK_RET(6, params.cParams.targetLength != savedParams.cParams.targetLength, "targetLength");
254
255 CHECK_RET(7, params.fParams.checksumFlag != savedParams.fParams.checksumFlag, "checksumFlag");
256 CHECK_RET(8, params.fParams.contentSizeFlag != savedParams.fParams.contentSizeFlag, "contentSizeFlag");
257 CHECK_RET(9, params.fParams.noDictIDFlag != savedParams.fParams.noDictIDFlag, "noDictIDFlag");
258 return 0;
259}
260
Yann Colletbd88f632017-11-27 12:15:23 -0800261static int basicUnitTests(U32 seed, double compressibility)
Yann Colletd7883a22016-08-12 16:48:02 +0200262{
Yann Colletb3060f72016-09-09 16:44:16 +0200263 size_t const CNBufferSize = COMPRESSIBLE_NOISE_LENGTH;
Yann Colletd7883a22016-08-12 16:48:02 +0200264 void* CNBuffer = malloc(CNBufferSize);
Nick Terrelle19b0822017-11-01 13:10:03 -0700265 size_t const skippableFrameSize = 200 KB;
Yann Colletd7883a22016-08-12 16:48:02 +0200266 size_t const compressedBufferSize = (8 + skippableFrameSize) + ZSTD_compressBound(COMPRESSIBLE_NOISE_LENGTH);
267 void* compressedBuffer = malloc(compressedBufferSize);
268 size_t const decodedBufferSize = CNBufferSize;
269 void* decodedBuffer = malloc(decodedBufferSize);
270 size_t cSize;
Yann Colletb3060f72016-09-09 16:44:16 +0200271 int testResult = 0;
Yann Colletededcfc2018-12-21 16:19:44 -0800272 int testNb = 1;
Yann Collet67113962018-01-19 22:11:11 -0800273 U32 coreSeed = 0; /* this name to conform with CHECK_Z macro display */
Yann Colletbd88f632017-11-27 12:15:23 -0800274 ZSTD_CStream* zc = ZSTD_createCStream();
275 ZSTD_DStream* zd = ZSTD_createDStream();
Nick Terrellc51a9e72020-10-01 18:47:54 -0700276 ZSTD_CCtx* mtctx = ZSTD_createCCtx();
Stella Lau90a31bf2017-08-30 14:36:54 -0700277
Yann Collet9ffbeea2016-12-02 18:37:38 -0800278 ZSTD_inBuffer inBuff, inBuff2;
Yann Collet53e17fb2016-08-17 01:39:22 +0200279 ZSTD_outBuffer outBuff;
Yann Colletd195eec2018-09-13 12:29:52 -0700280 buffer_t dictionary = kBuffNull;
Yann Collet30ab64e2017-05-10 11:30:19 -0700281 size_t const dictSize = 128 KB;
Yann Collet33fce032017-01-16 19:46:22 -0800282 unsigned dictID = 0;
Yann Colletd7883a22016-08-12 16:48:02 +0200283
284 /* Create compressible test buffer */
Nick Terrellc51a9e72020-10-01 18:47:54 -0700285 if (!CNBuffer || !compressedBuffer || !decodedBuffer || !zc || !zd || !mtctx) {
Yann Collet33fce032017-01-16 19:46:22 -0800286 DISPLAY("Not enough memory, aborting \n");
Yann Colletd7883a22016-08-12 16:48:02 +0200287 goto _output_error;
288 }
289 RDG_genBuffer(CNBuffer, CNBufferSize, compressibility, 0., seed);
290
Nick Terrellc51a9e72020-10-01 18:47:54 -0700291 CHECK_Z(ZSTD_CCtx_setParameter(mtctx, ZSTD_c_nbWorkers, 2));
292
Yann Collet33fce032017-01-16 19:46:22 -0800293 /* Create dictionary */
Yann Collete0065cf2017-09-28 18:34:38 -0700294 DISPLAYLEVEL(3, "creating dictionary for unit tests \n");
Yann Colletb18cb7e2018-03-20 16:18:48 -0700295 dictionary = FUZ_createDictionary(CNBuffer, CNBufferSize / 3, 16 KB, 48 KB);
Yann Collet33fce032017-01-16 19:46:22 -0800296 if (!dictionary.start) {
297 DISPLAY("Error creating dictionary, aborting \n");
298 goto _output_error;
299 }
300 dictID = ZDICT_getDictID(dictionary.start, dictionary.filled);
301
Yann Collet21f76722017-12-07 03:06:01 -0500302 /* Basic compression test */
303 DISPLAYLEVEL(3, "test%3i : compress %u bytes : ", testNb++, COMPRESSIBLE_NOISE_LENGTH);
304 CHECK_Z( ZSTD_initCStream(zc, 1 /* cLevel */) );
305 outBuff.dst = (char*)(compressedBuffer);
306 outBuff.size = compressedBufferSize;
307 outBuff.pos = 0;
308 inBuff.src = CNBuffer;
309 inBuff.size = CNBufferSize;
310 inBuff.pos = 0;
311 CHECK_Z( ZSTD_compressStream(zc, &outBuff, &inBuff) );
312 if (inBuff.pos != inBuff.size) goto _output_error; /* entire input should be consumed */
313 { size_t const r = ZSTD_endStream(zc, &outBuff);
314 if (r != 0) goto _output_error; } /* error, or some data not flushed */
Yann Colletededcfc2018-12-21 16:19:44 -0800315 DISPLAYLEVEL(3, "OK (%u bytes)\n", (unsigned)outBuff.pos);
Yann Collet21f76722017-12-07 03:06:01 -0500316
Yann Colletd7883a22016-08-12 16:48:02 +0200317 /* generate skippable frame */
318 MEM_writeLE32(compressedBuffer, ZSTD_MAGIC_SKIPPABLE_START);
319 MEM_writeLE32(((char*)compressedBuffer)+4, (U32)skippableFrameSize);
320 cSize = skippableFrameSize + 8;
321
Yann Collet21f76722017-12-07 03:06:01 -0500322 /* Basic compression test using dict */
323 DISPLAYLEVEL(3, "test%3i : skipframe + compress %u bytes : ", testNb++, COMPRESSIBLE_NOISE_LENGTH);
Yann Collet3c1e3f82017-10-13 18:32:06 -0700324 CHECK_Z( ZSTD_initCStream_usingDict(zc, CNBuffer, dictSize, 1 /* cLevel */) );
Yann Collet53e17fb2016-08-17 01:39:22 +0200325 outBuff.dst = (char*)(compressedBuffer)+cSize;
Yann Collet3c1e3f82017-10-13 18:32:06 -0700326 assert(compressedBufferSize > cSize);
327 outBuff.size = compressedBufferSize - cSize;
Yann Collet53e17fb2016-08-17 01:39:22 +0200328 outBuff.pos = 0;
329 inBuff.src = CNBuffer;
330 inBuff.size = CNBufferSize;
331 inBuff.pos = 0;
Yann Colletd6770f82017-09-28 02:14:48 -0700332 CHECK_Z( ZSTD_compressStream(zc, &outBuff, &inBuff) );
Yann Collet53e17fb2016-08-17 01:39:22 +0200333 if (inBuff.pos != inBuff.size) goto _output_error; /* entire input should be consumed */
334 { size_t const r = ZSTD_endStream(zc, &outBuff);
Yann Collet9a021c12016-08-26 09:05:06 +0200335 if (r != 0) goto _output_error; } /* error, or some data not flushed */
Yann Collet53e17fb2016-08-17 01:39:22 +0200336 cSize += outBuff.pos;
Yann Colletededcfc2018-12-21 16:19:44 -0800337 DISPLAYLEVEL(3, "OK (%u bytes : %.2f%%)\n",
338 (unsigned)cSize, (double)cSize/COMPRESSIBLE_NOISE_LENGTH*100);
Yann Colletd7883a22016-08-12 16:48:02 +0200339
Yann Collet30ab64e2017-05-10 11:30:19 -0700340 /* context size functions */
341 DISPLAYLEVEL(3, "test%3i : estimate CStream size : ", testNb++);
342 { ZSTD_compressionParameters const cParams = ZSTD_getCParams(1, CNBufferSize, dictSize);
Yann Collet96f0cde2017-09-24 16:47:02 -0700343 size_t const cstreamSize = ZSTD_estimateCStreamSize_usingCParams(cParams);
344 size_t const cdictSize = ZSTD_estimateCDictSize_advanced(dictSize, cParams, ZSTD_dlm_byCopy); /* uses ZSTD_initCStream_usingDict() */
345 if (ZSTD_isError(cstreamSize)) goto _output_error;
346 if (ZSTD_isError(cdictSize)) goto _output_error;
Yann Colletededcfc2018-12-21 16:19:44 -0800347 DISPLAYLEVEL(3, "OK (%u bytes) \n", (unsigned)(cstreamSize + cdictSize));
Yann Collet30ab64e2017-05-10 11:30:19 -0700348 }
349
Nick Terrell56682a72019-04-01 17:51:28 -0700350 /* context size functions */
351 DISPLAYLEVEL(3, "test%3i : estimate CStream size using CCtxParams : ", testNb++);
352 { ZSTD_CCtx_params* const params = ZSTD_createCCtxParams();
353 size_t cstreamSize, cctxSize;
354 CHECK_Z( ZSTD_CCtxParams_setParameter(params, ZSTD_c_compressionLevel, 19) );
355 cstreamSize = ZSTD_estimateCStreamSize_usingCCtxParams(params);
356 CHECK_Z(cstreamSize);
357 cctxSize = ZSTD_estimateCCtxSize_usingCCtxParams(params);
358 CHECK_Z(cctxSize);
359 if (cstreamSize <= cctxSize + 2 * ZSTD_BLOCKSIZE_MAX) goto _output_error;
360 ZSTD_freeCCtxParams(params);
361 DISPLAYLEVEL(3, "OK \n");
362 }
363
Yann Collet30ab64e2017-05-10 11:30:19 -0700364 DISPLAYLEVEL(3, "test%3i : check actual CStream size : ", testNb++);
Yann Colletdce78922017-06-21 15:53:42 -0700365 { size_t const s = ZSTD_sizeof_CStream(zc);
366 if (ZSTD_isError(s)) goto _output_error;
Yann Colletededcfc2018-12-21 16:19:44 -0800367 DISPLAYLEVEL(3, "OK (%u bytes) \n", (unsigned)s);
Yann Colletcb327632016-08-23 00:30:31 +0200368 }
369
Yann Collet4b987ad2017-04-10 17:50:44 -0700370 /* Attempt bad compression parameters */
371 DISPLAYLEVEL(3, "test%3i : use bad compression parameters : ", testNb++);
372 { size_t r;
373 ZSTD_parameters params = ZSTD_getParams(1, 0, 0);
Yann Collete874dac2018-11-20 14:56:07 -0800374 params.cParams.minMatch = 2;
Yann Collet4b987ad2017-04-10 17:50:44 -0700375 r = ZSTD_initCStream_advanced(zc, NULL, 0, params, 0);
376 if (!ZSTD_isError(r)) goto _output_error;
377 DISPLAYLEVEL(3, "init error : %s \n", ZSTD_getErrorName(r));
378 }
379
Yann Colletd7883a22016-08-12 16:48:02 +0200380 /* skippable frame test */
Yann Collet736788f2017-01-19 12:12:50 -0800381 DISPLAYLEVEL(3, "test%3i : decompress skippable frame : ", testNb++);
Yann Colletd6770f82017-09-28 02:14:48 -0700382 CHECK_Z( ZSTD_initDStream_usingDict(zd, CNBuffer, dictSize) );
Yann Collet53e17fb2016-08-17 01:39:22 +0200383 inBuff.src = compressedBuffer;
384 inBuff.size = cSize;
385 inBuff.pos = 0;
386 outBuff.dst = decodedBuffer;
387 outBuff.size = CNBufferSize;
388 outBuff.pos = 0;
Yann Colletdce78922017-06-21 15:53:42 -0700389 { size_t const r = ZSTD_decompressStream(zd, &outBuff, &inBuff);
Yann Colletededcfc2018-12-21 16:19:44 -0800390 DISPLAYLEVEL(5, " ( ZSTD_decompressStream => %u ) ", (unsigned)r);
Yann Colletdce78922017-06-21 15:53:42 -0700391 if (r != 0) goto _output_error;
392 }
Yann Colleta33ae642017-02-28 01:15:28 -0800393 if (outBuff.pos != 0) goto _output_error; /* skippable frame output len is 0 */
Yann Collet736788f2017-01-19 12:12:50 -0800394 DISPLAYLEVEL(3, "OK \n");
Yann Colletd7883a22016-08-12 16:48:02 +0200395
396 /* Basic decompression test */
Yann Collet9ffbeea2016-12-02 18:37:38 -0800397 inBuff2 = inBuff;
Yann Collet736788f2017-01-19 12:12:50 -0800398 DISPLAYLEVEL(3, "test%3i : decompress %u bytes : ", testNb++, COMPRESSIBLE_NOISE_LENGTH);
Yann Collet30ab64e2017-05-10 11:30:19 -0700399 ZSTD_initDStream_usingDict(zd, CNBuffer, dictSize);
Yann Collet3e042d52018-12-04 17:30:58 -0800400 CHECK_Z( ZSTD_DCtx_setParameter(zd, ZSTD_d_windowLogMax, ZSTD_WINDOWLOG_LIMIT_DEFAULT+1) ); /* large limit */
Yann Collet9ffbeea2016-12-02 18:37:38 -0800401 { size_t const remaining = ZSTD_decompressStream(zd, &outBuff, &inBuff);
402 if (remaining != 0) goto _output_error; } /* should reach end of frame == 0; otherwise, some data left, or an error */
403 if (outBuff.pos != CNBufferSize) goto _output_error; /* should regenerate the same amount */
404 if (inBuff.pos != inBuff.size) goto _output_error; /* should have read the entire frame */
Yann Collet736788f2017-01-19 12:12:50 -0800405 DISPLAYLEVEL(3, "OK \n");
Yann Collet9ffbeea2016-12-02 18:37:38 -0800406
407 /* Re-use without init */
Yann Collet736788f2017-01-19 12:12:50 -0800408 DISPLAYLEVEL(3, "test%3i : decompress again without init (re-use previous settings): ", testNb++);
Yann Collet9ffbeea2016-12-02 18:37:38 -0800409 outBuff.pos = 0;
410 { size_t const remaining = ZSTD_decompressStream(zd, &outBuff, &inBuff2);
411 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 +0200412 if (outBuff.pos != CNBufferSize) goto _output_error; /* should regenerate the same amount */
413 if (inBuff.pos != inBuff.size) goto _output_error; /* should have read the entire frame */
Yann Collet736788f2017-01-19 12:12:50 -0800414 DISPLAYLEVEL(3, "OK \n");
Yann Colletd7883a22016-08-12 16:48:02 +0200415
416 /* check regenerated data is byte exact */
Yann Collet736788f2017-01-19 12:12:50 -0800417 DISPLAYLEVEL(3, "test%3i : check decompressed result : ", testNb++);
Yann Colletd7883a22016-08-12 16:48:02 +0200418 { size_t i;
419 for (i=0; i<CNBufferSize; i++) {
420 if (((BYTE*)decodedBuffer)[i] != ((BYTE*)CNBuffer)[i]) goto _output_error;
421 } }
Yann Collet736788f2017-01-19 12:12:50 -0800422 DISPLAYLEVEL(3, "OK \n");
Yann Colletd7883a22016-08-12 16:48:02 +0200423
Yann Colletf16f4492017-05-09 16:18:17 -0700424 /* context size functions */
425 DISPLAYLEVEL(3, "test%3i : estimate DStream size : ", testNb++);
426 { ZSTD_frameHeader fhi;
427 const void* cStart = (char*)compressedBuffer + (skippableFrameSize + 8);
428 size_t const gfhError = ZSTD_getFrameHeader(&fhi, cStart, cSize);
429 if (gfhError!=0) goto _output_error;
Yann Colletededcfc2018-12-21 16:19:44 -0800430 DISPLAYLEVEL(5, " (windowSize : %u) ", (unsigned)fhi.windowSize);
Yann Colletdde10b22017-06-26 17:44:26 -0700431 { size_t const s = ZSTD_estimateDStreamSize(fhi.windowSize)
Yann Collet25989e32017-05-25 15:07:37 -0700432 /* uses ZSTD_initDStream_usingDict() */
Stella Lauc88fb922017-08-29 11:55:02 -0700433 + ZSTD_estimateDDictSize(dictSize, ZSTD_dlm_byCopy);
Yann Colletf16f4492017-05-09 16:18:17 -0700434 if (ZSTD_isError(s)) goto _output_error;
Yann Colletededcfc2018-12-21 16:19:44 -0800435 DISPLAYLEVEL(3, "OK (%u bytes) \n", (unsigned)s);
Yann Colletf16f4492017-05-09 16:18:17 -0700436 } }
437
438 DISPLAYLEVEL(3, "test%3i : check actual DStream size : ", testNb++);
Yann Collet70e3b312016-08-23 01:18:06 +0200439 { size_t const s = ZSTD_sizeof_DStream(zd);
Yann Colletcb327632016-08-23 00:30:31 +0200440 if (ZSTD_isError(s)) goto _output_error;
Yann Colletededcfc2018-12-21 16:19:44 -0800441 DISPLAYLEVEL(3, "OK (%u bytes) \n", (unsigned)s);
Yann Colletcb327632016-08-23 00:30:31 +0200442 }
443
Yann Collet67113962018-01-19 22:11:11 -0800444 /* Decompression by small increment */
Yann Collet736788f2017-01-19 12:12:50 -0800445 DISPLAYLEVEL(3, "test%3i : decompress byte-by-byte : ", testNb++);
Yann Collet3ecbe6a2016-09-14 17:26:59 +0200446 { /* skippable frame */
447 size_t r = 1;
Yann Collet30ab64e2017-05-10 11:30:19 -0700448 ZSTD_initDStream_usingDict(zd, CNBuffer, dictSize);
Yann Collet53e17fb2016-08-17 01:39:22 +0200449 inBuff.src = compressedBuffer;
450 outBuff.dst = decodedBuffer;
451 inBuff.pos = 0;
452 outBuff.pos = 0;
Yann Colletd7883a22016-08-12 16:48:02 +0200453 while (r) { /* skippable frame */
Yann Collet31769ce2018-06-22 17:58:21 -0700454 size_t const inSize = (FUZ_rand(&coreSeed) & 15) + 1;
455 size_t const outSize = (FUZ_rand(&coreSeed) & 15) + 1;
Yann Collet67113962018-01-19 22:11:11 -0800456 inBuff.size = inBuff.pos + inSize;
457 outBuff.size = outBuff.pos + outSize;
Yann Collet53e17fb2016-08-17 01:39:22 +0200458 r = ZSTD_decompressStream(zd, &outBuff, &inBuff);
Yann Collet31769ce2018-06-22 17:58:21 -0700459 if (ZSTD_isError(r)) DISPLAYLEVEL(4, "ZSTD_decompressStream on skippable frame error : %s \n", ZSTD_getErrorName(r));
Yann Colletd7883a22016-08-12 16:48:02 +0200460 if (ZSTD_isError(r)) goto _output_error;
461 }
Yann Collet3ecbe6a2016-09-14 17:26:59 +0200462 /* normal frame */
Yann Collet30ab64e2017-05-10 11:30:19 -0700463 ZSTD_initDStream_usingDict(zd, CNBuffer, dictSize);
Yann Colletd7883a22016-08-12 16:48:02 +0200464 r=1;
Yann Collet3ecbe6a2016-09-14 17:26:59 +0200465 while (r) {
Yann Collet67113962018-01-19 22:11:11 -0800466 size_t const inSize = FUZ_rand(&coreSeed) & 15;
Yann Collet31769ce2018-06-22 17:58:21 -0700467 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 -0800468 inBuff.size = inBuff.pos + inSize;
469 outBuff.size = outBuff.pos + outSize;
Yann Collet53e17fb2016-08-17 01:39:22 +0200470 r = ZSTD_decompressStream(zd, &outBuff, &inBuff);
Yann Collet31769ce2018-06-22 17:58:21 -0700471 if (ZSTD_isError(r)) DISPLAYLEVEL(4, "ZSTD_decompressStream error : %s \n", ZSTD_getErrorName(r));
Yann Colletd7883a22016-08-12 16:48:02 +0200472 if (ZSTD_isError(r)) goto _output_error;
473 }
474 }
Yann Collet31769ce2018-06-22 17:58:21 -0700475 if (outBuff.pos != CNBufferSize) DISPLAYLEVEL(4, "outBuff.pos != CNBufferSize : should have regenerated same amount ! \n");
Yann Collet53e17fb2016-08-17 01:39:22 +0200476 if (outBuff.pos != CNBufferSize) goto _output_error; /* should regenerate the same amount */
Yann Collet31769ce2018-06-22 17:58:21 -0700477 if (inBuff.pos != cSize) DISPLAYLEVEL(4, "inBuff.pos != cSize : should have real all input ! \n");
Yann Collet53e17fb2016-08-17 01:39:22 +0200478 if (inBuff.pos != cSize) goto _output_error; /* should have read the entire frame */
Yann Collet736788f2017-01-19 12:12:50 -0800479 DISPLAYLEVEL(3, "OK \n");
Yann Colletd7883a22016-08-12 16:48:02 +0200480
481 /* check regenerated data is byte exact */
Yann Collet736788f2017-01-19 12:12:50 -0800482 DISPLAYLEVEL(3, "test%3i : check decompressed result : ", testNb++);
Yann Colletd7883a22016-08-12 16:48:02 +0200483 { size_t i;
484 for (i=0; i<CNBufferSize; i++) {
Ed Masteb81d7cc2019-08-15 21:17:06 -0400485 if (((BYTE*)decodedBuffer)[i] != ((BYTE*)CNBuffer)[i]) goto _output_error;
Yann Colletd7883a22016-08-12 16:48:02 +0200486 } }
Yann Collet736788f2017-01-19 12:12:50 -0800487 DISPLAYLEVEL(3, "OK \n");
Yann Colletd7883a22016-08-12 16:48:02 +0200488
Yann Collet31769ce2018-06-22 17:58:21 -0700489 /* Decompression forward progress */
490 DISPLAYLEVEL(3, "test%3i : generate error when ZSTD_decompressStream() doesn't progress : ", testNb++);
491 { /* skippable frame */
492 size_t r = 0;
493 int decNb = 0;
494 int const maxDec = 100;
495 inBuff.src = compressedBuffer;
496 inBuff.size = cSize;
497 inBuff.pos = 0;
498
499 outBuff.dst = decodedBuffer;
500 outBuff.pos = 0;
501 outBuff.size = CNBufferSize-1; /* 1 byte missing */
502
503 for (decNb=0; decNb<maxDec; decNb++) {
504 if (r==0) ZSTD_initDStream_usingDict(zd, CNBuffer, dictSize);
505 r = ZSTD_decompressStream(zd, &outBuff, &inBuff);
506 if (ZSTD_isError(r)) break;
507 }
508 if (!ZSTD_isError(r)) DISPLAYLEVEL(4, "ZSTD_decompressStream should have triggered a no_forward_progress error \n");
509 if (!ZSTD_isError(r)) goto _output_error; /* should have triggered no_forward_progress error */
510 }
511 DISPLAYLEVEL(3, "OK \n");
512
Nick Terrell659e9f02019-11-20 18:21:51 -0800513 DISPLAYLEVEL(3, "test%3i : NULL buffers : ", testNb++);
514 inBuff.src = NULL;
515 inBuff.size = 0;
516 inBuff.pos = 0;
517 outBuff.dst = NULL;
518 outBuff.size = 0;
519 outBuff.pos = 0;
520 CHECK_Z( ZSTD_compressStream(zc, &outBuff, &inBuff) );
521 CHECK(inBuff.pos != inBuff.size, "Entire input should be consumed");
522 CHECK_Z( ZSTD_endStream(zc, &outBuff) );
523 outBuff.dst = (char*)(compressedBuffer);
524 outBuff.size = compressedBufferSize;
525 outBuff.pos = 0;
526 { size_t const r = ZSTD_endStream(zc, &outBuff);
527 CHECK(r != 0, "Error or some data not flushed (ret=%zu)", r);
528 }
529 inBuff.src = outBuff.dst;
530 inBuff.size = outBuff.pos;
531 inBuff.pos = 0;
532 outBuff.dst = NULL;
533 outBuff.size = 0;
534 outBuff.pos = 0;
535 CHECK_Z( ZSTD_initDStream(zd) );
536 { size_t const ret = ZSTD_decompressStream(zd, &outBuff, &inBuff);
537 if (ret != 0) goto _output_error;
538 }
539 DISPLAYLEVEL(3, "OK\n");
Yann Collete795c8a2016-12-13 16:39:36 +0100540 /* _srcSize compression test */
Yann Collet736788f2017-01-19 12:12:50 -0800541 DISPLAYLEVEL(3, "test%3i : compress_srcSize %u bytes : ", testNb++, COMPRESSIBLE_NOISE_LENGTH);
Nick Terrelle55da9e2019-03-13 14:05:18 -0700542 CHECK_Z( ZSTD_initCStream_srcSize(zc, 1, CNBufferSize) );
Yann Colletd564faa2016-12-18 21:39:15 +0100543 outBuff.dst = (char*)(compressedBuffer);
Yann Collete795c8a2016-12-13 16:39:36 +0100544 outBuff.size = compressedBufferSize;
545 outBuff.pos = 0;
546 inBuff.src = CNBuffer;
547 inBuff.size = CNBufferSize;
548 inBuff.pos = 0;
Yann Colletd6770f82017-09-28 02:14:48 -0700549 CHECK_Z( ZSTD_compressStream(zc, &outBuff, &inBuff) );
Nick Terrelle55da9e2019-03-13 14:05:18 -0700550 CHECK(inBuff.pos != inBuff.size, "Entire input should be consumed");
551 { size_t const r = ZSTD_endStream(zc, &outBuff);
552 CHECK(r != 0, "Error or some data not flushed (ret=%zu)", r);
553 }
554 { unsigned long long origSize = ZSTD_findDecompressedSize(outBuff.dst, outBuff.pos);
555 CHECK(origSize == ZSTD_CONTENTSIZE_UNKNOWN, "Unknown!");
556 CHECK((size_t)origSize != CNBufferSize, "Exact original size must be present (got %llu)", origSize);
557 }
Yann Colletededcfc2018-12-21 16:19:44 -0800558 DISPLAYLEVEL(3, "OK (%u bytes : %.2f%%)\n", (unsigned)cSize, (double)cSize/COMPRESSIBLE_NOISE_LENGTH*100);
Yann Collete795c8a2016-12-13 16:39:36 +0100559
560 /* wrong _srcSize compression test */
Nick Terrell48acadd2018-02-01 12:04:05 -0800561 DISPLAYLEVEL(3, "test%3i : too large srcSize : %u bytes : ", testNb++, COMPRESSIBLE_NOISE_LENGTH-1);
562 ZSTD_initCStream_srcSize(zc, 1, CNBufferSize+1);
Yann Colletd564faa2016-12-18 21:39:15 +0100563 outBuff.dst = (char*)(compressedBuffer);
Yann Collete795c8a2016-12-13 16:39:36 +0100564 outBuff.size = compressedBufferSize;
565 outBuff.pos = 0;
566 inBuff.src = CNBuffer;
567 inBuff.size = CNBufferSize;
568 inBuff.pos = 0;
Yann Colletd6770f82017-09-28 02:14:48 -0700569 CHECK_Z( ZSTD_compressStream(zc, &outBuff, &inBuff) );
Yann Collete795c8a2016-12-13 16:39:36 +0100570 if (inBuff.pos != inBuff.size) goto _output_error; /* entire input should be consumed */
571 { size_t const r = ZSTD_endStream(zc, &outBuff);
572 if (ZSTD_getErrorCode(r) != ZSTD_error_srcSize_wrong) goto _output_error; /* must fail : wrong srcSize */
Yann Collet736788f2017-01-19 12:12:50 -0800573 DISPLAYLEVEL(3, "OK (error detected : %s) \n", ZSTD_getErrorName(r)); }
Yann Collete795c8a2016-12-13 16:39:36 +0100574
Nick Terrell48acadd2018-02-01 12:04:05 -0800575 /* wrong _srcSize compression test */
576 DISPLAYLEVEL(3, "test%3i : too small srcSize : %u bytes : ", testNb++, COMPRESSIBLE_NOISE_LENGTH-1);
577 ZSTD_initCStream_srcSize(zc, 1, CNBufferSize-1);
578 outBuff.dst = (char*)(compressedBuffer);
579 outBuff.size = compressedBufferSize;
580 outBuff.pos = 0;
581 inBuff.src = CNBuffer;
582 inBuff.size = CNBufferSize;
583 inBuff.pos = 0;
584 { size_t const r = ZSTD_compressStream(zc, &outBuff, &inBuff);
585 if (ZSTD_getErrorCode(r) != ZSTD_error_srcSize_wrong) goto _output_error; /* must fail : wrong srcSize */
586 DISPLAYLEVEL(3, "OK (error detected : %s) \n", ZSTD_getErrorName(r));
587 }
588
Nick Terrell3c3f59e2018-04-12 16:02:03 -0700589 DISPLAYLEVEL(3, "test%3i : wrong srcSize !contentSizeFlag : %u bytes : ", testNb++, COMPRESSIBLE_NOISE_LENGTH-1);
590 { ZSTD_parameters params = ZSTD_getParams(1, CNBufferSize, 0);
591 params.fParams.contentSizeFlag = 0;
592 CHECK_Z(ZSTD_initCStream_advanced(zc, NULL, 0, params, CNBufferSize - MIN(CNBufferSize, 200 KB)));
593 outBuff.dst = (char*)compressedBuffer;
594 outBuff.size = compressedBufferSize;
595 outBuff.pos = 0;
596 inBuff.src = CNBuffer;
597 inBuff.size = CNBufferSize;
598 inBuff.pos = 0;
599 { size_t const r = ZSTD_compressStream(zc, &outBuff, &inBuff);
600 if (ZSTD_getErrorCode(r) != ZSTD_error_srcSize_wrong) goto _output_error; /* must fail : wrong srcSize */
601 DISPLAYLEVEL(3, "OK (error detected : %s) \n", ZSTD_getErrorName(r));
602 } }
603
Yann Collet12083a42016-09-06 15:01:51 +0200604 /* Complex context re-use scenario */
Yann Collet736788f2017-01-19 12:12:50 -0800605 DISPLAYLEVEL(3, "test%3i : context re-use : ", testNb++);
Yann Collet12083a42016-09-06 15:01:51 +0200606 ZSTD_freeCStream(zc);
Yann Colletbd88f632017-11-27 12:15:23 -0800607 zc = ZSTD_createCStream();
Yann Collet12083a42016-09-06 15:01:51 +0200608 if (zc==NULL) goto _output_error; /* memory allocation issue */
609 /* use 1 */
610 { size_t const inSize = 513;
Yann Collet0be6fd32017-05-08 16:08:01 -0700611 DISPLAYLEVEL(5, "use1 ");
Yann Collet12083a42016-09-06 15:01:51 +0200612 ZSTD_initCStream_advanced(zc, NULL, 0, ZSTD_getParams(19, inSize, 0), inSize); /* needs btopt + search3 to trigger hashLog3 */
613 inBuff.src = CNBuffer;
614 inBuff.size = inSize;
615 inBuff.pos = 0;
616 outBuff.dst = (char*)(compressedBuffer)+cSize;
617 outBuff.size = ZSTD_compressBound(inSize);
618 outBuff.pos = 0;
Yann Collet0be6fd32017-05-08 16:08:01 -0700619 DISPLAYLEVEL(5, "compress1 ");
Yann Colletd6770f82017-09-28 02:14:48 -0700620 CHECK_Z( ZSTD_compressStream(zc, &outBuff, &inBuff) );
Yann Collet12083a42016-09-06 15:01:51 +0200621 if (inBuff.pos != inBuff.size) goto _output_error; /* entire input should be consumed */
Yann Collet0be6fd32017-05-08 16:08:01 -0700622 DISPLAYLEVEL(5, "end1 ");
Yann Collet12083a42016-09-06 15:01:51 +0200623 { size_t const r = ZSTD_endStream(zc, &outBuff);
624 if (r != 0) goto _output_error; } /* error, or some data not flushed */
625 }
626 /* use 2 */
627 { size_t const inSize = 1025; /* will not continue, because tables auto-adjust and are therefore different size */
Yann Collet0be6fd32017-05-08 16:08:01 -0700628 DISPLAYLEVEL(5, "use2 ");
Yann Collet12083a42016-09-06 15:01:51 +0200629 ZSTD_initCStream_advanced(zc, NULL, 0, ZSTD_getParams(19, inSize, 0), inSize); /* needs btopt + search3 to trigger hashLog3 */
630 inBuff.src = CNBuffer;
631 inBuff.size = inSize;
632 inBuff.pos = 0;
633 outBuff.dst = (char*)(compressedBuffer)+cSize;
634 outBuff.size = ZSTD_compressBound(inSize);
635 outBuff.pos = 0;
Yann Collet0be6fd32017-05-08 16:08:01 -0700636 DISPLAYLEVEL(5, "compress2 ");
Yann Colletd6770f82017-09-28 02:14:48 -0700637 CHECK_Z( ZSTD_compressStream(zc, &outBuff, &inBuff) );
Yann Collet12083a42016-09-06 15:01:51 +0200638 if (inBuff.pos != inBuff.size) goto _output_error; /* entire input should be consumed */
Yann Collet0be6fd32017-05-08 16:08:01 -0700639 DISPLAYLEVEL(5, "end2 ");
Yann Collet12083a42016-09-06 15:01:51 +0200640 { size_t const r = ZSTD_endStream(zc, &outBuff);
641 if (r != 0) goto _output_error; } /* error, or some data not flushed */
642 }
Yann Collet736788f2017-01-19 12:12:50 -0800643 DISPLAYLEVEL(3, "OK \n");
Yann Collet12083a42016-09-06 15:01:51 +0200644
Nick Terrellf33de062020-04-27 18:10:45 -0700645 /* Decompression single pass with empty frame */
646 cSize = ZSTD_compress(compressedBuffer, compressedBufferSize, NULL, 0, 1);
647 CHECK_Z(cSize);
648 DISPLAYLEVEL(3, "test%3i : ZSTD_decompressStream() single pass on empty frame : ", testNb++);
649 { ZSTD_DCtx* dctx = ZSTD_createDCtx();
650 size_t const dctxSize = ZSTD_sizeof_DCtx(dctx);
651 CHECK_Z(ZSTD_DCtx_setParameter(dctx, ZSTD_d_stableOutBuffer, 1));
652
653 outBuff.dst = decodedBuffer;
654 outBuff.pos = 0;
655 outBuff.size = CNBufferSize;
656
657 inBuff.src = compressedBuffer;
658 inBuff.size = cSize;
659 inBuff.pos = 0;
660 { size_t const r = ZSTD_decompressStream(dctx, &outBuff, &inBuff);
661 CHECK_Z(r);
662 CHECK(r != 0, "Entire frame must be decompressed");
663 CHECK(outBuff.pos != 0, "Wrong size!");
664 CHECK(memcmp(CNBuffer, outBuff.dst, CNBufferSize) != 0, "Corruption!");
665 }
666 CHECK(dctxSize != ZSTD_sizeof_DCtx(dctx), "No buffers allocated");
667 ZSTD_freeDCtx(dctx);
668 }
669 DISPLAYLEVEL(3, "OK \n");
670
Nick Terrella4ff2172020-04-27 17:42:03 -0700671 /* Decompression with ZSTD_d_stableOutBuffer */
672 cSize = ZSTD_compress(compressedBuffer, compressedBufferSize, CNBuffer, CNBufferSize, 1);
673 CHECK_Z(cSize);
674 { ZSTD_DCtx* dctx = ZSTD_createDCtx();
675 size_t const dctxSize0 = ZSTD_sizeof_DCtx(dctx);
676 size_t dctxSize1;
677 CHECK_Z(ZSTD_DCtx_setParameter(dctx, ZSTD_d_stableOutBuffer, 1));
678
679 outBuff.dst = decodedBuffer;
680 outBuff.pos = 0;
681 outBuff.size = CNBufferSize;
682
683 DISPLAYLEVEL(3, "test%3i : ZSTD_decompressStream() single pass : ", testNb++);
684 inBuff.src = compressedBuffer;
685 inBuff.size = cSize;
686 inBuff.pos = 0;
687 { size_t const r = ZSTD_decompressStream(dctx, &outBuff, &inBuff);
688 CHECK_Z(r);
689 CHECK(r != 0, "Entire frame must be decompressed");
690 CHECK(outBuff.pos != CNBufferSize, "Wrong size!");
691 CHECK(memcmp(CNBuffer, outBuff.dst, CNBufferSize) != 0, "Corruption!");
692 }
693 CHECK(dctxSize0 != ZSTD_sizeof_DCtx(dctx), "No buffers allocated");
694 DISPLAYLEVEL(3, "OK \n");
695
696 DISPLAYLEVEL(3, "test%3i : ZSTD_decompressStream() stable out buffer : ", testNb++);
697 outBuff.pos = 0;
698 inBuff.pos = 0;
699 inBuff.size = 0;
700 while (inBuff.pos < cSize) {
701 inBuff.size += MIN(cSize - inBuff.pos, 1 + (FUZ_rand(&coreSeed) & 15));
702 CHECK_Z(ZSTD_decompressStream(dctx, &outBuff, &inBuff));
703 }
704 CHECK(outBuff.pos != CNBufferSize, "Wrong size!");
705 CHECK(memcmp(CNBuffer, outBuff.dst, CNBufferSize) != 0, "Corruption!");
706 dctxSize1 = ZSTD_sizeof_DCtx(dctx);
707 CHECK(!(dctxSize0 < dctxSize1), "Input buffer allocated");
708 DISPLAYLEVEL(3, "OK \n");
709
710 DISPLAYLEVEL(3, "test%3i : ZSTD_decompressStream() stable out buffer too small : ", testNb++);
711 ZSTD_DCtx_reset(dctx, ZSTD_reset_session_only);
712 CHECK_Z(ZSTD_DCtx_setParameter(dctx, ZSTD_d_stableOutBuffer, 1));
713 inBuff.src = compressedBuffer;
714 inBuff.size = cSize;
715 inBuff.pos = 0;
716 outBuff.pos = 0;
717 outBuff.size = CNBufferSize - 1;
718 { size_t const r = ZSTD_decompressStream(dctx, &outBuff, &inBuff);
719 CHECK(ZSTD_getErrorCode(r) != ZSTD_error_dstSize_tooSmall, "Must error but got %s", ZSTD_getErrorName(r));
720 }
721 DISPLAYLEVEL(3, "OK \n");
722
723 DISPLAYLEVEL(3, "test%3i : ZSTD_decompressStream() stable out buffer modified : ", testNb++);
724 ZSTD_DCtx_reset(dctx, ZSTD_reset_session_only);
725 CHECK_Z(ZSTD_DCtx_setParameter(dctx, ZSTD_d_stableOutBuffer, 1));
726 inBuff.src = compressedBuffer;
727 inBuff.size = cSize - 1;
728 inBuff.pos = 0;
729 outBuff.pos = 0;
730 outBuff.size = CNBufferSize;
731 CHECK_Z(ZSTD_decompressStream(dctx, &outBuff, &inBuff));
732 ++inBuff.size;
733 outBuff.pos = 0;
734 { size_t const r = ZSTD_decompressStream(dctx, &outBuff, &inBuff);
735 CHECK(ZSTD_getErrorCode(r) != ZSTD_error_dstBuffer_wrong, "Must error but got %s", ZSTD_getErrorName(r));
736 }
737 DISPLAYLEVEL(3, "OK \n");
738
739 DISPLAYLEVEL(3, "test%3i : ZSTD_decompressStream() buffered output : ", testNb++);
740 ZSTD_DCtx_reset(dctx, ZSTD_reset_session_only);
741 CHECK_Z(ZSTD_DCtx_setParameter(dctx, ZSTD_d_stableOutBuffer, 0));
742 outBuff.pos = 0;
743 inBuff.pos = 0;
744 inBuff.size = 0;
745 while (inBuff.pos < cSize) {
746 inBuff.size += MIN(cSize - inBuff.pos, 1 + (FUZ_rand(&coreSeed) & 15));
747 CHECK_Z(ZSTD_decompressStream(dctx, &outBuff, &inBuff));
748 }
749 CHECK(outBuff.pos != CNBufferSize, "Wrong size!");
750 CHECK(memcmp(CNBuffer, outBuff.dst, CNBufferSize) != 0, "Corruption!");
751 CHECK(!(dctxSize1 < ZSTD_sizeof_DCtx(dctx)), "Output buffer allocated");
752 DISPLAYLEVEL(3, "OK \n");
753
754 ZSTD_freeDCtx(dctx);
755 }
756
Nick Terrell2ebf6d52020-10-12 18:40:14 -0700757 /* Compression with ZSTD_c_stable{In,Out}Buffer */
758 { ZSTD_CCtx* cctx = ZSTD_createCCtx();
759 ZSTD_inBuffer in;
760 ZSTD_outBuffer out;
761 size_t cctxSize1;
762 size_t cctxSize2;
763 in.src = CNBuffer;
764 in.size = CNBufferSize;
765 out.dst = compressedBuffer;
766 out.size = compressedBufferSize;
767 CHECK_Z(ZSTD_CCtx_setParameter(cctx, ZSTD_c_checksumFlag, 1));
768 DISPLAYLEVEL(3, "test%3i : ZSTD_compress2() uses stable input and output : ", testNb++);
769 CHECK_Z(cSize = ZSTD_compress2(cctx, compressedBuffer, compressedBufferSize, CNBuffer, CNBufferSize));
770 CHECK(!(cSize < ZSTD_compressBound(CNBufferSize)), "cSize too large for test");
771 CHECK_Z(cSize = ZSTD_compress2(cctx, compressedBuffer, cSize + 4, CNBuffer, CNBufferSize));
772 CHECK_Z(cctxSize1 = ZSTD_sizeof_CCtx(cctx));
773 { ZSTD_CCtx* cctx2 = ZSTD_createCCtx();
774 in.pos = out.pos = 0;
775 CHECK_Z(ZSTD_compressStream2(cctx2, &out, &in, ZSTD_e_continue));
776 CHECK(!(ZSTD_compressStream2(cctx2, &out, &in, ZSTD_e_end) == 0), "Not finished");
777 CHECK_Z(cctxSize2 = ZSTD_sizeof_CCtx(cctx2));
778 ZSTD_freeCCtx(cctx2);
779 }
780 { ZSTD_CCtx* cctx3 = ZSTD_createCCtx();
781 ZSTD_parameters params = ZSTD_getParams(0, CNBufferSize, 0);
782 size_t cSize3;
783 params.fParams.checksumFlag = 1;
784 cSize3 = ZSTD_compress_advanced(cctx3, compressedBuffer, compressedBufferSize, CNBuffer, CNBufferSize, NULL, 0, params);
785 CHECK_Z(cSize3);
786 CHECK(!(cSize == cSize3), "Must be same compressed size");
787 CHECK(!(cctxSize1 == ZSTD_sizeof_CCtx(cctx3)), "Must be same CCtx size");
788 ZSTD_freeCCtx(cctx3);
789 }
790 CHECK(!(cctxSize1 < cctxSize2), "Stable buffers means less allocated size");
791 CHECK_Z(ZSTD_decompress(decodedBuffer, CNBufferSize, compressedBuffer, cSize));
792 DISPLAYLEVEL(3, "OK \n");
793
794 DISPLAYLEVEL(3, "test%3i : ZSTD_compress2() doesn't modify user parameters : ", testNb++);
795 {
796 int stableInBuffer;
797 int stableOutBuffer;
798 CHECK_Z(ZSTD_CCtx_getParameter(cctx, ZSTD_c_stableInBuffer, &stableInBuffer));
799 CHECK_Z(ZSTD_CCtx_getParameter(cctx, ZSTD_c_stableOutBuffer, &stableOutBuffer));
800 CHECK(!(stableInBuffer == 0), "Modified");
801 CHECK(!(stableOutBuffer == 0), "Modified");
802 CHECK_Z(ZSTD_CCtx_setParameter(cctx, ZSTD_c_stableInBuffer, 1));
803 CHECK_Z(ZSTD_CCtx_setParameter(cctx, ZSTD_c_stableOutBuffer, 1));
804 CHECK_Z(cSize = ZSTD_compress2(cctx, compressedBuffer, compressedBufferSize, CNBuffer, CNBufferSize));
805 CHECK_Z(ZSTD_CCtx_getParameter(cctx, ZSTD_c_stableInBuffer, &stableInBuffer));
806 CHECK_Z(ZSTD_CCtx_getParameter(cctx, ZSTD_c_stableOutBuffer, &stableOutBuffer));
807 CHECK(!(stableInBuffer == 1), "Modified");
808 CHECK(!(stableOutBuffer == 1), "Modified");
809 }
810 DISPLAYLEVEL(3, "OK \n");
811
812 DISPLAYLEVEL(3, "test%3i : ZSTD_compressStream2() with ZSTD_c_stableInBuffer and ZSTD_c_stableOutBuffer : ", testNb++);
813 CHECK_Z(ZSTD_CCtx_reset(cctx, ZSTD_reset_session_and_parameters));
814 CHECK_Z(ZSTD_CCtx_setParameter(cctx, ZSTD_c_checksumFlag, 1));
815 CHECK_Z(ZSTD_CCtx_setParameter(cctx, ZSTD_c_stableInBuffer, 1));
816 CHECK_Z(ZSTD_CCtx_setParameter(cctx, ZSTD_c_stableOutBuffer, 1));
817 in.pos = out.pos = 0;
818 CHECK(!(ZSTD_compressStream2(cctx, &out, &in, ZSTD_e_end) == 0), "Not finished");
819 CHECK_Z(ZSTD_decompress(decodedBuffer, CNBufferSize, compressedBuffer, cSize));
820 DISPLAYLEVEL(3, "OK \n");
821
822 DISPLAYLEVEL(3, "test%3i : ZSTD_compressStream2() ZSTD_c_stableInBuffer and ZSTD_c_stableOutBuffer allocated size : ", testNb++);
823 { size_t const cctxSize = ZSTD_sizeof_CCtx(cctx);
824 CHECK(!(cctxSize1 == cctxSize), "Must be the same size as single pass");
825 }
826 DISPLAYLEVEL(3, "OK \n");
827
828 DISPLAYLEVEL(3, "test%3i : ZSTD_compressStream2() with ZSTD_c_stableInBuffer only : ", testNb++);
829 CHECK_Z(ZSTD_CCtx_reset(cctx, ZSTD_reset_session_and_parameters));
830 CHECK_Z(ZSTD_CCtx_setParameter(cctx, ZSTD_c_checksumFlag, 1));
831 CHECK_Z(ZSTD_CCtx_setParameter(cctx, ZSTD_c_stableInBuffer, 1));
832 in.pos = out.pos = 0;
833 out.size = cSize / 4;
834 for (;;) {
835 size_t const ret = ZSTD_compressStream2(cctx, &out, &in, ZSTD_e_end);
836 CHECK_Z(ret);
837 if (ret == 0)
838 break;
839 out.size = MIN(out.size + cSize / 4, compressedBufferSize);
840 }
841 CHECK_Z(ZSTD_decompress(decodedBuffer, CNBufferSize, compressedBuffer, cSize));
842 DISPLAYLEVEL(3, "OK \n");
843
844 DISPLAYLEVEL(3, "test%3i : ZSTD_compressStream2() ZSTD_c_stableInBuffer modify buffer : ", testNb++);
845 in.pos = out.pos = 0;
846 out.size = cSize / 4;
847 CHECK_Z(ZSTD_compressStream2(cctx, &out, &in, ZSTD_e_end));
848 in.src = (char const*)in.src + in.pos;
849 in.size -= in.pos;
850 in.pos = 0;
851 { size_t const ret = ZSTD_compressStream2(cctx, &out, &in, ZSTD_e_end);
852 CHECK(!ZSTD_isError(ret), "Must error");
853 CHECK(!(ZSTD_getErrorCode(ret) == ZSTD_error_srcBuffer_wrong), "Must be this error");
854 }
855 DISPLAYLEVEL(3, "OK \n");
856
857 DISPLAYLEVEL(3, "test%3i : ZSTD_compressStream2() ZSTD_c_stableInBuffer with continue and flush : ", testNb++);
858 in.src = CNBuffer;
859 in.size = CNBufferSize;
860 in.pos = 0;
861 out.pos = 0;
862 out.size = compressedBufferSize;
863 CHECK_Z(ZSTD_CCtx_reset(cctx, ZSTD_reset_session_only));
864 { size_t const ret = ZSTD_compressStream2(cctx, &out, &in, ZSTD_e_continue);
865 CHECK(!ZSTD_isError(ret), "Must error");
866 CHECK(!(ZSTD_getErrorCode(ret) == ZSTD_error_srcBuffer_wrong), "Must be this error");
867 }
868 CHECK_Z(ZSTD_CCtx_reset(cctx, ZSTD_reset_session_only));
869 { size_t const ret = ZSTD_compressStream2(cctx, &out, &in, ZSTD_e_flush);
870 CHECK(!ZSTD_isError(ret), "Must error");
871 CHECK(!(ZSTD_getErrorCode(ret) == ZSTD_error_srcBuffer_wrong), "Must be this error");
872 }
873 DISPLAYLEVEL(3, "OK \n");
874
875 DISPLAYLEVEL(3, "test%3i : ZSTD_compressStream2() ZSTD_c_stableInBuffer allocated size : ", testNb++);
876 { size_t const cctxSize = ZSTD_sizeof_CCtx(cctx);
877 CHECK(!(cctxSize1 < cctxSize), "Must be bigger than single-pass");
878 CHECK(!(cctxSize < cctxSize2), "Must be smaller than streaming");
879 cctxSize1 = cctxSize;
880 }
881 DISPLAYLEVEL(3, "OK \n");
882
883 DISPLAYLEVEL(3, "test%3i : ZSTD_compressStream2() with ZSTD_c_stableOutBuffer only : ", testNb++);
884 CHECK_Z(ZSTD_CCtx_reset(cctx, ZSTD_reset_session_and_parameters));
885 CHECK_Z(ZSTD_CCtx_setParameter(cctx, ZSTD_c_checksumFlag, 1));
886 CHECK_Z(ZSTD_CCtx_setParameter(cctx, ZSTD_c_stableOutBuffer, 1));
887 in.pos = out.pos = 0;
888 in.size = MIN(CNBufferSize, 10);
889 CHECK_Z(ZSTD_compressStream2(cctx, &out, &in, ZSTD_e_flush));
890 in.pos = 0;
891 in.size = CNBufferSize - in.size;
892 CHECK(!(ZSTD_compressStream2(cctx, &out, &in, ZSTD_e_end) == 0), "Not finished");
893 CHECK_Z(ZSTD_decompress(decodedBuffer, CNBufferSize, compressedBuffer, cSize));
894 DISPLAYLEVEL(3, "OK \n");
895
896 DISPLAYLEVEL(3, "test%3i : ZSTD_compressStream2() ZSTD_c_stableOutBuffer modify buffer : ", testNb++);
897 in.pos = out.pos = 0;
898 in.size = CNBufferSize;
899 CHECK_Z(ZSTD_compressStream2(cctx, &out, &in, ZSTD_e_continue));
900 in.pos = out.pos = 0;
901 { size_t const ret = ZSTD_compressStream2(cctx, &out, &in, ZSTD_e_continue);
902 CHECK(!ZSTD_isError(ret), "Must have errored");
903 CHECK(!(ZSTD_getErrorCode(ret) == ZSTD_error_dstBuffer_wrong), "Must be this error");
904 }
905 DISPLAYLEVEL(3, "OK \n");
906
907 DISPLAYLEVEL(3, "test%3i : ZSTD_compressStream2() ZSTD_c_stableOutBuffer allocated size : ", testNb++);
908 { size_t const cctxSize = ZSTD_sizeof_CCtx(cctx);
909 CHECK(!(cctxSize1 < cctxSize), "Must be bigger than single-pass and stableInBuffer");
910 CHECK(!(cctxSize < cctxSize2), "Must be smaller than streaming");
911 }
912 DISPLAYLEVEL(3, "OK \n");
913
914 ZSTD_freeCCtx(cctx);
915 }
916
Yann Collet95162342016-10-25 16:19:52 -0700917 /* CDict scenario */
Yann Collet736788f2017-01-19 12:12:50 -0800918 DISPLAYLEVEL(3, "test%3i : digested dictionary : ", testNb++);
Yann Collet2e427422017-06-27 17:09:12 -0700919 { ZSTD_CDict* const cdict = ZSTD_createCDict(dictionary.start, dictionary.filled, 1 /*byRef*/ );
Yann Collet95162342016-10-25 16:19:52 -0700920 size_t const initError = ZSTD_initCStream_usingCDict(zc, cdict);
Yann Colletededcfc2018-12-21 16:19:44 -0800921 DISPLAYLEVEL(5, "ZSTD_initCStream_usingCDict result : %u ", (unsigned)initError);
Yann Collet95162342016-10-25 16:19:52 -0700922 if (ZSTD_isError(initError)) goto _output_error;
Yann Collet95162342016-10-25 16:19:52 -0700923 outBuff.dst = compressedBuffer;
924 outBuff.size = compressedBufferSize;
925 outBuff.pos = 0;
926 inBuff.src = CNBuffer;
927 inBuff.size = CNBufferSize;
928 inBuff.pos = 0;
Yann Collet15768ca2017-11-16 15:02:28 -0800929 DISPLAYLEVEL(5, "- starting ZSTD_compressStream ");
Yann Colletd6770f82017-09-28 02:14:48 -0700930 CHECK_Z( ZSTD_compressStream(zc, &outBuff, &inBuff) );
Yann Collet95162342016-10-25 16:19:52 -0700931 if (inBuff.pos != inBuff.size) goto _output_error; /* entire input should be consumed */
Yann Collet15768ca2017-11-16 15:02:28 -0800932 { size_t const r = ZSTD_endStream(zc, &outBuff);
Yann Colletededcfc2018-12-21 16:19:44 -0800933 DISPLAYLEVEL(5, "- ZSTD_endStream result : %u ", (unsigned)r);
Yann Collet15768ca2017-11-16 15:02:28 -0800934 if (r != 0) goto _output_error; /* error, or some data not flushed */
935 }
Yann Collet95162342016-10-25 16:19:52 -0700936 cSize = outBuff.pos;
937 ZSTD_freeCDict(cdict);
Yann Colletededcfc2018-12-21 16:19:44 -0800938 DISPLAYLEVEL(3, "OK (%u bytes : %.2f%%)\n", (unsigned)cSize, (double)cSize/CNBufferSize*100);
Yann Collet95162342016-10-25 16:19:52 -0700939 }
940
Yann Collet736788f2017-01-19 12:12:50 -0800941 DISPLAYLEVEL(3, "test%3i : check CStream size : ", testNb++);
Yann Collet12083a42016-09-06 15:01:51 +0200942 { size_t const s = ZSTD_sizeof_CStream(zc);
943 if (ZSTD_isError(s)) goto _output_error;
Yann Colletededcfc2018-12-21 16:19:44 -0800944 DISPLAYLEVEL(3, "OK (%u bytes) \n", (unsigned)s);
Yann Collet12083a42016-09-06 15:01:51 +0200945 }
946
Yann Collet33fce032017-01-16 19:46:22 -0800947 DISPLAYLEVEL(4, "test%3i : check Dictionary ID : ", testNb++);
948 { unsigned const dID = ZSTD_getDictID_fromFrame(compressedBuffer, cSize);
949 if (dID != dictID) goto _output_error;
950 DISPLAYLEVEL(4, "OK (%u) \n", dID);
951 }
952
Yann Collet335ad5d2016-10-25 17:47:02 -0700953 /* DDict scenario */
Yann Colletededcfc2018-12-21 16:19:44 -0800954 DISPLAYLEVEL(3, "test%3i : decompress %u bytes with digested dictionary : ", testNb++, (unsigned)CNBufferSize);
Yann Collet33fce032017-01-16 19:46:22 -0800955 { ZSTD_DDict* const ddict = ZSTD_createDDict(dictionary.start, dictionary.filled);
Yann Collet335ad5d2016-10-25 17:47:02 -0700956 size_t const initError = ZSTD_initDStream_usingDDict(zd, ddict);
957 if (ZSTD_isError(initError)) goto _output_error;
Yann Collet8a104fd2017-12-12 12:51:49 -0800958 outBuff.dst = decodedBuffer;
959 outBuff.size = CNBufferSize;
960 outBuff.pos = 0;
Yann Collet03832b72017-12-12 14:01:54 -0800961 inBuff.src = compressedBuffer;
962 inBuff.size = cSize;
963 inBuff.pos = 0;
Yann Collet335ad5d2016-10-25 17:47:02 -0700964 { size_t const r = ZSTD_decompressStream(zd, &outBuff, &inBuff);
965 if (r != 0) goto _output_error; } /* should reach end of frame == 0; otherwise, some data left, or an error */
966 if (outBuff.pos != CNBufferSize) goto _output_error; /* should regenerate the same amount */
967 if (inBuff.pos != inBuff.size) goto _output_error; /* should have read the entire frame */
968 ZSTD_freeDDict(ddict);
Yann Collet736788f2017-01-19 12:12:50 -0800969 DISPLAYLEVEL(3, "OK \n");
Yann Collet335ad5d2016-10-25 17:47:02 -0700970 }
971
Yann Collet17e482e2016-08-23 16:58:10 +0200972 /* Memory restriction */
Yann Collet736788f2017-01-19 12:12:50 -0800973 DISPLAYLEVEL(3, "test%3i : maxWindowSize < frame requirement : ", testNb++);
Yann Collet30ab64e2017-05-10 11:30:19 -0700974 ZSTD_initDStream_usingDict(zd, CNBuffer, dictSize);
Yann Collet3e042d52018-12-04 17:30:58 -0800975 CHECK_Z( ZSTD_DCtx_setParameter(zd, ZSTD_d_windowLogMax, 10) ); /* too small limit */
Yann Collet8a104fd2017-12-12 12:51:49 -0800976 outBuff.dst = decodedBuffer;
977 outBuff.size = CNBufferSize;
978 outBuff.pos = 0;
Yann Collet03832b72017-12-12 14:01:54 -0800979 inBuff.src = compressedBuffer;
980 inBuff.size = cSize;
981 inBuff.pos = 0;
Yann Collet17e482e2016-08-23 16:58:10 +0200982 { size_t const r = ZSTD_decompressStream(zd, &outBuff, &inBuff);
983 if (!ZSTD_isError(r)) goto _output_error; /* must fail : frame requires > 100 bytes */
Yann Collet736788f2017-01-19 12:12:50 -0800984 DISPLAYLEVEL(3, "OK (%s)\n", ZSTD_getErrorName(r)); }
Yann Collet5c686392018-11-15 16:12:39 -0800985 ZSTD_DCtx_reset(zd, ZSTD_reset_session_and_parameters); /* leave zd in good shape for next tests */
Yann Collet17e482e2016-08-23 16:58:10 +0200986
Nick Terrellab3346a2018-01-30 13:30:30 -0800987 DISPLAYLEVEL(3, "test%3i : dictionary source size and level : ", testNb++);
988 { ZSTD_DCtx* const dctx = ZSTD_createDCtx();
Yann Collet6cda8c92018-03-20 16:16:13 -0700989 int const maxLevel = 16; /* first level with zstd_opt */
Nick Terrellab3346a2018-01-30 13:30:30 -0800990 int level;
Yann Collet2af41592018-03-20 15:59:25 -0700991 assert(maxLevel < ZSTD_maxCLevel());
992 CHECK_Z( ZSTD_DCtx_loadDictionary_byReference(dctx, dictionary.start, dictionary.filled) );
Nick Terrellab3346a2018-01-30 13:30:30 -0800993 for (level = 1; level <= maxLevel; ++level) {
994 ZSTD_CDict* const cdict = ZSTD_createCDict(dictionary.start, dictionary.filled, level);
Yann Collet2af41592018-03-20 15:59:25 -0700995 size_t const maxSize = MIN(1 MB, CNBufferSize);
996 size_t size;
Nick Terrellab3346a2018-01-30 13:30:30 -0800997 for (size = 512; size <= maxSize; size <<= 1) {
Yann Collet2af41592018-03-20 15:59:25 -0700998 U64 const crcOrig = XXH64(CNBuffer, size, 0);
Nick Terrellab3346a2018-01-30 13:30:30 -0800999 ZSTD_CCtx* const cctx = ZSTD_createCCtx();
Nick Terrellca778222018-04-25 16:32:29 -07001000 ZSTD_parameters savedParams;
1001 getCCtxParams(cctx, &savedParams);
Nick Terrellab3346a2018-01-30 13:30:30 -08001002 outBuff.dst = compressedBuffer;
1003 outBuff.size = compressedBufferSize;
1004 outBuff.pos = 0;
1005 inBuff.src = CNBuffer;
1006 inBuff.size = size;
1007 inBuff.pos = 0;
1008 CHECK_Z(ZSTD_CCtx_refCDict(cctx, cdict));
Yann Colletd8e215c2018-11-30 11:16:26 -08001009 CHECK_Z(ZSTD_compressStream2(cctx, &outBuff, &inBuff, ZSTD_e_end));
Nick Terrellca778222018-04-25 16:32:29 -07001010 CHECK(badParameters(cctx, savedParams), "Bad CCtx params");
Nick Terrellab3346a2018-01-30 13:30:30 -08001011 if (inBuff.pos != inBuff.size) goto _output_error;
Yann Collet2af41592018-03-20 15:59:25 -07001012 { ZSTD_outBuffer decOut = {decodedBuffer, size, 0};
1013 ZSTD_inBuffer decIn = {outBuff.dst, outBuff.pos, 0};
Yann Collet34e146f2018-12-04 10:28:36 -08001014 CHECK_Z( ZSTD_decompressStream(dctx, &decOut, &decIn) );
Yann Collet2af41592018-03-20 15:59:25 -07001015 if (decIn.pos != decIn.size) goto _output_error;
1016 if (decOut.pos != size) goto _output_error;
1017 { U64 const crcDec = XXH64(decOut.dst, decOut.pos, 0);
1018 if (crcDec != crcOrig) goto _output_error;
1019 } }
Nick Terrellab3346a2018-01-30 13:30:30 -08001020 ZSTD_freeCCtx(cctx);
1021 }
1022 ZSTD_freeCDict(cdict);
1023 }
Nick Terrellab3346a2018-01-30 13:30:30 -08001024 ZSTD_freeDCtx(dctx);
1025 }
1026 DISPLAYLEVEL(3, "OK\n");
1027
Nick Terrell50b9c412019-04-10 12:34:21 -07001028 ZSTD_CCtx_reset(zc, ZSTD_reset_session_and_parameters);
1029 CHECK_Z( ZSTD_CCtx_loadDictionary(zc, dictionary.start, dictionary.filled) );
1030 cSize = ZSTD_compress2(zc, compressedBuffer, compressedBufferSize, CNBuffer, MIN(CNBufferSize, 100 KB));
1031 CHECK_Z(cSize);
1032 DISPLAYLEVEL(3, "test%3i : ZSTD_decompressStream() with dictionary : ", testNb++);
1033 {
1034 ZSTD_DCtx* dctx = ZSTD_createDCtx();
1035 /* We should fail to decompress without a dictionary. */
1036 ZSTD_DCtx_reset(dctx, ZSTD_reset_session_and_parameters);
1037 { ZSTD_outBuffer out = {decodedBuffer, decodedBufferSize, 0};
1038 ZSTD_inBuffer in = {compressedBuffer, cSize, 0};
1039 size_t const ret = ZSTD_decompressStream(dctx, &out, &in);
1040 if (!ZSTD_isError(ret)) goto _output_error;
1041 }
1042 /* We should succeed to decompress with the dictionary. */
1043 ZSTD_DCtx_reset(dctx, ZSTD_reset_session_and_parameters);
1044 CHECK_Z( ZSTD_DCtx_loadDictionary(dctx, dictionary.start, dictionary.filled) );
1045 { ZSTD_outBuffer out = {decodedBuffer, decodedBufferSize, 0};
1046 ZSTD_inBuffer in = {compressedBuffer, cSize, 0};
1047 if (ZSTD_decompressStream(dctx, &out, &in) != 0) goto _output_error;
1048 if (in.pos != in.size) goto _output_error;
1049 }
1050 /* The dictionary should presist across calls. */
1051 { ZSTD_outBuffer out = {decodedBuffer, decodedBufferSize, 0};
1052 ZSTD_inBuffer in = {compressedBuffer, cSize, 0};
1053 if (ZSTD_decompressStream(dctx, &out, &in) != 0) goto _output_error;
1054 if (in.pos != in.size) goto _output_error;
1055 }
1056 /* The dictionary should not be cleared by ZSTD_reset_session_only. */
1057 ZSTD_DCtx_reset(dctx, ZSTD_reset_session_only);
1058 { ZSTD_outBuffer out = {decodedBuffer, decodedBufferSize, 0};
1059 ZSTD_inBuffer in = {compressedBuffer, cSize, 0};
1060 if (ZSTD_decompressStream(dctx, &out, &in) != 0) goto _output_error;
1061 if (in.pos != in.size) goto _output_error;
1062 }
1063 /* When we reset the context the dictionary is cleared. */
1064 ZSTD_DCtx_reset(dctx, ZSTD_reset_session_and_parameters);
1065 { ZSTD_outBuffer out = {decodedBuffer, decodedBufferSize, 0};
1066 ZSTD_inBuffer in = {compressedBuffer, cSize, 0};
1067 size_t const ret = ZSTD_decompressStream(dctx, &out, &in);
1068 if (!ZSTD_isError(ret)) goto _output_error;
1069 }
1070 ZSTD_freeDCtx(dctx);
1071 }
1072 DISPLAYLEVEL(3, "OK \n");
1073
Josh Sorefa880ca22019-04-12 14:18:11 -04001074 DISPLAYLEVEL(3, "test%3i : ZSTD_resetDStream() with dictionary : ", testNb++);
Nick Terrell50b9c412019-04-10 12:34:21 -07001075 {
1076 ZSTD_DCtx* dctx = ZSTD_createDCtx();
1077 /* We should succeed to decompress with the dictionary. */
1078 ZSTD_resetDStream(dctx);
1079 CHECK_Z( ZSTD_DCtx_loadDictionary(dctx, dictionary.start, dictionary.filled) );
1080 { ZSTD_outBuffer out = {decodedBuffer, decodedBufferSize, 0};
1081 ZSTD_inBuffer in = {compressedBuffer, cSize, 0};
1082 if (ZSTD_decompressStream(dctx, &out, &in) != 0) goto _output_error;
1083 if (in.pos != in.size) goto _output_error;
1084 }
1085 /* The dictionary should not be cleared by ZSTD_resetDStream(). */
1086 ZSTD_resetDStream(dctx);
1087 { ZSTD_outBuffer out = {decodedBuffer, decodedBufferSize, 0};
1088 ZSTD_inBuffer in = {compressedBuffer, cSize, 0};
1089 if (ZSTD_decompressStream(dctx, &out, &in) != 0) goto _output_error;
1090 if (in.pos != in.size) goto _output_error;
1091 }
1092 /* The dictionary should be cleared by ZSTD_initDStream(). */
1093 CHECK_Z( ZSTD_initDStream(dctx) );
1094 { ZSTD_outBuffer out = {decodedBuffer, decodedBufferSize, 0};
1095 ZSTD_inBuffer in = {compressedBuffer, cSize, 0};
1096 size_t const ret = ZSTD_decompressStream(dctx, &out, &in);
1097 if (!ZSTD_isError(ret)) goto _output_error;
1098 }
1099 ZSTD_freeDCtx(dctx);
1100 }
1101 DISPLAYLEVEL(3, "OK \n");
1102
1103 DISPLAYLEVEL(3, "test%3i : ZSTD_decompressStream() with ddict : ", testNb++);
1104 {
1105 ZSTD_DCtx* dctx = ZSTD_createDCtx();
1106 ZSTD_DDict* ddict = ZSTD_createDDict(dictionary.start, dictionary.filled);
1107 /* We should succeed to decompress with the ddict. */
1108 ZSTD_DCtx_reset(dctx, ZSTD_reset_session_and_parameters);
1109 CHECK_Z( ZSTD_DCtx_refDDict(dctx, ddict) );
1110 { ZSTD_outBuffer out = {decodedBuffer, decodedBufferSize, 0};
1111 ZSTD_inBuffer in = {compressedBuffer, cSize, 0};
1112 if (ZSTD_decompressStream(dctx, &out, &in) != 0) goto _output_error;
1113 if (in.pos != in.size) goto _output_error;
1114 }
1115 /* The ddict should presist across calls. */
1116 { ZSTD_outBuffer out = {decodedBuffer, decodedBufferSize, 0};
1117 ZSTD_inBuffer in = {compressedBuffer, cSize, 0};
1118 if (ZSTD_decompressStream(dctx, &out, &in) != 0) goto _output_error;
1119 if (in.pos != in.size) goto _output_error;
1120 }
1121 /* When we reset the context the ddict is cleared. */
1122 ZSTD_DCtx_reset(dctx, ZSTD_reset_session_and_parameters);
1123 { ZSTD_outBuffer out = {decodedBuffer, decodedBufferSize, 0};
1124 ZSTD_inBuffer in = {compressedBuffer, cSize, 0};
1125 size_t const ret = ZSTD_decompressStream(dctx, &out, &in);
1126 if (!ZSTD_isError(ret)) goto _output_error;
1127 }
1128 ZSTD_freeDCtx(dctx);
1129 ZSTD_freeDDict(ddict);
1130 }
1131 DISPLAYLEVEL(3, "OK \n");
1132
1133 DISPLAYLEVEL(3, "test%3i : ZSTD_decompressDCtx() with prefix : ", testNb++);
1134 {
1135 ZSTD_DCtx* dctx = ZSTD_createDCtx();
1136 /* We should succeed to decompress with the prefix. */
1137 ZSTD_DCtx_reset(dctx, ZSTD_reset_session_and_parameters);
1138 CHECK_Z( ZSTD_DCtx_refPrefix_advanced(dctx, dictionary.start, dictionary.filled, ZSTD_dct_auto) );
1139 { ZSTD_outBuffer out = {decodedBuffer, decodedBufferSize, 0};
1140 ZSTD_inBuffer in = {compressedBuffer, cSize, 0};
1141 if (ZSTD_decompressStream(dctx, &out, &in) != 0) goto _output_error;
1142 if (in.pos != in.size) goto _output_error;
1143 }
1144 /* The prefix should be cleared after the first compression. */
1145 { ZSTD_outBuffer out = {decodedBuffer, decodedBufferSize, 0};
1146 ZSTD_inBuffer in = {compressedBuffer, cSize, 0};
1147 size_t const ret = ZSTD_decompressStream(dctx, &out, &in);
1148 if (!ZSTD_isError(ret)) goto _output_error;
1149 }
1150 ZSTD_freeDCtx(dctx);
1151 }
1152 DISPLAYLEVEL(3, "OK \n");
1153
1154 DISPLAYLEVEL(3, "test%3i : ZSTD_initDStream*() with dictionary : ", testNb++);
1155 {
1156 ZSTD_DCtx* dctx = ZSTD_createDCtx();
1157 ZSTD_DDict* ddict = ZSTD_createDDict(dictionary.start, dictionary.filled);
1158 size_t ret;
1159 /* We should succeed to decompress with the dictionary. */
1160 CHECK_Z( ZSTD_initDStream_usingDict(dctx, dictionary.start, dictionary.filled) );
1161 CHECK_Z( ZSTD_decompressDCtx(dctx, decodedBuffer, decodedBufferSize, compressedBuffer, cSize) );
1162 /* The dictionary should presist across calls. */
1163 CHECK_Z( ZSTD_decompressDCtx(dctx, decodedBuffer, decodedBufferSize, compressedBuffer, cSize) );
1164 /* We should succeed to decompress with the ddict. */
1165 CHECK_Z( ZSTD_initDStream_usingDDict(dctx, ddict) );
1166 CHECK_Z( ZSTD_decompressDCtx(dctx, decodedBuffer, decodedBufferSize, compressedBuffer, cSize) );
1167 /* The ddict should presist across calls. */
1168 CHECK_Z( ZSTD_decompressDCtx(dctx, decodedBuffer, decodedBufferSize, compressedBuffer, cSize) );
1169 /* When we reset the context the ddict is cleared. */
1170 CHECK_Z( ZSTD_initDStream(dctx) );
1171 ret = ZSTD_decompressDCtx(dctx, decodedBuffer, decodedBufferSize, compressedBuffer, cSize);
1172 if (!ZSTD_isError(ret)) goto _output_error;
1173 ZSTD_freeDCtx(dctx);
1174 ZSTD_freeDDict(ddict);
1175 }
1176 DISPLAYLEVEL(3, "OK \n");
1177
Yann Collet7d283cd2017-04-27 14:48:34 -07001178 DISPLAYLEVEL(3, "test%3i : ZSTD_initCStream_usingCDict_advanced with masked dictID : ", testNb++);
1179 { ZSTD_compressionParameters const cParams = ZSTD_getCParams(1, CNBufferSize, dictionary.filled);
1180 ZSTD_frameParameters const fParams = { 1 /* contentSize */, 1 /* checksum */, 1 /* noDictID */};
Yann Collet6873fec2018-03-20 15:13:14 -07001181 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 -07001182 size_t const initError = ZSTD_initCStream_usingCDict_advanced(zc, cdict, fParams, CNBufferSize);
Yann Collet7d283cd2017-04-27 14:48:34 -07001183 if (ZSTD_isError(initError)) goto _output_error;
Nick Terrell62ecad32017-04-03 20:56:39 -07001184 outBuff.dst = compressedBuffer;
1185 outBuff.size = compressedBufferSize;
1186 outBuff.pos = 0;
1187 inBuff.src = CNBuffer;
1188 inBuff.size = CNBufferSize;
1189 inBuff.pos = 0;
Yann Colletd6770f82017-09-28 02:14:48 -07001190 CHECK_Z( ZSTD_compressStream(zc, &outBuff, &inBuff) );
Yann Collet8c910d22017-06-03 01:15:02 -07001191 if (inBuff.pos != inBuff.size) goto _output_error; /* entire input should be consumed */
Nick Terrell62ecad32017-04-03 20:56:39 -07001192 { size_t const r = ZSTD_endStream(zc, &outBuff);
1193 if (r != 0) goto _output_error; } /* error, or some data not flushed */
1194 cSize = outBuff.pos;
1195 ZSTD_freeCDict(cdict);
Yann Colletededcfc2018-12-21 16:19:44 -08001196 DISPLAYLEVEL(3, "OK (%u bytes : %.2f%%)\n", (unsigned)cSize, (double)cSize/CNBufferSize*100);
Yann Collet4ee6b152017-04-11 11:59:44 -07001197 }
Nick Terrell62ecad32017-04-03 20:56:39 -07001198
Yann Colleta92cbb72017-04-27 15:08:56 -07001199 DISPLAYLEVEL(3, "test%3i : try retrieving dictID from frame : ", testNb++);
1200 { U32 const did = ZSTD_getDictID_fromFrame(compressedBuffer, cSize);
1201 if (did != 0) goto _output_error;
1202 }
1203 DISPLAYLEVEL(3, "OK (not detected) \n");
1204
Yann Collet4ee6b152017-04-11 11:59:44 -07001205 DISPLAYLEVEL(3, "test%3i : decompress without dictionary : ", testNb++);
1206 { size_t const r = ZSTD_decompress(decodedBuffer, CNBufferSize, compressedBuffer, cSize);
1207 if (!ZSTD_isError(r)) goto _output_error; /* must fail : dictionary not used */
1208 DISPLAYLEVEL(3, "OK (%s)\n", ZSTD_getErrorName(r));
Nick Terrell62ecad32017-04-03 20:56:39 -07001209 }
1210
Yann Collet62f7efc2017-06-28 16:25:13 -07001211 DISPLAYLEVEL(3, "test%3i : compress with ZSTD_CCtx_refPrefix : ", testNb++);
Yann Colletd6770f82017-09-28 02:14:48 -07001212 CHECK_Z( ZSTD_CCtx_refPrefix(zc, dictionary.start, dictionary.filled) );
Yann Collet62f7efc2017-06-28 16:25:13 -07001213 outBuff.dst = compressedBuffer;
1214 outBuff.size = compressedBufferSize;
1215 outBuff.pos = 0;
1216 inBuff.src = CNBuffer;
1217 inBuff.size = CNBufferSize;
1218 inBuff.pos = 0;
Yann Colletd8e215c2018-11-30 11:16:26 -08001219 CHECK_Z( ZSTD_compressStream2(zc, &outBuff, &inBuff, ZSTD_e_end) );
Yann Collet62f7efc2017-06-28 16:25:13 -07001220 if (inBuff.pos != inBuff.size) goto _output_error; /* entire input should be consumed */
1221 cSize = outBuff.pos;
Yann Colletededcfc2018-12-21 16:19:44 -08001222 DISPLAYLEVEL(3, "OK (%u bytes : %.2f%%)\n", (unsigned)cSize, (double)cSize/CNBufferSize*100);
Yann Collet62f7efc2017-06-28 16:25:13 -07001223
Yann Collet6cda8c92018-03-20 16:16:13 -07001224 DISPLAYLEVEL(3, "test%3i : decompress with ZSTD_DCtx_refPrefix : ", testNb++);
1225 CHECK_Z( ZSTD_DCtx_refPrefix(zd, dictionary.start, dictionary.filled) );
1226 outBuff.dst = decodedBuffer;
1227 outBuff.size = CNBufferSize;
1228 outBuff.pos = 0;
1229 inBuff.src = compressedBuffer;
1230 inBuff.size = cSize;
1231 inBuff.pos = 0;
Yann Collet34e146f2018-12-04 10:28:36 -08001232 CHECK_Z( ZSTD_decompressStream(zd, &outBuff, &inBuff) );
Yann Collet6cda8c92018-03-20 16:16:13 -07001233 if (inBuff.pos != inBuff.size) goto _output_error; /* entire input should be consumed */
1234 if (outBuff.pos != CNBufferSize) goto _output_error; /* must regenerate whole input */
1235 DISPLAYLEVEL(3, "OK \n");
Yann Collet62f7efc2017-06-28 16:25:13 -07001236
1237 DISPLAYLEVEL(3, "test%3i : decompress without dictionary (should fail): ", testNb++);
1238 { size_t const r = ZSTD_decompress(decodedBuffer, CNBufferSize, compressedBuffer, cSize);
1239 if (!ZSTD_isError(r)) goto _output_error; /* must fail : dictionary not used */
1240 DISPLAYLEVEL(3, "OK (%s)\n", ZSTD_getErrorName(r));
1241 }
1242
Yann Colletd8e215c2018-11-30 11:16:26 -08001243 DISPLAYLEVEL(3, "test%3i : compress again with ZSTD_compressStream2 : ", testNb++);
Yann Collet62f7efc2017-06-28 16:25:13 -07001244 outBuff.dst = compressedBuffer;
1245 outBuff.size = compressedBufferSize;
1246 outBuff.pos = 0;
1247 inBuff.src = CNBuffer;
1248 inBuff.size = CNBufferSize;
1249 inBuff.pos = 0;
Yann Colletd8e215c2018-11-30 11:16:26 -08001250 CHECK_Z( ZSTD_compressStream2(zc, &outBuff, &inBuff, ZSTD_e_end) );
Yann Collet62f7efc2017-06-28 16:25:13 -07001251 if (inBuff.pos != inBuff.size) goto _output_error; /* entire input should be consumed */
1252 cSize = outBuff.pos;
Yann Colletededcfc2018-12-21 16:19:44 -08001253 DISPLAYLEVEL(3, "OK (%u bytes : %.2f%%)\n", (unsigned)cSize, (double)cSize/CNBufferSize*100);
Yann Collet62f7efc2017-06-28 16:25:13 -07001254
1255 DISPLAYLEVEL(3, "test%3i : decompress without dictionary (should work): ", testNb++);
Yann Colletd6770f82017-09-28 02:14:48 -07001256 CHECK_Z( ZSTD_decompress(decodedBuffer, CNBufferSize, compressedBuffer, cSize) );
1257 DISPLAYLEVEL(3, "OK \n");
Yann Collet62f7efc2017-06-28 16:25:13 -07001258
Yann Collet0bb381d2017-04-18 15:08:52 -07001259 /* Empty srcSize */
1260 DISPLAYLEVEL(3, "test%3i : ZSTD_initCStream_advanced with pledgedSrcSize=0 and dict : ", testNb++);
1261 { ZSTD_parameters params = ZSTD_getParams(5, 0, 0);
1262 params.fParams.contentSizeFlag = 1;
Yann Collet213ef3b2017-10-13 19:01:58 -07001263 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 -07001264 } /* cstream advanced shall write content size = 0 */
Yann Collet8a104fd2017-12-12 12:51:49 -08001265 outBuff.dst = compressedBuffer;
1266 outBuff.size = compressedBufferSize;
1267 outBuff.pos = 0;
Yann Collet03832b72017-12-12 14:01:54 -08001268 inBuff.src = CNBuffer;
1269 inBuff.size = 0;
1270 inBuff.pos = 0;
Yann Colletd6770f82017-09-28 02:14:48 -07001271 CHECK_Z( ZSTD_compressStream(zc, &outBuff, &inBuff) );
Yann Collet0bb381d2017-04-18 15:08:52 -07001272 if (ZSTD_endStream(zc, &outBuff) != 0) goto _output_error;
1273 cSize = outBuff.pos;
1274 if (ZSTD_findDecompressedSize(compressedBuffer, cSize) != 0) goto _output_error;
1275 DISPLAYLEVEL(3, "OK \n");
1276
Sean Purcell2db72492017-02-09 10:50:43 -08001277 DISPLAYLEVEL(3, "test%3i : pledgedSrcSize == 0 behaves properly : ", testNb++);
1278 { ZSTD_parameters params = ZSTD_getParams(5, 0, 0);
1279 params.fParams.contentSizeFlag = 1;
Yann Colletd6770f82017-09-28 02:14:48 -07001280 CHECK_Z( ZSTD_initCStream_advanced(zc, NULL, 0, params, 0) );
Yann Collet4ee6b152017-04-11 11:59:44 -07001281 } /* cstream advanced shall write content size = 0 */
Sean Purcell2db72492017-02-09 10:50:43 -08001282 inBuff.src = CNBuffer;
1283 inBuff.size = 0;
1284 inBuff.pos = 0;
1285 outBuff.dst = compressedBuffer;
1286 outBuff.size = compressedBufferSize;
1287 outBuff.pos = 0;
Yann Colletd6770f82017-09-28 02:14:48 -07001288 CHECK_Z( ZSTD_compressStream(zc, &outBuff, &inBuff) );
Sean Purcell2db72492017-02-09 10:50:43 -08001289 if (ZSTD_endStream(zc, &outBuff) != 0) goto _output_error;
1290 cSize = outBuff.pos;
1291 if (ZSTD_findDecompressedSize(compressedBuffer, cSize) != 0) goto _output_error;
1292
1293 ZSTD_resetCStream(zc, 0); /* resetCStream should treat 0 as unknown */
Yann Collet8a104fd2017-12-12 12:51:49 -08001294 outBuff.dst = compressedBuffer;
1295 outBuff.size = compressedBufferSize;
1296 outBuff.pos = 0;
Yann Collet03832b72017-12-12 14:01:54 -08001297 inBuff.src = CNBuffer;
1298 inBuff.size = 0;
1299 inBuff.pos = 0;
Yann Colletd6770f82017-09-28 02:14:48 -07001300 CHECK_Z( ZSTD_compressStream(zc, &outBuff, &inBuff) );
Sean Purcell2db72492017-02-09 10:50:43 -08001301 if (ZSTD_endStream(zc, &outBuff) != 0) goto _output_error;
1302 cSize = outBuff.pos;
1303 if (ZSTD_findDecompressedSize(compressedBuffer, cSize) != ZSTD_CONTENTSIZE_UNKNOWN) goto _output_error;
1304 DISPLAYLEVEL(3, "OK \n");
Yann Collet17e482e2016-08-23 16:58:10 +02001305
Stella Lau90a31bf2017-08-30 14:36:54 -07001306 /* Basic multithreading compression test */
1307 DISPLAYLEVEL(3, "test%3i : compress %u bytes with multiple threads : ", testNb++, COMPRESSIBLE_NOISE_LENGTH);
Nick Terrellc51a9e72020-10-01 18:47:54 -07001308 { int jobSize;
1309 CHECK_Z( ZSTD_CCtx_getParameter(mtctx, ZSTD_c_jobSize, &jobSize));
Nick Terrellb426bcc2018-06-25 15:21:08 -07001310 CHECK(jobSize != 0, "job size non-zero");
Nick Terrellc51a9e72020-10-01 18:47:54 -07001311 CHECK_Z( ZSTD_CCtx_getParameter(mtctx, ZSTD_c_jobSize, &jobSize));
Nick Terrellb426bcc2018-06-25 15:21:08 -07001312 CHECK(jobSize != 0, "job size non-zero");
Yann Colletd6770f82017-09-28 02:14:48 -07001313 }
Yann Collet03832b72017-12-12 14:01:54 -08001314 outBuff.dst = compressedBuffer;
Stella Lau90a31bf2017-08-30 14:36:54 -07001315 outBuff.size = compressedBufferSize;
1316 outBuff.pos = 0;
1317 inBuff.src = CNBuffer;
1318 inBuff.size = CNBufferSize;
1319 inBuff.pos = 0;
Nick Terrellc51a9e72020-10-01 18:47:54 -07001320 { size_t const compressResult = ZSTD_compressStream2(mtctx, &outBuff, &inBuff, ZSTD_e_end);
Yann Collet67113962018-01-19 22:11:11 -08001321 if (compressResult != 0) goto _output_error; /* compression must be completed in a single round */
1322 }
Stella Lau90a31bf2017-08-30 14:36:54 -07001323 if (inBuff.pos != inBuff.size) goto _output_error; /* entire input should be consumed */
Yann Collet67113962018-01-19 22:11:11 -08001324 { size_t const compressedSize = ZSTD_findFrameCompressedSize(compressedBuffer, outBuff.pos);
1325 if (compressedSize != outBuff.pos) goto _output_error; /* must be a full valid frame */
1326 }
Stella Lau90a31bf2017-08-30 14:36:54 -07001327 DISPLAYLEVEL(3, "OK \n");
1328
Yann Collet03832b72017-12-12 14:01:54 -08001329 /* Complex multithreading + dictionary test */
Yann Collet209df522018-02-01 19:29:30 -08001330 { U32 const nbWorkers = 2;
Yann Collet03832b72017-12-12 14:01:54 -08001331 size_t const jobSize = 4 * 1 MB;
Yann Collet209df522018-02-01 19:29:30 -08001332 size_t const srcSize = jobSize * nbWorkers; /* we want each job to have predictable size */
Yann Collet03832b72017-12-12 14:01:54 -08001333 size_t const segLength = 2 KB;
1334 size_t const offset = 600 KB; /* must be larger than window defined in cdict */
1335 size_t const start = jobSize + (offset-1);
1336 const BYTE* const srcToCopy = (const BYTE*)CNBuffer + start;
1337 BYTE* const dst = (BYTE*)CNBuffer + start - offset;
Yann Colletededcfc2018-12-21 16:19:44 -08001338 DISPLAYLEVEL(3, "test%3i : compress %u bytes with multiple threads + dictionary : ", testNb++, (unsigned)srcSize);
Yann Collet3583d192018-12-05 17:26:02 -08001339 CHECK_Z( ZSTD_CCtx_setParameter(zc, ZSTD_c_compressionLevel, 3) );
1340 CHECK_Z( ZSTD_CCtx_setParameter(zc, ZSTD_c_nbWorkers, nbWorkers) );
1341 CHECK_Z( ZSTD_CCtx_setParameter(zc, ZSTD_c_jobSize, jobSize) );
Yann Collet03832b72017-12-12 14:01:54 -08001342 assert(start > offset);
1343 assert(start + segLength < COMPRESSIBLE_NOISE_LENGTH);
1344 memcpy(dst, srcToCopy, segLength); /* create a long repetition at long distance for job 2 */
1345 outBuff.dst = compressedBuffer;
1346 outBuff.size = compressedBufferSize;
1347 outBuff.pos = 0;
1348 inBuff.src = CNBuffer;
1349 inBuff.size = srcSize; assert(srcSize < COMPRESSIBLE_NOISE_LENGTH);
1350 inBuff.pos = 0;
1351 }
Josh Sorefa880ca22019-04-12 14:18:11 -04001352 { 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 -07001353 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 -08001354 DISPLAYLEVEL(5, "cParams.windowLog = %u : ", cParams.windowLog);
Yann Colletd23eb9a2017-12-13 15:35:49 -08001355 CHECK_Z( ZSTD_CCtx_refCDict(zc, cdict) );
Yann Colletd8e215c2018-11-30 11:16:26 -08001356 CHECK_Z( ZSTD_compressStream2(zc, &outBuff, &inBuff, ZSTD_e_end) );
Yann Colletd23eb9a2017-12-13 15:35:49 -08001357 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 -08001358 ZSTD_freeCDict(cdict);
1359 }
1360 if (inBuff.pos != inBuff.size) goto _output_error; /* entire input should be consumed */
1361 cSize = outBuff.pos;
1362 DISPLAYLEVEL(3, "OK \n");
1363
1364 DISPLAYLEVEL(3, "test%3i : decompress large frame created from multiple threads + dictionary : ", testNb++);
1365 { ZSTD_DStream* const dstream = ZSTD_createDCtx();
1366 ZSTD_frameHeader zfh;
1367 ZSTD_getFrameHeader(&zfh, compressedBuffer, cSize);
Yann Colletededcfc2018-12-21 16:19:44 -08001368 DISPLAYLEVEL(5, "frame windowsize = %u : ", (unsigned)zfh.windowSize);
Yann Collet03832b72017-12-12 14:01:54 -08001369 outBuff.dst = decodedBuffer;
1370 outBuff.size = CNBufferSize;
1371 outBuff.pos = 0;
1372 inBuff.src = compressedBuffer;
1373 inBuff.pos = 0;
1374 CHECK_Z( ZSTD_initDStream_usingDict(dstream, dictionary.start, dictionary.filled) );
1375 inBuff.size = 1; /* avoid shortcut to single-pass mode */
1376 CHECK_Z( ZSTD_decompressStream(dstream, &outBuff, &inBuff) );
1377 inBuff.size = cSize;
1378 CHECK_Z( ZSTD_decompressStream(dstream, &outBuff, &inBuff) );
1379 if (inBuff.pos != inBuff.size) goto _output_error; /* entire input should be consumed */
1380 ZSTD_freeDStream(dstream);
1381 }
1382 DISPLAYLEVEL(3, "OK \n");
1383
Nick Terrelle600b5d2017-10-16 17:18:43 -07001384 DISPLAYLEVEL(3, "test%3i : check dictionary FSE tables can represent every code : ", testNb++);
1385 { unsigned const kMaxWindowLog = 24;
1386 unsigned value;
1387 ZSTD_compressionParameters cParams = ZSTD_getCParams(3, 1U << kMaxWindowLog, 1024);
1388 ZSTD_CDict* cdict;
1389 ZSTD_DDict* ddict;
1390 SEQ_stream seq = SEQ_initStream(0x87654321);
1391 SEQ_gen_type type;
1392 XXH64_state_t xxh;
1393
1394 XXH64_reset(&xxh, 0);
1395 cParams.windowLog = kMaxWindowLog;
Yann Collet6873fec2018-03-20 15:13:14 -07001396 cdict = ZSTD_createCDict_advanced(dictionary.start, dictionary.filled, ZSTD_dlm_byRef, ZSTD_dct_fullDict, cParams, ZSTD_defaultCMem);
Nick Terrelle600b5d2017-10-16 17:18:43 -07001397 ddict = ZSTD_createDDict(dictionary.start, dictionary.filled);
1398
1399 if (!cdict || !ddict) goto _output_error;
1400
Yann Collet5c686392018-11-15 16:12:39 -08001401 ZSTD_CCtx_reset(zc, ZSTD_reset_session_only);
Nick Terrelle600b5d2017-10-16 17:18:43 -07001402 ZSTD_resetDStream(zd);
1403 CHECK_Z(ZSTD_CCtx_refCDict(zc, cdict));
1404 CHECK_Z(ZSTD_initDStream_usingDDict(zd, ddict));
Yann Collet3e042d52018-12-04 17:30:58 -08001405 CHECK_Z(ZSTD_DCtx_setParameter(zd, ZSTD_d_windowLogMax, kMaxWindowLog));
Nick Terrelle600b5d2017-10-16 17:18:43 -07001406 /* Test all values < 300 */
1407 for (value = 0; value < 300; ++value) {
1408 for (type = (SEQ_gen_type)0; type < SEQ_gen_max; ++type) {
1409 CHECK_Z(SEQ_generateRoundTrip(zc, zd, &xxh, &seq, type, value));
1410 }
1411 }
1412 /* Test values 2^8 to 2^17 */
1413 for (value = (1 << 8); value < (1 << 17); value <<= 1) {
1414 for (type = (SEQ_gen_type)0; type < SEQ_gen_max; ++type) {
1415 CHECK_Z(SEQ_generateRoundTrip(zc, zd, &xxh, &seq, type, value));
1416 CHECK_Z(SEQ_generateRoundTrip(zc, zd, &xxh, &seq, type, value + (value >> 2)));
1417 }
1418 }
1419 /* Test offset values up to the max window log */
1420 for (value = 8; value <= kMaxWindowLog; ++value) {
1421 CHECK_Z(SEQ_generateRoundTrip(zc, zd, &xxh, &seq, SEQ_gen_of, (1U << value) - 1));
1422 }
1423
1424 CHECK_Z(SEQ_roundTrip(zc, zd, &xxh, NULL, 0, ZSTD_e_end));
1425 CHECK(SEQ_digest(&seq) != XXH64_digest(&xxh), "SEQ XXH64 does not match");
1426
1427 ZSTD_freeCDict(cdict);
1428 ZSTD_freeDDict(ddict);
1429 }
1430 DISPLAYLEVEL(3, "OK \n");
Stella Lau90a31bf2017-08-30 14:36:54 -07001431
Nick Terrell6d222c42018-07-12 17:56:58 -07001432 DISPLAYLEVEL(3, "test%3i : ZSTD_initCStream_srcSize sets requestedParams : ", testNb++);
Yann Colletd4d4e102018-11-21 15:37:26 -08001433 { int level;
Nick Terrell6d222c42018-07-12 17:56:58 -07001434 CHECK_Z(ZSTD_initCStream_srcSize(zc, 11, ZSTD_CONTENTSIZE_UNKNOWN));
Yann Collet3583d192018-12-05 17:26:02 -08001435 CHECK_Z(ZSTD_CCtx_getParameter(zc, ZSTD_c_compressionLevel, &level));
Nick Terrell6d222c42018-07-12 17:56:58 -07001436 CHECK(level != 11, "Compression level does not match");
1437 ZSTD_resetCStream(zc, ZSTD_CONTENTSIZE_UNKNOWN);
Yann Collet3583d192018-12-05 17:26:02 -08001438 CHECK_Z(ZSTD_CCtx_getParameter(zc, ZSTD_c_compressionLevel, &level));
Nick Terrell6d222c42018-07-12 17:56:58 -07001439 CHECK(level != 11, "Compression level does not match");
1440 }
1441 DISPLAYLEVEL(3, "OK \n");
1442
1443 DISPLAYLEVEL(3, "test%3i : ZSTD_initCStream_advanced sets requestedParams : ", testNb++);
1444 { ZSTD_parameters const params = ZSTD_getParams(9, 0, 0);
1445 CHECK_Z(ZSTD_initCStream_advanced(zc, NULL, 0, params, ZSTD_CONTENTSIZE_UNKNOWN));
1446 CHECK(badParameters(zc, params), "Compression parameters do not match");
1447 ZSTD_resetCStream(zc, ZSTD_CONTENTSIZE_UNKNOWN);
1448 CHECK(badParameters(zc, params), "Compression parameters do not match");
1449 }
1450 DISPLAYLEVEL(3, "OK \n");
1451
Nick Terrell51990242019-09-18 11:05:08 -07001452 DISPLAYLEVEL(3, "test%3i : ZSTD_c_srcSizeHint bounds : ", testNb++);
1453 ZSTD_CCtx_reset(zc, ZSTD_reset_session_and_parameters);
1454 CHECK_Z(ZSTD_CCtx_setParameter(zc, ZSTD_c_srcSizeHint, INT_MAX));
1455 { int srcSizeHint;
1456 CHECK_Z(ZSTD_CCtx_getParameter(zc, ZSTD_c_srcSizeHint, &srcSizeHint));
1457 CHECK(!(srcSizeHint == INT_MAX), "srcSizeHint doesn't match");
1458 }
1459 CHECK(!ZSTD_isError(ZSTD_CCtx_setParameter(zc, ZSTD_c_srcSizeHint, -1)), "Out of range doesn't error");
1460 DISPLAYLEVEL(3, "OK \n");
1461
Sean Purcell887eaa92017-02-15 16:43:45 -08001462 /* Overlen overwriting window data bug */
1463 DISPLAYLEVEL(3, "test%3i : wildcopy doesn't overwrite potential match data : ", testNb++);
Sean Purcell0ed39012017-02-16 13:29:47 -08001464 { /* This test has a window size of 1024 bytes and consists of 3 blocks:
1465 1. 'a' repeated 517 times
1466 2. 'b' repeated 516 times
1467 3. a compressed block with no literals and 3 sequence commands:
1468 litlength = 0, offset = 24, match length = 24
1469 litlength = 0, offset = 24, match length = 3 (this one creates an overlength write of length 2*WILDCOPY_OVERLENGTH - 3)
1470 litlength = 0, offset = 1021, match length = 3 (this one will try to read from overwritten data if the buffer is too small) */
1471
1472 const char* testCase =
1473 "\x28\xB5\x2F\xFD\x04\x00\x4C\x00\x00\x10\x61\x61\x01\x00\x00\x2A"
1474 "\x80\x05\x44\x00\x00\x08\x62\x01\x00\x00\x2A\x20\x04\x5D\x00\x00"
1475 "\x00\x03\x40\x00\x00\x64\x60\x27\xB0\xE0\x0C\x67\x62\xCE\xE0";
Yann Colletd6770f82017-09-28 02:14:48 -07001476 ZSTD_DStream* const zds = ZSTD_createDStream();
1477 if (zds==NULL) goto _output_error;
Sean Purcell887eaa92017-02-15 16:43:45 -08001478
Yann Colletd6770f82017-09-28 02:14:48 -07001479 CHECK_Z( ZSTD_initDStream(zds) );
Sean Purcell887eaa92017-02-15 16:43:45 -08001480 inBuff.src = testCase;
Sean Purcell0ed39012017-02-16 13:29:47 -08001481 inBuff.size = 47;
Sean Purcell887eaa92017-02-15 16:43:45 -08001482 inBuff.pos = 0;
1483 outBuff.dst = decodedBuffer;
1484 outBuff.size = CNBufferSize;
1485 outBuff.pos = 0;
1486
1487 while (inBuff.pos < inBuff.size) {
Yann Colletd6770f82017-09-28 02:14:48 -07001488 CHECK_Z( ZSTD_decompressStream(zds, &outBuff, &inBuff) );
Sean Purcell887eaa92017-02-15 16:43:45 -08001489 }
Przemyslaw Skibinski684858e2017-02-21 18:17:24 +01001490
1491 ZSTD_freeDStream(zds);
Sean Purcell887eaa92017-02-15 16:43:45 -08001492 }
1493 DISPLAYLEVEL(3, "OK \n");
1494
Ephraim Park01e83842019-06-27 17:27:29 -07001495 /* Small Sequence Section bug */
1496 DISPLAYLEVEL(3, "test%3i : decompress blocks with small sequences section : ", testNb++);
1497 { /* This test consists of 3 blocks. Each block has one sequence.
1498 The sequence has literal length of 10, match length of 10 and offset of 10.
1499 The sequence value and compression mode for the blocks are following:
1500 The order of values are ll, ml, of.
1501 - First block : (10, 7, 13) (rle, rle, rle)
1502 - size of sequences section: 6 bytes (1 byte for nbSeq, 1 byte for encoding mode, 3 bytes for rle, 1 byte bitstream)
1503 - Second block : (10, 7, 1) (repeat, repeat, rle)
1504 - size of sequences section: 4 bytes (1 byte for nbSeq, 1 byte for encoding mode, 1 bytes for rle, 1 byte bitstream)
1505 - Third block : (10, 7, 1) (repeat, repeat, repeat)
1506 - size of sequences section: 3 bytes (1 byte for nbSeq, 1 byte for encoding mode, 1 byte bitstream) */
1507
1508 unsigned char compressed[] = {
1509 0x28, 0xb5, 0x2f, 0xfd, 0x24, 0x3c, 0x35, 0x01, 0x00, 0xf0, 0x85, 0x08,
1510 0xc2, 0xc4, 0x70, 0xcf, 0xd7, 0xc0, 0x96, 0x7e, 0x4c, 0x6b, 0xa9, 0x8b,
1511 0xbc, 0xc5, 0xb6, 0xd9, 0x7f, 0x4c, 0xf1, 0x05, 0xa6, 0x54, 0xef, 0xac,
1512 0x69, 0x94, 0x89, 0x1c, 0x03, 0x44, 0x0a, 0x07, 0x00, 0xb4, 0x04, 0x80,
1513 0x40, 0x0a, 0xa4
1514 };
1515 unsigned int compressedSize = 51;
1516 unsigned char decompressed[] = {
1517 0x85, 0x08, 0xc2, 0xc4, 0x70, 0xcf, 0xd7, 0xc0, 0x96, 0x7e, 0x85, 0x08,
1518 0xc2, 0xc4, 0x70, 0xcf, 0xd7, 0xc0, 0x96, 0x7e, 0x4c, 0x6b, 0xa9, 0x8b,
1519 0xbc, 0xc5, 0xb6, 0xd9, 0x7f, 0x4c, 0x4c, 0x6b, 0xa9, 0x8b, 0xbc, 0xc5,
1520 0xb6, 0xd9, 0x7f, 0x4c, 0xf1, 0x05, 0xa6, 0x54, 0xef, 0xac, 0x69, 0x94,
1521 0x89, 0x1c, 0xf1, 0x05, 0xa6, 0x54, 0xef, 0xac, 0x69, 0x94, 0x89, 0x1c
1522 };
1523 unsigned int decompressedSize = 60;
1524
1525 ZSTD_DStream* const zds = ZSTD_createDStream();
1526 if (zds==NULL) goto _output_error;
1527
1528 CHECK_Z( ZSTD_initDStream(zds) );
1529 inBuff.src = compressed;
1530 inBuff.size = compressedSize;
1531 inBuff.pos = 0;
1532 outBuff.dst = decodedBuffer;
1533 outBuff.size = CNBufferSize;
1534 outBuff.pos = 0;
1535
Ephraim Park28309522019-07-01 10:17:30 -07001536 CHECK(ZSTD_decompressStream(zds, &outBuff, &inBuff) != 0,
1537 "Decompress did not reach the end of frame");
1538 CHECK(inBuff.pos != inBuff.size, "Decompress did not fully consume input");
1539 CHECK(outBuff.pos != decompressedSize, "Decompressed size does not match");
1540 CHECK(memcmp(outBuff.dst, decompressed, decompressedSize) != 0,
1541 "Decompressed data does not match");
Ephraim Park01e83842019-06-27 17:27:29 -07001542
1543 ZSTD_freeDStream(zds);
1544 }
1545 DISPLAYLEVEL(3, "OK \n");
1546
Nick Terrell036b30b2020-01-10 18:02:11 -08001547 DISPLAYLEVEL(3, "test%3i : raw block can be streamed: ", testNb++);
1548 { size_t const inputSize = 10000;
1549 size_t const compCapacity = ZSTD_compressBound(inputSize);
1550 BYTE* const input = (BYTE*)malloc(inputSize);
1551 BYTE* const comp = (BYTE*)malloc(compCapacity);
1552 BYTE* const decomp = (BYTE*)malloc(inputSize);
1553
1554 CHECK(input == NULL || comp == NULL || decomp == NULL, "failed to alloc buffers");
1555
1556 RDG_genBuffer(input, inputSize, 0.0, 0.0, seed);
1557 { size_t const compSize = ZSTD_compress(comp, compCapacity, input, inputSize, -(int)inputSize);
1558 ZSTD_inBuffer in = { comp, 0, 0 };
1559 ZSTD_outBuffer out = { decomp, 0, 0 };
1560 CHECK_Z(compSize);
1561 CHECK_Z( ZSTD_DCtx_reset(zd, ZSTD_reset_session_and_parameters) );
1562 while (in.size < compSize) {
1563 in.size = MIN(in.size + 100, compSize);
1564 while (in.pos < in.size) {
1565 size_t const outPos = out.pos;
1566 if (out.pos == out.size) {
1567 out.size = MIN(out.size + 10, inputSize);
1568 }
1569 CHECK_Z( ZSTD_decompressStream(zd, &out, &in) );
1570 CHECK(!(out.pos > outPos), "We are not streaming (no output generated)");
1571 }
1572 }
1573 CHECK(in.pos != compSize, "Not all input consumed!");
1574 CHECK(out.pos != inputSize, "Not all output produced!");
1575 }
1576 CHECK(memcmp(input, decomp, inputSize), "round trip failed!");
1577
1578 free(input);
1579 free(comp);
1580 free(decomp);
1581 }
1582 DISPLAYLEVEL(3, "OK \n");
1583
W. Felix Handtedb4c8d02018-08-24 14:30:21 -07001584 DISPLAYLEVEL(3, "test%3i : dictionary + uncompressible block + reusing tables checks offset table validity: ", testNb++);
1585 { ZSTD_CDict* const cdict = ZSTD_createCDict_advanced(
1586 dictionary.start, dictionary.filled,
1587 ZSTD_dlm_byRef, ZSTD_dct_fullDict,
1588 ZSTD_getCParams(3, 0, dictionary.filled),
1589 ZSTD_defaultCMem);
1590 const size_t inbufsize = 2 * 128 * 1024; /* 2 blocks */
1591 const size_t outbufsize = ZSTD_compressBound(inbufsize);
1592 size_t inbufpos = 0;
1593 size_t cursegmentlen;
1594 BYTE *inbuf = (BYTE *)malloc(inbufsize);
1595 BYTE *outbuf = (BYTE *)malloc(outbufsize);
1596 BYTE *checkbuf = (BYTE *)malloc(inbufsize);
1597 size_t ret;
1598
1599 CHECK(cdict == NULL, "failed to alloc cdict");
1600 CHECK(inbuf == NULL, "failed to alloc input buffer");
Yann Colletd195eec2018-09-13 12:29:52 -07001601
W. Felix Handtedb4c8d02018-08-24 14:30:21 -07001602 /* first block is uncompressible */
1603 cursegmentlen = 128 * 1024;
1604 RDG_genBuffer(inbuf + inbufpos, cursegmentlen, 0., 0., seed);
1605 inbufpos += cursegmentlen;
1606
1607 /* second block is compressible */
1608 cursegmentlen = 128 * 1024 - 256;
1609 RDG_genBuffer(inbuf + inbufpos, cursegmentlen, 0.05, 0., seed);
1610 inbufpos += cursegmentlen;
1611
1612 /* and includes a very long backref */
1613 cursegmentlen = 128;
W. Felix Handtedacbcd22020-05-01 12:24:51 -04001614 memcpy(inbuf + inbufpos, (BYTE*)dictionary.start + 256, cursegmentlen);
W. Felix Handtedb4c8d02018-08-24 14:30:21 -07001615 inbufpos += cursegmentlen;
1616
1617 /* and includes a very long backref */
1618 cursegmentlen = 128;
W. Felix Handtedacbcd22020-05-01 12:24:51 -04001619 memcpy(inbuf + inbufpos, (BYTE*)dictionary.start + 128, cursegmentlen);
W. Felix Handtedb4c8d02018-08-24 14:30:21 -07001620 inbufpos += cursegmentlen;
1621
1622 ret = ZSTD_compress_usingCDict(zc, outbuf, outbufsize, inbuf, inbufpos, cdict);
1623 CHECK_Z(ret);
1624
1625 ret = ZSTD_decompress_usingDict(zd, checkbuf, inbufsize, outbuf, ret, dictionary.start, dictionary.filled);
1626 CHECK_Z(ret);
1627
1628 CHECK(memcmp(inbuf, checkbuf, inbufpos), "start and finish buffers don't match");
1629
1630 ZSTD_freeCDict(cdict);
1631 free(inbuf);
1632 free(outbuf);
1633 free(checkbuf);
1634 }
1635 DISPLAYLEVEL(3, "OK \n");
1636
Nick Terrell146049a2018-09-28 12:09:14 -07001637 DISPLAYLEVEL(3, "test%3i : dictionary + small blocks + reusing tables checks offset table validity: ", testNb++);
1638 { ZSTD_CDict* const cdict = ZSTD_createCDict_advanced(
1639 dictionary.start, dictionary.filled,
1640 ZSTD_dlm_byRef, ZSTD_dct_fullDict,
1641 ZSTD_getCParams(3, 0, dictionary.filled),
1642 ZSTD_defaultCMem);
1643 ZSTD_outBuffer out = {compressedBuffer, compressedBufferSize, 0};
1644 int remainingInput = 256 * 1024;
Nick Terrelleb4423e2018-09-28 14:24:38 -07001645 int offset;
Nick Terrell146049a2018-09-28 12:09:14 -07001646
Yann Collet5c686392018-11-15 16:12:39 -08001647 CHECK_Z(ZSTD_CCtx_reset(zc, ZSTD_reset_session_and_parameters));
Nick Terrell146049a2018-09-28 12:09:14 -07001648 CHECK_Z(ZSTD_CCtx_refCDict(zc, cdict));
Yann Collet3583d192018-12-05 17:26:02 -08001649 CHECK_Z(ZSTD_CCtx_setParameter(zc, ZSTD_c_checksumFlag, 1));
Nick Terrell146049a2018-09-28 12:09:14 -07001650 /* Write a bunch of 6 byte blocks */
1651 while (remainingInput > 0) {
Nick Terrell0e7a7f12018-09-28 12:14:24 -07001652 char testBuffer[6] = "\xAA\xAA\xAA\xAA\xAA\xAA";
1653 const size_t kSmallBlockSize = sizeof(testBuffer);
Nick Terrell146049a2018-09-28 12:09:14 -07001654 ZSTD_inBuffer in = {testBuffer, kSmallBlockSize, 0};
1655
Yann Colletd8e215c2018-11-30 11:16:26 -08001656 CHECK_Z(ZSTD_compressStream2(zc, &out, &in, ZSTD_e_flush));
Nick Terrell146049a2018-09-28 12:09:14 -07001657 CHECK(in.pos != in.size, "input not fully consumed");
1658 remainingInput -= kSmallBlockSize;
1659 }
1660 /* Write several very long offset matches into the dictionary */
Nick Terrelleb4423e2018-09-28 14:24:38 -07001661 for (offset = 1024; offset >= 0; offset -= 128) {
W. Felix Handtedacbcd22020-05-01 12:24:51 -04001662 ZSTD_inBuffer in = {(BYTE*)dictionary.start + offset, 128, 0};
Nick Terrell146049a2018-09-28 12:09:14 -07001663 ZSTD_EndDirective flush = offset > 0 ? ZSTD_e_continue : ZSTD_e_end;
Yann Colletd8e215c2018-11-30 11:16:26 -08001664 CHECK_Z(ZSTD_compressStream2(zc, &out, &in, flush));
Nick Terrell146049a2018-09-28 12:09:14 -07001665 CHECK(in.pos != in.size, "input not fully consumed");
1666 }
1667 /* Ensure decompression works */
1668 CHECK_Z(ZSTD_decompress_usingDict(zd, decodedBuffer, CNBufferSize, out.dst, out.pos, dictionary.start, dictionary.filled));
1669
1670 ZSTD_freeCDict(cdict);
1671 }
1672 DISPLAYLEVEL(3, "OK \n");
1673
Yann Colletd7883a22016-08-12 16:48:02 +02001674_end:
Yann Collet33fce032017-01-16 19:46:22 -08001675 FUZ_freeDictionary(dictionary);
Yann Colletd7883a22016-08-12 16:48:02 +02001676 ZSTD_freeCStream(zc);
1677 ZSTD_freeDStream(zd);
Nick Terrellc51a9e72020-10-01 18:47:54 -07001678 ZSTD_freeCCtx(mtctx);
Yann Colletd7883a22016-08-12 16:48:02 +02001679 free(CNBuffer);
1680 free(compressedBuffer);
1681 free(decodedBuffer);
1682 return testResult;
1683
1684_output_error:
1685 testResult = 1;
1686 DISPLAY("Error detected in Unit tests ! \n");
1687 goto _end;
1688}
1689
1690
Yann Collet3ecbe6a2016-09-14 17:26:59 +02001691/* ====== Fuzzer tests ====== */
1692
Yann Colletd7883a22016-08-12 16:48:02 +02001693static size_t findDiff(const void* buf1, const void* buf2, size_t max)
1694{
1695 const BYTE* b1 = (const BYTE*)buf1;
1696 const BYTE* b2 = (const BYTE*)buf2;
1697 size_t u;
1698 for (u=0; u<max; u++) {
1699 if (b1[u] != b2[u]) break;
1700 }
Yann Collet940634a2018-01-19 13:19:59 -08001701 if (u==max) {
Yann Colletededcfc2018-12-21 16:19:44 -08001702 DISPLAY("=> No difference detected within %u bytes \n", (unsigned)max);
Yann Collet940634a2018-01-19 13:19:59 -08001703 return u;
1704 }
Yann Colletededcfc2018-12-21 16:19:44 -08001705 DISPLAY("Error at position %u / %u \n", (unsigned)u, (unsigned)max);
Yann Colletdc696232018-01-19 12:41:56 -08001706 if (u>=3)
1707 DISPLAY(" %02X %02X %02X ",
1708 b1[u-3], b1[u-2], b1[u-1]);
1709 DISPLAY(" :%02X: %02X %02X %02X %02X %02X \n",
1710 b1[u], b1[u+1], b1[u+2], b1[u+3], b1[u+4], b1[u+5]);
1711 if (u>=3)
1712 DISPLAY(" %02X %02X %02X ",
1713 b2[u-3], b2[u-2], b2[u-1]);
1714 DISPLAY(" :%02X: %02X %02X %02X %02X %02X \n",
1715 b2[u], b2[u+1], b2[u+2], b2[u+3], b2[u+4], b2[u+5]);
Yann Colletd7883a22016-08-12 16:48:02 +02001716 return u;
1717}
1718
1719static size_t FUZ_rLogLength(U32* seed, U32 logLength)
1720{
1721 size_t const lengthMask = ((size_t)1 << logLength) - 1;
1722 return (lengthMask+1) + (FUZ_rand(seed) & lengthMask);
1723}
1724
1725static size_t FUZ_randomLength(U32* seed, U32 maxLog)
1726{
1727 U32 const logLength = FUZ_rand(seed) % maxLog;
1728 return FUZ_rLogLength(seed, logLength);
1729}
1730
Stella Lau9e406022017-09-06 08:39:46 -07001731/* Return value in range minVal <= v <= maxVal */
1732static U32 FUZ_randomClampedLength(U32* seed, U32 minVal, U32 maxVal)
1733{
1734 U32 const mod = maxVal < minVal ? 1 : (maxVal + 1) - minVal;
1735 return (U32)((FUZ_rand(seed) % mod) + minVal);
1736}
1737
Yann Colletededcfc2018-12-21 16:19:44 -08001738static int fuzzerTests(U32 seed, unsigned nbTests, unsigned startTest, double compressibility, int bigTests)
Yann Colletd7883a22016-08-12 16:48:02 +02001739{
Yann Colletf99c2c12017-06-21 23:35:58 -07001740 U32 const maxSrcLog = bigTests ? 24 : 22;
Yann Colletd7883a22016-08-12 16:48:02 +02001741 static const U32 maxSampleLog = 19;
Yann Collet58d5dfe2016-09-25 01:34:03 +02001742 size_t const srcBufferSize = (size_t)1<<maxSrcLog;
Yann Colletd7883a22016-08-12 16:48:02 +02001743 BYTE* cNoiseBuffer[5];
Yann Colletbc32b402017-09-27 17:27:38 -07001744 size_t const copyBufferSize = srcBufferSize + (1<<maxSampleLog);
Yann Collet58d5dfe2016-09-25 01:34:03 +02001745 BYTE* const copyBuffer = (BYTE*)malloc (copyBufferSize);
Yann Colletbc32b402017-09-27 17:27:38 -07001746 size_t const cBufferSize = ZSTD_compressBound(srcBufferSize);
Yann Collet58d5dfe2016-09-25 01:34:03 +02001747 BYTE* const cBuffer = (BYTE*)malloc (cBufferSize);
1748 size_t const dstBufferSize = srcBufferSize;
1749 BYTE* const dstBuffer = (BYTE*)malloc (dstBufferSize);
Yann Colletd7883a22016-08-12 16:48:02 +02001750 U32 result = 0;
Yann Colletededcfc2018-12-21 16:19:44 -08001751 unsigned testNb = 0;
Yann Colletd7883a22016-08-12 16:48:02 +02001752 U32 coreSeed = seed;
Yann Colletbc32b402017-09-27 17:27:38 -07001753 ZSTD_CStream* zc = ZSTD_createCStream(); /* will be re-created sometimes */
1754 ZSTD_DStream* zd = ZSTD_createDStream(); /* will be re-created sometimes */
Yann Collet58d5dfe2016-09-25 01:34:03 +02001755 ZSTD_DStream* const zd_noise = ZSTD_createDStream();
Nick Terrell9a2f6f42017-11-29 19:11:12 -08001756 UTIL_time_t const startClock = UTIL_getTime();
Yann Colletbc32b402017-09-27 17:27:38 -07001757 const BYTE* dict = NULL; /* can keep same dict on 2 consecutive tests */
Yann Colletcf409a72016-09-26 16:41:05 +02001758 size_t dictSize = 0;
1759 U32 oldTestLog = 0;
Yann Collet49f84592017-06-21 18:43:39 -07001760 U32 const cLevelMax = bigTests ? (U32)ZSTD_maxCLevel() : g_cLevelMax_smallTests;
Yann Colletd7883a22016-08-12 16:48:02 +02001761
1762 /* allocations */
Yann Colletd7883a22016-08-12 16:48:02 +02001763 cNoiseBuffer[0] = (BYTE*)malloc (srcBufferSize);
1764 cNoiseBuffer[1] = (BYTE*)malloc (srcBufferSize);
1765 cNoiseBuffer[2] = (BYTE*)malloc (srcBufferSize);
1766 cNoiseBuffer[3] = (BYTE*)malloc (srcBufferSize);
1767 cNoiseBuffer[4] = (BYTE*)malloc (srcBufferSize);
Yann Colletd7883a22016-08-12 16:48:02 +02001768 CHECK (!cNoiseBuffer[0] || !cNoiseBuffer[1] || !cNoiseBuffer[2] || !cNoiseBuffer[3] || !cNoiseBuffer[4] ||
Yann Collet58d5dfe2016-09-25 01:34:03 +02001769 !copyBuffer || !dstBuffer || !cBuffer || !zc || !zd || !zd_noise ,
Yann Colletd7883a22016-08-12 16:48:02 +02001770 "Not enough memory, fuzzer tests cancelled");
1771
1772 /* Create initial samples */
1773 RDG_genBuffer(cNoiseBuffer[0], srcBufferSize, 0.00, 0., coreSeed); /* pure noise */
1774 RDG_genBuffer(cNoiseBuffer[1], srcBufferSize, 0.05, 0., coreSeed); /* barely compressible */
1775 RDG_genBuffer(cNoiseBuffer[2], srcBufferSize, compressibility, 0., coreSeed);
1776 RDG_genBuffer(cNoiseBuffer[3], srcBufferSize, 0.95, 0., coreSeed); /* highly compressible */
1777 RDG_genBuffer(cNoiseBuffer[4], srcBufferSize, 1.00, 0., coreSeed); /* sparse content */
1778 memset(copyBuffer, 0x65, copyBufferSize); /* make copyBuffer considered initialized */
Yann Collet58d5dfe2016-09-25 01:34:03 +02001779 ZSTD_initDStream_usingDict(zd, NULL, 0); /* ensure at least one init */
Yann Colletd7883a22016-08-12 16:48:02 +02001780
1781 /* catch up testNb */
1782 for (testNb=1; testNb < startTest; testNb++)
1783 FUZ_rand(&coreSeed);
1784
1785 /* test loop */
Nick Terrell9a2f6f42017-11-29 19:11:12 -08001786 for ( ; (testNb <= nbTests) || (UTIL_clockSpanMicro(startClock) < g_clockTime) ; testNb++ ) {
Yann Colletd7883a22016-08-12 16:48:02 +02001787 U32 lseed;
1788 const BYTE* srcBuffer;
Yann Collet58d5dfe2016-09-25 01:34:03 +02001789 size_t totalTestSize, totalGenSize, cSize;
Yann Colletd7883a22016-08-12 16:48:02 +02001790 XXH64_state_t xxhState;
1791 U64 crcOrig;
Yann Collet58d5dfe2016-09-25 01:34:03 +02001792 U32 resetAllowed = 1;
Yann Colletcf409a72016-09-26 16:41:05 +02001793 size_t maxTestSize;
Yann Colletd7883a22016-08-12 16:48:02 +02001794
1795 /* init */
Yann Colletd7883a22016-08-12 16:48:02 +02001796 FUZ_rand(&coreSeed);
Yann Collet33fce032017-01-16 19:46:22 -08001797 lseed = coreSeed ^ prime32;
Yann Collet3ad7d492018-01-19 17:35:08 -08001798 if (nbTests >= testNb) {
Yann Collet9c40ae72018-01-26 17:48:33 -08001799 DISPLAYUPDATE(2, "\r%6u/%6u ", testNb, nbTests);
Yann Collet3ad7d492018-01-19 17:35:08 -08001800 } else {
Yann Collet9c40ae72018-01-26 17:48:33 -08001801 DISPLAYUPDATE(2, "\r%6u ", testNb);
Yann Collet3ad7d492018-01-19 17:35:08 -08001802 }
Yann Colletd7883a22016-08-12 16:48:02 +02001803
Yann Collet3ecbe6a2016-09-14 17:26:59 +02001804 /* states full reset (deliberately not synchronized) */
1805 /* some issues can only happen when reusing states */
Yann Colleted1d0392017-06-19 11:07:33 -07001806 if ((FUZ_rand(&lseed) & 0xFF) == 131) {
1807 ZSTD_freeCStream(zc);
1808 zc = ZSTD_createCStream();
Yann Colletdce78922017-06-21 15:53:42 -07001809 CHECK(zc==NULL, "ZSTD_createCStream : allocation error");
Yann Colleted1d0392017-06-19 11:07:33 -07001810 resetAllowed=0;
1811 }
1812 if ((FUZ_rand(&lseed) & 0xFF) == 132) {
1813 ZSTD_freeDStream(zd);
1814 zd = ZSTD_createDStream();
Yann Colletdce78922017-06-21 15:53:42 -07001815 CHECK(zd==NULL, "ZSTD_createDStream : allocation error");
1816 CHECK_Z( ZSTD_initDStream_usingDict(zd, NULL, 0) ); /* ensure at least one init */
Yann Colleted1d0392017-06-19 11:07:33 -07001817 }
Yann Colletd7883a22016-08-12 16:48:02 +02001818
1819 /* srcBuffer selection [0-4] */
1820 { U32 buffNb = FUZ_rand(&lseed) & 0x7F;
1821 if (buffNb & 7) buffNb=2; /* most common : compressible (P) */
1822 else {
1823 buffNb >>= 3;
1824 if (buffNb & 7) {
1825 const U32 tnb[2] = { 1, 3 }; /* barely/highly compressible */
1826 buffNb = tnb[buffNb >> 3];
1827 } else {
1828 const U32 tnb[2] = { 0, 4 }; /* not compressible / sparse */
1829 buffNb = tnb[buffNb >> 3];
1830 } }
1831 srcBuffer = cNoiseBuffer[buffNb];
1832 }
1833
1834 /* compression init */
Yann Colletcf409a72016-09-26 16:41:05 +02001835 if ((FUZ_rand(&lseed)&1) /* at beginning, to keep same nb of rand */
1836 && oldTestLog /* at least one test happened */ && resetAllowed) {
1837 maxTestSize = FUZ_randomLength(&lseed, oldTestLog+2);
Yann Colletbc32b402017-09-27 17:27:38 -07001838 maxTestSize = MIN(maxTestSize, srcBufferSize-16);
Yann Colletcf409a72016-09-26 16:41:05 +02001839 { U64 const pledgedSrcSize = (FUZ_rand(&lseed) & 3) ? 0 : maxTestSize;
Yann Collet01743a32017-06-16 17:56:41 -07001840 CHECK_Z( ZSTD_resetCStream(zc, pledgedSrcSize) );
Yann Colletcf409a72016-09-26 16:41:05 +02001841 }
Yann Collet58d5dfe2016-09-25 01:34:03 +02001842 } else {
1843 U32 const testLog = FUZ_rand(&lseed) % maxSrcLog;
Sean Purcellf5e50512017-03-15 15:04:54 -07001844 U32 const dictLog = FUZ_rand(&lseed) % maxSrcLog;
Yann Colletbfc2f002017-06-21 17:57:14 -07001845 U32 const cLevelCandidate = ( FUZ_rand(&lseed) %
Sean Purcell7ebf2de2017-03-20 11:25:00 -07001846 (ZSTD_maxCLevel() -
Yann Colletbfc2f002017-06-21 17:57:14 -07001847 (MAX(testLog, dictLog) / 3)))
Yann Colletce800982017-04-05 16:34:09 -07001848 + 1;
Yann Colletbfc2f002017-06-21 17:57:14 -07001849 U32 const cLevel = MIN(cLevelCandidate, cLevelMax);
Yann Colletd7883a22016-08-12 16:48:02 +02001850 maxTestSize = FUZ_rLogLength(&lseed, testLog);
Yann Colletcf409a72016-09-26 16:41:05 +02001851 oldTestLog = testLog;
Yann Colletd7883a22016-08-12 16:48:02 +02001852 /* random dictionary selection */
Yann Colletf99c2c12017-06-21 23:35:58 -07001853 dictSize = ((FUZ_rand(&lseed)&7)==1) ? FUZ_rLogLength(&lseed, dictLog) : 0;
Yann Colletd7883a22016-08-12 16:48:02 +02001854 { size_t const dictStart = FUZ_rand(&lseed) % (srcBufferSize - dictSize);
1855 dict = srcBuffer + dictStart;
1856 }
Yann Collet213ef3b2017-10-13 19:01:58 -07001857 { U64 const pledgedSrcSize = (FUZ_rand(&lseed) & 3) ? ZSTD_CONTENTSIZE_UNKNOWN : maxTestSize;
Yann Colletcf409a72016-09-26 16:41:05 +02001858 ZSTD_parameters params = ZSTD_getParams(cLevel, pledgedSrcSize, dictSize);
Yann Colletd7883a22016-08-12 16:48:02 +02001859 params.fParams.checksumFlag = FUZ_rand(&lseed) & 1;
1860 params.fParams.noDictIDFlag = FUZ_rand(&lseed) & 1;
Yann Collet213ef3b2017-10-13 19:01:58 -07001861 params.fParams.contentSizeFlag = FUZ_rand(&lseed) & 1;
Yann Collet01743a32017-06-16 17:56:41 -07001862 CHECK_Z ( ZSTD_initCStream_advanced(zc, dict, dictSize, params, pledgedSrcSize) );
1863 } }
Yann Colletd7883a22016-08-12 16:48:02 +02001864
1865 /* multi-segments compression test */
1866 XXH64_reset(&xxhState, 0);
Yann Collet2f263942016-09-26 14:06:08 +02001867 { ZSTD_outBuffer outBuff = { cBuffer, cBufferSize, 0 } ;
Yann Collet58d5dfe2016-09-25 01:34:03 +02001868 U32 n;
Yann Collet2f263942016-09-26 14:06:08 +02001869 for (n=0, cSize=0, totalTestSize=0 ; totalTestSize < maxTestSize ; n++) {
Yann Collete795c8a2016-12-13 16:39:36 +01001870 /* compress random chunks into randomly sized dst buffers */
Yann Collet2f263942016-09-26 14:06:08 +02001871 { size_t const randomSrcSize = FUZ_randomLength(&lseed, maxSampleLog);
Yann Collet150354c2017-11-01 16:57:48 -07001872 size_t const srcSize = MIN(maxTestSize-totalTestSize, randomSrcSize);
Yann Collet2f263942016-09-26 14:06:08 +02001873 size_t const srcStart = FUZ_rand(&lseed) % (srcBufferSize - srcSize);
Yann Colletd7883a22016-08-12 16:48:02 +02001874 size_t const randomDstSize = FUZ_randomLength(&lseed, maxSampleLog);
1875 size_t const dstBuffSize = MIN(cBufferSize - cSize, randomDstSize);
Yann Collet2f263942016-09-26 14:06:08 +02001876 ZSTD_inBuffer inBuff = { srcBuffer+srcStart, srcSize, 0 };
Yann Collet53e17fb2016-08-17 01:39:22 +02001877 outBuff.size = outBuff.pos + dstBuffSize;
Yann Colletd7883a22016-08-12 16:48:02 +02001878
Yann Colleted1d0392017-06-19 11:07:33 -07001879 CHECK_Z( ZSTD_compressStream(zc, &outBuff, &inBuff) );
Yann Colletd7883a22016-08-12 16:48:02 +02001880
Yann Collet53e17fb2016-08-17 01:39:22 +02001881 XXH64_update(&xxhState, srcBuffer+srcStart, inBuff.pos);
1882 memcpy(copyBuffer+totalTestSize, srcBuffer+srcStart, inBuff.pos);
1883 totalTestSize += inBuff.pos;
Yann Colletd7883a22016-08-12 16:48:02 +02001884 }
1885
1886 /* random flush operation, to mess around */
1887 if ((FUZ_rand(&lseed) & 15) == 0) {
1888 size_t const randomDstSize = FUZ_randomLength(&lseed, maxSampleLog);
Yann Collet53e17fb2016-08-17 01:39:22 +02001889 size_t const adjustedDstSize = MIN(cBufferSize - cSize, randomDstSize);
1890 outBuff.size = outBuff.pos + adjustedDstSize;
Yann Colleted1d0392017-06-19 11:07:33 -07001891 CHECK_Z( ZSTD_flushStream(zc, &outBuff) );
1892 } }
Yann Colletd7883a22016-08-12 16:48:02 +02001893
1894 /* final frame epilogue */
1895 { size_t remainingToFlush = (size_t)(-1);
1896 while (remainingToFlush) {
1897 size_t const randomDstSize = FUZ_randomLength(&lseed, maxSampleLog);
1898 size_t const adjustedDstSize = MIN(cBufferSize - cSize, randomDstSize);
Yann Collet53e17fb2016-08-17 01:39:22 +02001899 outBuff.size = outBuff.pos + adjustedDstSize;
1900 remainingToFlush = ZSTD_endStream(zc, &outBuff);
Yann Collet009d6042017-05-19 10:17:59 -07001901 CHECK (ZSTD_isError(remainingToFlush), "end error : %s", ZSTD_getErrorName(remainingToFlush));
Yann Colletd7883a22016-08-12 16:48:02 +02001902 } }
1903 crcOrig = XXH64_digest(&xxhState);
Yann Collet53e17fb2016-08-17 01:39:22 +02001904 cSize = outBuff.pos;
Yann Colletd7883a22016-08-12 16:48:02 +02001905 }
1906
1907 /* multi - fragments decompression test */
Yann Collet58d5dfe2016-09-25 01:34:03 +02001908 if (!dictSize /* don't reset if dictionary : could be different */ && (FUZ_rand(&lseed) & 1)) {
Yann Colletdce78922017-06-21 15:53:42 -07001909 CHECK_Z ( ZSTD_resetDStream(zd) );
Yann Collet9ffbeea2016-12-02 18:37:38 -08001910 } else {
Yann Colletdce78922017-06-21 15:53:42 -07001911 CHECK_Z ( ZSTD_initDStream_usingDict(zd, dict, dictSize) );
Yann Collet9ffbeea2016-12-02 18:37:38 -08001912 }
Yann Colletd7883a22016-08-12 16:48:02 +02001913 { size_t decompressionResult = 1;
Yann Collet53e17fb2016-08-17 01:39:22 +02001914 ZSTD_inBuffer inBuff = { cBuffer, cSize, 0 };
1915 ZSTD_outBuffer outBuff= { dstBuffer, dstBufferSize, 0 };
1916 for (totalGenSize = 0 ; decompressionResult ; ) {
Yann Colletd7883a22016-08-12 16:48:02 +02001917 size_t const readCSrcSize = FUZ_randomLength(&lseed, maxSampleLog);
1918 size_t const randomDstSize = FUZ_randomLength(&lseed, maxSampleLog);
1919 size_t const dstBuffSize = MIN(dstBufferSize - totalGenSize, randomDstSize);
Yann Collet53e17fb2016-08-17 01:39:22 +02001920 inBuff.size = inBuff.pos + readCSrcSize;
Yann Colletca306c12017-09-27 00:39:41 -07001921 outBuff.size = outBuff.pos + dstBuffSize;
Yann Collet53e17fb2016-08-17 01:39:22 +02001922 decompressionResult = ZSTD_decompressStream(zd, &outBuff, &inBuff);
Yann Colletb3f33cc2017-09-09 14:37:28 -07001923 if (ZSTD_getErrorCode(decompressionResult) == ZSTD_error_checksum_wrong) {
1924 DISPLAY("checksum error : \n");
1925 findDiff(copyBuffer, dstBuffer, totalTestSize);
1926 }
1927 CHECK( ZSTD_isError(decompressionResult), "decompression error : %s",
1928 ZSTD_getErrorName(decompressionResult) );
Yann Colletd7883a22016-08-12 16:48:02 +02001929 }
1930 CHECK (decompressionResult != 0, "frame not fully decoded");
Yann Colletb3f33cc2017-09-09 14:37:28 -07001931 CHECK (outBuff.pos != totalTestSize, "decompressed data : wrong size (%u != %u)",
Yann Colletededcfc2018-12-21 16:19:44 -08001932 (unsigned)outBuff.pos, (unsigned)totalTestSize);
Yann Collet53e17fb2016-08-17 01:39:22 +02001933 CHECK (inBuff.pos != cSize, "compressed data should be fully read")
Yann Colletd7883a22016-08-12 16:48:02 +02001934 { U64 const crcDest = XXH64(dstBuffer, totalTestSize, 0);
1935 if (crcDest!=crcOrig) findDiff(copyBuffer, dstBuffer, totalTestSize);
1936 CHECK (crcDest!=crcOrig, "decompressed data corrupted");
1937 } }
1938
1939 /*===== noisy/erroneous src decompression test =====*/
1940
1941 /* add some noise */
1942 { U32 const nbNoiseChunks = (FUZ_rand(&lseed) & 7) + 2;
1943 U32 nn; for (nn=0; nn<nbNoiseChunks; nn++) {
1944 size_t const randomNoiseSize = FUZ_randomLength(&lseed, maxSampleLog);
1945 size_t const noiseSize = MIN((cSize/3) , randomNoiseSize);
1946 size_t const noiseStart = FUZ_rand(&lseed) % (srcBufferSize - noiseSize);
1947 size_t const cStart = FUZ_rand(&lseed) % (cSize - noiseSize);
1948 memcpy(cBuffer+cStart, srcBuffer+noiseStart, noiseSize);
1949 } }
1950
1951 /* try decompression on noisy data */
Yann Colletdce78922017-06-21 15:53:42 -07001952 CHECK_Z( ZSTD_initDStream(zd_noise) ); /* note : no dictionary */
Yann Collet53e17fb2016-08-17 01:39:22 +02001953 { ZSTD_inBuffer inBuff = { cBuffer, cSize, 0 };
1954 ZSTD_outBuffer outBuff= { dstBuffer, dstBufferSize, 0 };
1955 while (outBuff.pos < dstBufferSize) {
Yann Colletd7883a22016-08-12 16:48:02 +02001956 size_t const randomCSrcSize = FUZ_randomLength(&lseed, maxSampleLog);
1957 size_t const randomDstSize = FUZ_randomLength(&lseed, maxSampleLog);
Yann Collet53e17fb2016-08-17 01:39:22 +02001958 size_t const adjustedDstSize = MIN(dstBufferSize - outBuff.pos, randomDstSize);
Yann Collet64bf8ff2017-01-27 17:25:07 -08001959 size_t const adjustedCSrcSize = MIN(cSize - inBuff.pos, randomCSrcSize);
Yann Collet53e17fb2016-08-17 01:39:22 +02001960 outBuff.size = outBuff.pos + adjustedDstSize;
Yann Collet64bf8ff2017-01-27 17:25:07 -08001961 inBuff.size = inBuff.pos + adjustedCSrcSize;
Yann Collet53e17fb2016-08-17 01:39:22 +02001962 { size_t const decompressError = ZSTD_decompressStream(zd, &outBuff, &inBuff);
Yann Colletd7883a22016-08-12 16:48:02 +02001963 if (ZSTD_isError(decompressError)) break; /* error correctly detected */
Yann Collet64bf8ff2017-01-27 17:25:07 -08001964 /* No forward progress possible */
1965 if (outBuff.pos < outBuff.size && inBuff.pos == cSize) break;
Yann Colletd7883a22016-08-12 16:48:02 +02001966 } } } }
1967 DISPLAY("\r%u fuzzer tests completed \n", testNb);
1968
1969_cleanup:
1970 ZSTD_freeCStream(zc);
1971 ZSTD_freeDStream(zd);
Yann Collet58d5dfe2016-09-25 01:34:03 +02001972 ZSTD_freeDStream(zd_noise);
Yann Colletd7883a22016-08-12 16:48:02 +02001973 free(cNoiseBuffer[0]);
1974 free(cNoiseBuffer[1]);
1975 free(cNoiseBuffer[2]);
1976 free(cNoiseBuffer[3]);
1977 free(cNoiseBuffer[4]);
1978 free(copyBuffer);
1979 free(cBuffer);
1980 free(dstBuffer);
1981 return result;
1982
1983_output_error:
1984 result = 1;
1985 goto _cleanup;
1986}
1987
Stella Lau73c73bf2017-08-21 12:41:19 -07001988/** If useOpaqueAPI, sets param in cctxParams.
1989 * Otherwise, sets the param in zc. */
1990static size_t setCCtxParameter(ZSTD_CCtx* zc, ZSTD_CCtx_params* cctxParams,
1991 ZSTD_cParameter param, unsigned value,
Yann Colletc9e8ee92018-06-18 19:20:37 -07001992 int useOpaqueAPI)
Stella Lau73c73bf2017-08-21 12:41:19 -07001993{
1994 if (useOpaqueAPI) {
Nick Terrell7ad7ba32019-02-19 17:41:56 -08001995 return ZSTD_CCtxParams_setParameter(cctxParams, param, value);
Stella Lau73c73bf2017-08-21 12:41:19 -07001996 } else {
1997 return ZSTD_CCtx_setParameter(zc, param, value);
1998 }
1999}
Yann Collet736788f2017-01-19 12:12:50 -08002000
Yann Colletd7a3bff2017-06-19 11:53:01 -07002001/* Tests for ZSTD_compress_generic() API */
Yann Colletededcfc2018-12-21 16:19:44 -08002002static int fuzzerTests_newAPI(U32 seed, int nbTests, int startTest,
Yann Colletc9e8ee92018-06-18 19:20:37 -07002003 double compressibility, int bigTests)
Yann Collet01743a32017-06-16 17:56:41 -07002004{
Yann Colletf99c2c12017-06-21 23:35:58 -07002005 U32 const maxSrcLog = bigTests ? 24 : 22;
Yann Collet01743a32017-06-16 17:56:41 -07002006 static const U32 maxSampleLog = 19;
2007 size_t const srcBufferSize = (size_t)1<<maxSrcLog;
2008 BYTE* cNoiseBuffer[5];
2009 size_t const copyBufferSize= srcBufferSize + (1<<maxSampleLog);
2010 BYTE* const copyBuffer = (BYTE*)malloc (copyBufferSize);
2011 size_t const cBufferSize = ZSTD_compressBound(srcBufferSize);
2012 BYTE* const cBuffer = (BYTE*)malloc (cBufferSize);
2013 size_t const dstBufferSize = srcBufferSize;
2014 BYTE* const dstBuffer = (BYTE*)malloc (dstBufferSize);
2015 U32 result = 0;
Yann Colletededcfc2018-12-21 16:19:44 -08002016 int testNb = 0;
Yann Collet01743a32017-06-16 17:56:41 -07002017 U32 coreSeed = seed;
2018 ZSTD_CCtx* zc = ZSTD_createCCtx(); /* will be reset sometimes */
2019 ZSTD_DStream* zd = ZSTD_createDStream(); /* will be reset sometimes */
2020 ZSTD_DStream* const zd_noise = ZSTD_createDStream();
Nick Terrell9a2f6f42017-11-29 19:11:12 -08002021 UTIL_time_t const startClock = UTIL_getTime();
Yann Colletd7a3bff2017-06-19 11:53:01 -07002022 const BYTE* dict = NULL; /* can keep same dict on 2 consecutive tests */
Yann Collet01743a32017-06-16 17:56:41 -07002023 size_t dictSize = 0;
2024 U32 oldTestLog = 0;
Yann Colletaa800c42017-09-27 18:00:15 -07002025 U32 windowLogMalus = 0; /* can survive between 2 loops */
2026 U32 const cLevelMax = bigTests ? (U32)ZSTD_maxCLevel()-1 : g_cLevelMax_smallTests;
2027 U32 const nbThreadsMax = bigTests ? 4 : 2;
Stella Lau023b24e2017-08-20 22:55:07 -07002028 ZSTD_CCtx_params* cctxParams = ZSTD_createCCtxParams();
Yann Collet01743a32017-06-16 17:56:41 -07002029
2030 /* allocations */
2031 cNoiseBuffer[0] = (BYTE*)malloc (srcBufferSize);
2032 cNoiseBuffer[1] = (BYTE*)malloc (srcBufferSize);
2033 cNoiseBuffer[2] = (BYTE*)malloc (srcBufferSize);
2034 cNoiseBuffer[3] = (BYTE*)malloc (srcBufferSize);
2035 cNoiseBuffer[4] = (BYTE*)malloc (srcBufferSize);
2036 CHECK (!cNoiseBuffer[0] || !cNoiseBuffer[1] || !cNoiseBuffer[2] || !cNoiseBuffer[3] || !cNoiseBuffer[4] ||
2037 !copyBuffer || !dstBuffer || !cBuffer || !zc || !zd || !zd_noise ,
2038 "Not enough memory, fuzzer tests cancelled");
2039
2040 /* Create initial samples */
2041 RDG_genBuffer(cNoiseBuffer[0], srcBufferSize, 0.00, 0., coreSeed); /* pure noise */
2042 RDG_genBuffer(cNoiseBuffer[1], srcBufferSize, 0.05, 0., coreSeed); /* barely compressible */
2043 RDG_genBuffer(cNoiseBuffer[2], srcBufferSize, compressibility, 0., coreSeed);
2044 RDG_genBuffer(cNoiseBuffer[3], srcBufferSize, 0.95, 0., coreSeed); /* highly compressible */
2045 RDG_genBuffer(cNoiseBuffer[4], srcBufferSize, 1.00, 0., coreSeed); /* sparse content */
2046 memset(copyBuffer, 0x65, copyBufferSize); /* make copyBuffer considered initialized */
Yann Colletdce78922017-06-21 15:53:42 -07002047 CHECK_Z( ZSTD_initDStream_usingDict(zd, NULL, 0) ); /* ensure at least one init */
Yann Collet01743a32017-06-16 17:56:41 -07002048
2049 /* catch up testNb */
2050 for (testNb=1; testNb < startTest; testNb++)
2051 FUZ_rand(&coreSeed);
2052
2053 /* test loop */
Nick Terrell9a2f6f42017-11-29 19:11:12 -08002054 for ( ; (testNb <= nbTests) || (UTIL_clockSpanMicro(startClock) < g_clockTime) ; testNb++ ) {
Yann Collet01743a32017-06-16 17:56:41 -07002055 U32 lseed;
Yann Colletc9e8ee92018-06-18 19:20:37 -07002056 int opaqueAPI;
Yann Collet01743a32017-06-16 17:56:41 -07002057 const BYTE* srcBuffer;
2058 size_t totalTestSize, totalGenSize, cSize;
2059 XXH64_state_t xxhState;
2060 U64 crcOrig;
2061 U32 resetAllowed = 1;
2062 size_t maxTestSize;
Nick Terrellca778222018-04-25 16:32:29 -07002063 ZSTD_parameters savedParams;
Nick Terrell9ab92292020-10-01 15:02:15 -07002064 int isRefPrefix = 0;
2065 U64 pledgedSrcSize = ZSTD_CONTENTSIZE_UNKNOWN;
Yann Collet01743a32017-06-16 17:56:41 -07002066
2067 /* init */
2068 if (nbTests >= testNb) { DISPLAYUPDATE(2, "\r%6u/%6u ", testNb, nbTests); }
2069 else { DISPLAYUPDATE(2, "\r%6u ", testNb); }
2070 FUZ_rand(&coreSeed);
2071 lseed = coreSeed ^ prime32;
Yann Collet9b5b47a2017-09-28 01:25:40 -07002072 DISPLAYLEVEL(5, " *** Test %u *** \n", testNb);
Yann Colletc9e8ee92018-06-18 19:20:37 -07002073 opaqueAPI = FUZ_rand(&lseed) & 1;
Yann Collet01743a32017-06-16 17:56:41 -07002074
2075 /* states full reset (deliberately not synchronized) */
2076 /* some issues can only happen when reusing states */
2077 if ((FUZ_rand(&lseed) & 0xFF) == 131) {
2078 DISPLAYLEVEL(5, "Creating new context \n");
2079 ZSTD_freeCCtx(zc);
2080 zc = ZSTD_createCCtx();
Yann Collet62469c92018-06-19 20:14:03 -07002081 CHECK(zc == NULL, "ZSTD_createCCtx allocation error");
2082 resetAllowed = 0;
Yann Collet01743a32017-06-16 17:56:41 -07002083 }
2084 if ((FUZ_rand(&lseed) & 0xFF) == 132) {
2085 ZSTD_freeDStream(zd);
2086 zd = ZSTD_createDStream();
Yann Collet62469c92018-06-19 20:14:03 -07002087 CHECK(zd == NULL, "ZSTD_createDStream allocation error");
Yann Collet01743a32017-06-16 17:56:41 -07002088 ZSTD_initDStream_usingDict(zd, NULL, 0); /* ensure at least one init */
2089 }
2090
2091 /* srcBuffer selection [0-4] */
2092 { U32 buffNb = FUZ_rand(&lseed) & 0x7F;
2093 if (buffNb & 7) buffNb=2; /* most common : compressible (P) */
2094 else {
2095 buffNb >>= 3;
2096 if (buffNb & 7) {
2097 const U32 tnb[2] = { 1, 3 }; /* barely/highly compressible */
2098 buffNb = tnb[buffNb >> 3];
2099 } else {
2100 const U32 tnb[2] = { 0, 4 }; /* not compressible / sparse */
2101 buffNb = tnb[buffNb >> 3];
2102 } }
2103 srcBuffer = cNoiseBuffer[buffNb];
2104 }
2105
2106 /* compression init */
Yann Colletb7372932017-06-27 15:49:12 -07002107 CHECK_Z( ZSTD_CCtx_loadDictionary(zc, NULL, 0) ); /* cancel previous dict /*/
Yann Collet01743a32017-06-16 17:56:41 -07002108 if ((FUZ_rand(&lseed)&1) /* at beginning, to keep same nb of rand */
Yann Collet2108dec2018-06-01 15:18:32 -07002109 && oldTestLog /* at least one test happened */
2110 && resetAllowed) {
2111 /* just set a compression level */
Yann Collet01743a32017-06-16 17:56:41 -07002112 maxTestSize = FUZ_randomLength(&lseed, oldTestLog+2);
2113 if (maxTestSize >= srcBufferSize) maxTestSize = srcBufferSize-1;
Yann Collet01743a32017-06-16 17:56:41 -07002114 { int const compressionLevel = (FUZ_rand(&lseed) % 5) + 1;
Yann Collet2108dec2018-06-01 15:18:32 -07002115 DISPLAYLEVEL(5, "t%u : compression level : %i \n", testNb, compressionLevel);
Yann Collet3583d192018-12-05 17:26:02 -08002116 CHECK_Z (setCCtxParameter(zc, cctxParams, ZSTD_c_compressionLevel, compressionLevel, opaqueAPI) );
Yann Collet01743a32017-06-16 17:56:41 -07002117 }
2118 } else {
2119 U32 const testLog = FUZ_rand(&lseed) % maxSrcLog;
2120 U32 const dictLog = FUZ_rand(&lseed) % maxSrcLog;
Yann Colletbfc2f002017-06-21 17:57:14 -07002121 U32 const cLevelCandidate = (FUZ_rand(&lseed) %
Yann Collet01743a32017-06-16 17:56:41 -07002122 (ZSTD_maxCLevel() -
Yann Collet9fe50ed2017-09-28 01:42:06 -07002123 (MAX(testLog, dictLog) / 2))) +
Yann Collet01743a32017-06-16 17:56:41 -07002124 1;
Yann Colletededcfc2018-12-21 16:19:44 -08002125 int const cLevel = MIN(cLevelCandidate, cLevelMax);
2126 DISPLAYLEVEL(5, "t%i: base cLevel : %u \n", testNb, cLevel);
Yann Collet01743a32017-06-16 17:56:41 -07002127 maxTestSize = FUZ_rLogLength(&lseed, testLog);
Yann Colletededcfc2018-12-21 16:19:44 -08002128 DISPLAYLEVEL(5, "t%i: maxTestSize : %u \n", testNb, (unsigned)maxTestSize);
Yann Collet01743a32017-06-16 17:56:41 -07002129 oldTestLog = testLog;
2130 /* random dictionary selection */
2131 dictSize = ((FUZ_rand(&lseed)&63)==1) ? FUZ_rLogLength(&lseed, dictLog) : 0;
2132 { size_t const dictStart = FUZ_rand(&lseed) % (srcBufferSize - dictSize);
2133 dict = srcBuffer + dictStart;
Yann Colletd7a3bff2017-06-19 11:53:01 -07002134 if (!dictSize) dict=NULL;
Yann Collet01743a32017-06-16 17:56:41 -07002135 }
Nick Terrell9ab92292020-10-01 15:02:15 -07002136 pledgedSrcSize = (FUZ_rand(&lseed) & 3) ? ZSTD_CONTENTSIZE_UNKNOWN : maxTestSize;
2137 { ZSTD_compressionParameters cParams = ZSTD_getCParams(cLevel, pledgedSrcSize, dictSize);
Nick Terrell7ee910e2018-09-27 13:55:24 -07002138 const U32 windowLogMax = bigTests ? 24 : 20;
2139 const U32 searchLogMax = bigTests ? 15 : 13;
Yann Collet2108dec2018-06-01 15:18:32 -07002140 if (dictSize)
2141 DISPLAYLEVEL(5, "t%u: with dictionary of size : %zu \n", testNb, dictSize);
Yann Collet01743a32017-06-16 17:56:41 -07002142
2143 /* mess with compression parameters */
2144 cParams.windowLog += (FUZ_rand(&lseed) & 3) - 1;
Nick Terrellc233bdb2017-09-22 14:04:39 -07002145 cParams.windowLog = MIN(windowLogMax, cParams.windowLog);
Yann Collet01743a32017-06-16 17:56:41 -07002146 cParams.hashLog += (FUZ_rand(&lseed) & 3) - 1;
2147 cParams.chainLog += (FUZ_rand(&lseed) & 3) - 1;
2148 cParams.searchLog += (FUZ_rand(&lseed) & 3) - 1;
Nick Terrell7ee910e2018-09-27 13:55:24 -07002149 cParams.searchLog = MIN(searchLogMax, cParams.searchLog);
Yann Collete874dac2018-11-20 14:56:07 -08002150 cParams.minMatch += (FUZ_rand(&lseed) & 3) - 1;
Yann Colletaa800c42017-09-27 18:00:15 -07002151 cParams.targetLength = (U32)((cParams.targetLength + 1 ) * (0.5 + ((double)(FUZ_rand(&lseed) & 127) / 128)));
Yann Collet2108dec2018-06-01 15:18:32 -07002152 cParams = ZSTD_adjustCParams(cParams, pledgedSrcSize, dictSize);
Yann Collet01743a32017-06-16 17:56:41 -07002153
Yann Colletaa800c42017-09-27 18:00:15 -07002154 if (FUZ_rand(&lseed) & 1) {
Yann Colletd3c59ed2017-11-29 16:42:20 -08002155 DISPLAYLEVEL(5, "t%u: windowLog : %u \n", testNb, cParams.windowLog);
Yann Collet3583d192018-12-05 17:26:02 -08002156 CHECK_Z( setCCtxParameter(zc, cctxParams, ZSTD_c_windowLog, cParams.windowLog, opaqueAPI) );
Yann Colletaa800c42017-09-27 18:00:15 -07002157 assert(cParams.windowLog >= ZSTD_WINDOWLOG_MIN); /* guaranteed by ZSTD_adjustCParams() */
2158 windowLogMalus = (cParams.windowLog - ZSTD_WINDOWLOG_MIN) / 5;
2159 }
Yann Collet9b5b47a2017-09-28 01:25:40 -07002160 if (FUZ_rand(&lseed) & 1) {
Yann Collet9b5b47a2017-09-28 01:25:40 -07002161 DISPLAYLEVEL(5, "t%u: hashLog : %u \n", testNb, cParams.hashLog);
Yann Collet3583d192018-12-05 17:26:02 -08002162 CHECK_Z( setCCtxParameter(zc, cctxParams, ZSTD_c_hashLog, cParams.hashLog, opaqueAPI) );
Yann Collet9b5b47a2017-09-28 01:25:40 -07002163 }
2164 if (FUZ_rand(&lseed) & 1) {
Yann Collet9b5b47a2017-09-28 01:25:40 -07002165 DISPLAYLEVEL(5, "t%u: chainLog : %u \n", testNb, cParams.chainLog);
Yann Collet3583d192018-12-05 17:26:02 -08002166 CHECK_Z( setCCtxParameter(zc, cctxParams, ZSTD_c_chainLog, cParams.chainLog, opaqueAPI) );
Yann Collet9b5b47a2017-09-28 01:25:40 -07002167 }
Yann Collet3583d192018-12-05 17:26:02 -08002168 if (FUZ_rand(&lseed) & 1) CHECK_Z( setCCtxParameter(zc, cctxParams, ZSTD_c_searchLog, cParams.searchLog, opaqueAPI) );
2169 if (FUZ_rand(&lseed) & 1) CHECK_Z( setCCtxParameter(zc, cctxParams, ZSTD_c_minMatch, cParams.minMatch, opaqueAPI) );
2170 if (FUZ_rand(&lseed) & 1) CHECK_Z( setCCtxParameter(zc, cctxParams, ZSTD_c_targetLength, cParams.targetLength, opaqueAPI) );
Yann Collet01743a32017-06-16 17:56:41 -07002171
Stella Lau9e406022017-09-06 08:39:46 -07002172 /* mess with long distance matching parameters */
Yann Colletd3c59ed2017-11-29 16:42:20 -08002173 if (bigTests) {
Yann Collet3583d192018-12-05 17:26:02 -08002174 if (FUZ_rand(&lseed) & 1) CHECK_Z( setCCtxParameter(zc, cctxParams, ZSTD_c_enableLongDistanceMatching, FUZ_rand(&lseed) & 63, opaqueAPI) );
2175 if (FUZ_rand(&lseed) & 3) CHECK_Z( setCCtxParameter(zc, cctxParams, ZSTD_c_ldmHashLog, FUZ_randomClampedLength(&lseed, ZSTD_HASHLOG_MIN, 23), opaqueAPI) );
2176 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) );
2177 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) );
2178 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 -07002179 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 -08002180 }
Stella Lau6a546ef2017-07-28 15:51:33 -07002181
Yann Collet01743a32017-06-16 17:56:41 -07002182 /* mess with frame parameters */
Yann Colletebd955e2018-01-23 13:12:40 -08002183 if (FUZ_rand(&lseed) & 1) {
Yann Colletededcfc2018-12-21 16:19:44 -08002184 int const checksumFlag = FUZ_rand(&lseed) & 1;
Yann Colletebd955e2018-01-23 13:12:40 -08002185 DISPLAYLEVEL(5, "t%u: frame checksum : %u \n", testNb, checksumFlag);
Yann Collet3583d192018-12-05 17:26:02 -08002186 CHECK_Z( setCCtxParameter(zc, cctxParams, ZSTD_c_checksumFlag, checksumFlag, opaqueAPI) );
Yann Colletebd955e2018-01-23 13:12:40 -08002187 }
Yann Collet3583d192018-12-05 17:26:02 -08002188 if (FUZ_rand(&lseed) & 1) CHECK_Z( setCCtxParameter(zc, cctxParams, ZSTD_c_dictIDFlag, FUZ_rand(&lseed) & 1, opaqueAPI) );
2189 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 -08002190 if (FUZ_rand(&lseed) & 1) {
Yann Colletededcfc2018-12-21 16:19:44 -08002191 DISPLAYLEVEL(5, "t%u: pledgedSrcSize : %u \n", testNb, (unsigned)pledgedSrcSize);
Yann Colletd3c59ed2017-11-29 16:42:20 -08002192 CHECK_Z( ZSTD_CCtx_setPledgedSrcSize(zc, pledgedSrcSize) );
Nick Terrell9ab92292020-10-01 15:02:15 -07002193 } else {
2194 pledgedSrcSize = ZSTD_CONTENTSIZE_UNKNOWN;
Yann Colletd3c59ed2017-11-29 16:42:20 -08002195 }
Yann Collet01743a32017-06-16 17:56:41 -07002196
Josh Sorefa880ca22019-04-12 14:18:11 -04002197 /* multi-threading parameters. Only adjust occasionally for small tests. */
Nick Terrelld8c73cd2018-09-27 15:49:31 -07002198 if (bigTests || (FUZ_rand(&lseed) & 0xF) == 0xF) {
2199 U32 const nbThreadsCandidate = (FUZ_rand(&lseed) & 4) + 1;
Yann Colletaa800c42017-09-27 18:00:15 -07002200 U32 const nbThreadsAdjusted = (windowLogMalus < nbThreadsCandidate) ? nbThreadsCandidate - windowLogMalus : 1;
Yann Colletededcfc2018-12-21 16:19:44 -08002201 int const nbThreads = MIN(nbThreadsAdjusted, nbThreadsMax);
2202 DISPLAYLEVEL(5, "t%i: nbThreads : %u \n", testNb, nbThreads);
Yann Collet3583d192018-12-05 17:26:02 -08002203 CHECK_Z( setCCtxParameter(zc, cctxParams, ZSTD_c_nbWorkers, nbThreads, opaqueAPI) );
Yann Collet01743a32017-06-16 17:56:41 -07002204 if (nbThreads > 1) {
Yann Colleted1d0392017-06-19 11:07:33 -07002205 U32 const jobLog = FUZ_rand(&lseed) % (testLog+1);
Yann Collet9b784de2018-12-11 16:55:33 -08002206 CHECK_Z( setCCtxParameter(zc, cctxParams, ZSTD_c_overlapLog, FUZ_rand(&lseed) % 10, opaqueAPI) );
Yann Collet3583d192018-12-05 17:26:02 -08002207 CHECK_Z( setCCtxParameter(zc, cctxParams, ZSTD_c_jobSize, (U32)FUZ_rLogLength(&lseed, jobLog), opaqueAPI) );
Stella Lau023b24e2017-08-20 22:55:07 -07002208 }
2209 }
Nick Terrell71fe78c2018-11-14 13:53:14 -08002210 /* Enable rsyncable mode 1 in 4 times. */
Nick Terrellede4f972020-10-05 17:37:19 -07002211 {
2212 int const rsyncable = (FUZ_rand(&lseed) % 4 == 0);
2213 DISPLAYLEVEL(5, "t%u: rsyncable : %d \n", testNb, rsyncable);
2214 setCCtxParameter(zc, cctxParams, ZSTD_c_rsyncable, rsyncable, opaqueAPI);
2215 }
Stella Lau023b24e2017-08-20 22:55:07 -07002216
Yann Collet3583d192018-12-05 17:26:02 -08002217 if (FUZ_rand(&lseed) & 1) CHECK_Z( setCCtxParameter(zc, cctxParams, ZSTD_c_forceMaxWindow, FUZ_rand(&lseed) & 1, opaqueAPI) );
Stella Lau023b24e2017-08-20 22:55:07 -07002218
2219 /* Apply parameters */
Yann Colletc9e8ee92018-06-18 19:20:37 -07002220 if (opaqueAPI) {
Yann Collet2108dec2018-06-01 15:18:32 -07002221 DISPLAYLEVEL(5, "t%u: applying CCtxParams \n", testNb);
Stella Lau82d636b2017-08-29 18:03:06 -07002222 CHECK_Z (ZSTD_CCtx_setParametersUsingCCtxParams(zc, cctxParams) );
Stella Lau73c73bf2017-08-21 12:41:19 -07002223 }
Stella Lau023b24e2017-08-20 22:55:07 -07002224
2225 if (FUZ_rand(&lseed) & 1) {
Stella Laueb7bbab2017-08-25 10:48:07 -07002226 if (FUZ_rand(&lseed) & 1) {
2227 CHECK_Z( ZSTD_CCtx_loadDictionary(zc, dict, dictSize) );
2228 } else {
2229 CHECK_Z( ZSTD_CCtx_loadDictionary_byReference(zc, dict, dictSize) );
2230 }
Stella Lau73c73bf2017-08-21 12:41:19 -07002231 } else {
Nick Terrell9ab92292020-10-01 15:02:15 -07002232 isRefPrefix = 1;
Stella Lau023b24e2017-08-20 22:55:07 -07002233 CHECK_Z( ZSTD_CCtx_refPrefix(zc, dict, dictSize) );
2234 }
2235 } }
Yann Collet01743a32017-06-16 17:56:41 -07002236
Nick Terrellca778222018-04-25 16:32:29 -07002237 CHECK_Z(getCCtxParams(zc, &savedParams));
2238
Yann Collet01743a32017-06-16 17:56:41 -07002239 /* multi-segments compression test */
Nick Terrell9ab92292020-10-01 15:02:15 -07002240 { int iter;
2241 int const startSeed = lseed;
2242 XXH64_hash_t compressedCrcs[2];
2243 for (iter = 0; iter < 2; ++iter, lseed = startSeed) {
2244 ZSTD_outBuffer outBuff = { cBuffer, cBufferSize, 0 } ;
2245 int const singlePass = (FUZ_rand(&lseed) & 3) == 0;
2246 int nbWorkers;
Yann Collet01743a32017-06-16 17:56:41 -07002247
Nick Terrell9ab92292020-10-01 15:02:15 -07002248 XXH64_reset(&xxhState, 0);
Yann Collet01743a32017-06-16 17:56:41 -07002249
Nick Terrell9ab92292020-10-01 15:02:15 -07002250 CHECK_Z( ZSTD_CCtx_setPledgedSrcSize(zc, pledgedSrcSize) );
2251 if (isRefPrefix) {
2252 DISPLAYLEVEL(6, "t%u: Reloading prefix\n", testNb);
2253 /* Need to reload the prefix because it gets dropped after one compression */
2254 CHECK_Z( ZSTD_CCtx_refPrefix(zc, dict, dictSize) );
2255 }
2256
2257 /* Adjust number of workers occassionally - result must be deterministic independent of nbWorkers */
2258 CHECK_Z(ZSTD_CCtx_getParameter(zc, ZSTD_c_nbWorkers, &nbWorkers));
2259 if (nbWorkers > 0 && (FUZ_rand(&lseed) & 7) == 0) {
2260 DISPLAYLEVEL(6, "t%u: Modify nbWorkers: %d -> %d \n", testNb, nbWorkers, nbWorkers + iter);
2261 CHECK_Z(ZSTD_CCtx_setParameter(zc, ZSTD_c_nbWorkers, nbWorkers + iter));
2262 }
2263
2264 if (singlePass) {
2265 ZSTD_inBuffer inBuff = { srcBuffer, maxTestSize, 0 };
2266 CHECK_Z(ZSTD_compressStream2(zc, &outBuff, &inBuff, ZSTD_e_end));
2267 DISPLAYLEVEL(6, "t%u: Single pass compression: consumed %u bytes ; produced %u bytes \n",
2268 testNb, (unsigned)inBuff.pos, (unsigned)outBuff.pos);
2269 CHECK(inBuff.pos != inBuff.size, "Input not consumed!");
2270 crcOrig = XXH64(srcBuffer, maxTestSize, 0);
2271 totalTestSize = maxTestSize;
2272 } else {
2273 outBuff.size = 0;
2274 for (totalTestSize=0 ; (totalTestSize < maxTestSize) ; ) {
2275 /* compress random chunks into randomly sized dst buffers */
2276 size_t const randomSrcSize = FUZ_randomLength(&lseed, maxSampleLog);
2277 size_t const srcSize = MIN(maxTestSize-totalTestSize, randomSrcSize);
2278 size_t const srcStart = FUZ_rand(&lseed) % (srcBufferSize - srcSize);
2279 ZSTD_EndDirective const flush = (FUZ_rand(&lseed) & 15) ? ZSTD_e_continue : ZSTD_e_flush;
2280 ZSTD_inBuffer inBuff = { srcBuffer+srcStart, srcSize, 0 };
2281 int forwardProgress;
2282 do {
2283 size_t const ipos = inBuff.pos;
2284 size_t const opos = outBuff.pos;
2285 size_t ret;
2286 if (outBuff.pos == outBuff.size) {
2287 size_t const randomDstSize = FUZ_randomLength(&lseed, maxSampleLog+1);
2288 size_t const dstBuffSize = MIN(cBufferSize - outBuff.pos, randomDstSize);
2289 outBuff.size = outBuff.pos + dstBuffSize;
2290 }
2291 CHECK_Z( ret = ZSTD_compressStream2(zc, &outBuff, &inBuff, flush) );
2292 DISPLAYLEVEL(6, "t%u: compress consumed %u bytes (total : %u) ; flush: %u (total : %u) \n",
2293 testNb, (unsigned)inBuff.pos, (unsigned)(totalTestSize + inBuff.pos), (unsigned)flush, (unsigned)outBuff.pos);
2294
2295 /* We've completed the flush */
2296 if (flush == ZSTD_e_flush && ret == 0)
2297 break;
2298
2299 /* Ensure maximal forward progress for determinism */
2300 forwardProgress = (inBuff.pos != ipos) || (outBuff.pos != opos);
2301 } while (forwardProgress);
2302
2303 XXH64_update(&xxhState, srcBuffer+srcStart, inBuff.pos);
2304 memcpy(copyBuffer+totalTestSize, srcBuffer+srcStart, inBuff.pos);
2305 totalTestSize += inBuff.pos;
2306 }
2307
2308 /* final frame epilogue */
2309 { size_t remainingToFlush = 1;
2310 while (remainingToFlush) {
2311 ZSTD_inBuffer inBuff = { NULL, 0, 0 };
2312 size_t const randomDstSize = FUZ_randomLength(&lseed, maxSampleLog+1);
2313 size_t const adjustedDstSize = MIN(cBufferSize - outBuff.pos, randomDstSize);
2314 outBuff.size = outBuff.pos + adjustedDstSize;
2315 DISPLAYLEVEL(6, "t%u: End-flush into dst buffer of size %u \n", testNb, (unsigned)adjustedDstSize);
2316 /* ZSTD_e_end guarantees maximal forward progress */
2317 remainingToFlush = ZSTD_compressStream2(zc, &outBuff, &inBuff, ZSTD_e_end);
2318 DISPLAYLEVEL(6, "t%u: Total flushed so far : %u bytes \n", testNb, (unsigned)outBuff.pos);
2319 CHECK( ZSTD_isError(remainingToFlush),
2320 "ZSTD_compressStream2 w/ ZSTD_e_end error : %s",
2321 ZSTD_getErrorName(remainingToFlush) );
2322 } }
2323 crcOrig = XXH64_digest(&xxhState);
2324 }
2325 cSize = outBuff.pos;
2326 compressedCrcs[iter] = XXH64(cBuffer, cSize, 0);
2327 DISPLAYLEVEL(5, "Frame completed : %zu bytes \n", cSize);
Yann Colleted1d0392017-06-19 11:07:33 -07002328 }
Nick Terrell9ab92292020-10-01 15:02:15 -07002329 CHECK(!(compressedCrcs[0] == compressedCrcs[1]), "Compression is not deterministic!");
Yann Collet01743a32017-06-16 17:56:41 -07002330 }
2331
Nick Terrellca778222018-04-25 16:32:29 -07002332 CHECK(badParameters(zc, savedParams), "CCtx params are wrong");
2333
Yann Collet01743a32017-06-16 17:56:41 -07002334 /* multi - fragments decompression test */
2335 if (!dictSize /* don't reset if dictionary : could be different */ && (FUZ_rand(&lseed) & 1)) {
Yann Colletededcfc2018-12-21 16:19:44 -08002336 DISPLAYLEVEL(5, "resetting DCtx (dict:%p) \n", dict);
Yann Colletdce78922017-06-21 15:53:42 -07002337 CHECK_Z( ZSTD_resetDStream(zd) );
Yann Collet01743a32017-06-16 17:56:41 -07002338 } else {
Yann Collet2108dec2018-06-01 15:18:32 -07002339 if (dictSize)
2340 DISPLAYLEVEL(5, "using dictionary of size %zu \n", dictSize);
Yann Colletdce78922017-06-21 15:53:42 -07002341 CHECK_Z( ZSTD_initDStream_usingDict(zd, dict, dictSize) );
Yann Collet01743a32017-06-16 17:56:41 -07002342 }
2343 { size_t decompressionResult = 1;
2344 ZSTD_inBuffer inBuff = { cBuffer, cSize, 0 };
2345 ZSTD_outBuffer outBuff= { dstBuffer, dstBufferSize, 0 };
2346 for (totalGenSize = 0 ; decompressionResult ; ) {
2347 size_t const readCSrcSize = FUZ_randomLength(&lseed, maxSampleLog);
2348 size_t const randomDstSize = FUZ_randomLength(&lseed, maxSampleLog);
2349 size_t const dstBuffSize = MIN(dstBufferSize - totalGenSize, randomDstSize);
2350 inBuff.size = inBuff.pos + readCSrcSize;
Yann Colletbfabd1d2017-09-27 01:01:11 -07002351 outBuff.size = outBuff.pos + dstBuffSize;
Yann Collet4f7c8962018-01-23 18:00:51 -08002352 DISPLAYLEVEL(6, "decompression presented %u new bytes (pos:%u/%u)\n",
Yann Colletededcfc2018-12-21 16:19:44 -08002353 (unsigned)readCSrcSize, (unsigned)inBuff.pos, (unsigned)cSize);
Yann Collet01743a32017-06-16 17:56:41 -07002354 decompressionResult = ZSTD_decompressStream(zd, &outBuff, &inBuff);
Yann Collet4f7c8962018-01-23 18:00:51 -08002355 DISPLAYLEVEL(6, "so far: consumed = %u, produced = %u \n",
Yann Colletededcfc2018-12-21 16:19:44 -08002356 (unsigned)inBuff.pos, (unsigned)outBuff.pos);
Yann Colletebd955e2018-01-23 13:12:40 -08002357 if (ZSTD_isError(decompressionResult)) {
2358 DISPLAY("ZSTD_decompressStream error : %s \n", ZSTD_getErrorName(decompressionResult));
2359 findDiff(copyBuffer, dstBuffer, totalTestSize);
2360 }
Yann Collet01743a32017-06-16 17:56:41 -07002361 CHECK (ZSTD_isError(decompressionResult), "decompression error : %s", ZSTD_getErrorName(decompressionResult));
Yann Colletededcfc2018-12-21 16:19:44 -08002362 CHECK (inBuff.pos > cSize, "ZSTD_decompressStream consumes too much input : %u > %u ", (unsigned)inBuff.pos, (unsigned)cSize);
Yann Collet01743a32017-06-16 17:56:41 -07002363 }
Yann Colletededcfc2018-12-21 16:19:44 -08002364 CHECK (inBuff.pos != cSize, "compressed data should be fully read (%u != %u)", (unsigned)inBuff.pos, (unsigned)cSize);
2365 CHECK (outBuff.pos != totalTestSize, "decompressed data : wrong size (%u != %u)", (unsigned)outBuff.pos, (unsigned)totalTestSize);
Yann Collet01743a32017-06-16 17:56:41 -07002366 { U64 const crcDest = XXH64(dstBuffer, totalTestSize, 0);
2367 if (crcDest!=crcOrig) findDiff(copyBuffer, dstBuffer, totalTestSize);
2368 CHECK (crcDest!=crcOrig, "decompressed data corrupted");
2369 } }
2370
2371 /*===== noisy/erroneous src decompression test =====*/
2372
2373 /* add some noise */
2374 { U32 const nbNoiseChunks = (FUZ_rand(&lseed) & 7) + 2;
2375 U32 nn; for (nn=0; nn<nbNoiseChunks; nn++) {
2376 size_t const randomNoiseSize = FUZ_randomLength(&lseed, maxSampleLog);
2377 size_t const noiseSize = MIN((cSize/3) , randomNoiseSize);
2378 size_t const noiseStart = FUZ_rand(&lseed) % (srcBufferSize - noiseSize);
2379 size_t const cStart = FUZ_rand(&lseed) % (cSize - noiseSize);
2380 memcpy(cBuffer+cStart, srcBuffer+noiseStart, noiseSize);
2381 } }
2382
2383 /* try decompression on noisy data */
Yann Colletdce78922017-06-21 15:53:42 -07002384 CHECK_Z( ZSTD_initDStream(zd_noise) ); /* note : no dictionary */
Yann Collet01743a32017-06-16 17:56:41 -07002385 { ZSTD_inBuffer inBuff = { cBuffer, cSize, 0 };
2386 ZSTD_outBuffer outBuff= { dstBuffer, dstBufferSize, 0 };
2387 while (outBuff.pos < dstBufferSize) {
2388 size_t const randomCSrcSize = FUZ_randomLength(&lseed, maxSampleLog);
2389 size_t const randomDstSize = FUZ_randomLength(&lseed, maxSampleLog);
2390 size_t const adjustedDstSize = MIN(dstBufferSize - outBuff.pos, randomDstSize);
2391 size_t const adjustedCSrcSize = MIN(cSize - inBuff.pos, randomCSrcSize);
2392 outBuff.size = outBuff.pos + adjustedDstSize;
2393 inBuff.size = inBuff.pos + adjustedCSrcSize;
2394 { size_t const decompressError = ZSTD_decompressStream(zd, &outBuff, &inBuff);
2395 if (ZSTD_isError(decompressError)) break; /* error correctly detected */
Yann Colleted1d0392017-06-19 11:07:33 -07002396 /* Good so far, but no more progress possible */
Yann Collet01743a32017-06-16 17:56:41 -07002397 if (outBuff.pos < outBuff.size && inBuff.pos == cSize) break;
2398 } } } }
Yann Collet8dee0ec2017-06-18 23:25:15 -07002399 DISPLAY("\r%u fuzzer tests completed \n", testNb-1);
Yann Collet01743a32017-06-16 17:56:41 -07002400
2401_cleanup:
2402 ZSTD_freeCCtx(zc);
2403 ZSTD_freeDStream(zd);
2404 ZSTD_freeDStream(zd_noise);
Stella Lau023b24e2017-08-20 22:55:07 -07002405 ZSTD_freeCCtxParams(cctxParams);
Yann Collet01743a32017-06-16 17:56:41 -07002406 free(cNoiseBuffer[0]);
2407 free(cNoiseBuffer[1]);
2408 free(cNoiseBuffer[2]);
2409 free(cNoiseBuffer[3]);
2410 free(cNoiseBuffer[4]);
2411 free(copyBuffer);
2412 free(cBuffer);
2413 free(dstBuffer);
2414 return result;
2415
2416_output_error:
2417 result = 1;
2418 goto _cleanup;
2419}
2420
Yann Colletd7883a22016-08-12 16:48:02 +02002421/*-*******************************************************
2422* Command line
2423*********************************************************/
Nick Terrellf2d6db42018-09-27 15:13:43 -07002424static int FUZ_usage(const char* programName)
Yann Colletd7883a22016-08-12 16:48:02 +02002425{
2426 DISPLAY( "Usage :\n");
2427 DISPLAY( " %s [args]\n", programName);
2428 DISPLAY( "\n");
2429 DISPLAY( "Arguments :\n");
Taylor Braun-Jones3cbc3d32020-03-23 17:46:56 -04002430 DISPLAY( " -i# : Number of tests (default:%u)\n", nbTestsDefault);
2431 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 +02002432 DISPLAY( " -s# : Select seed (default:prompt user)\n");
2433 DISPLAY( " -t# : Select starting test number (default:0)\n");
2434 DISPLAY( " -P# : Select compressibility in %% (default:%i%%)\n", FUZ_COMPRESSIBILITY_DEFAULT);
2435 DISPLAY( " -v : verbose\n");
2436 DISPLAY( " -p : pause at the end\n");
2437 DISPLAY( " -h : display help and exit\n");
2438 return 0;
2439}
2440
Nick Terrellc51a9e72020-10-01 18:47:54 -07002441typedef enum { simple_api, advanced_api } e_api;
Yann Colletd7883a22016-08-12 16:48:02 +02002442
2443int main(int argc, const char** argv)
2444{
Yann Colletbd88f632017-11-27 12:15:23 -08002445 U32 seed = 0;
2446 int seedset = 0;
Yann Colletd7883a22016-08-12 16:48:02 +02002447 int nbTests = nbTestsDefault;
2448 int testNb = 0;
2449 int proba = FUZ_COMPRESSIBILITY_DEFAULT;
Yann Colletbd88f632017-11-27 12:15:23 -08002450 int result = 0;
Yann Collet19d670b2017-01-19 15:32:07 -08002451 int mainPause = 0;
Yann Colletafb0aca2017-06-29 18:19:09 -07002452 int bigTests = (sizeof(size_t) == 8);
Yann Collet01743a32017-06-16 17:56:41 -07002453 e_api selected_api = simple_api;
Yann Collet19d670b2017-01-19 15:32:07 -08002454 const char* const programName = argv[0];
Yann Colletbd88f632017-11-27 12:15:23 -08002455 int argNb;
Yann Colletd7883a22016-08-12 16:48:02 +02002456
2457 /* Check command line */
2458 for(argNb=1; argNb<argc; argNb++) {
2459 const char* argument = argv[argNb];
Yann Colletbd88f632017-11-27 12:15:23 -08002460 assert(argument != NULL);
Yann Colletd7883a22016-08-12 16:48:02 +02002461
2462 /* Parsing commands. Aggregated commands are allowed */
2463 if (argument[0]=='-') {
Yann Colletd7883a22016-08-12 16:48:02 +02002464
Yann Collet47c6a952017-09-28 18:27:22 -07002465 if (!strcmp(argument, "--newapi")) { selected_api=advanced_api; testNb += !testNb; continue; }
Sean Purcell7ebf2de2017-03-20 11:25:00 -07002466 if (!strcmp(argument, "--no-big-tests")) { bigTests=0; continue; }
Yann Collet19d670b2017-01-19 15:32:07 -08002467
2468 argument++;
Yann Colletd7883a22016-08-12 16:48:02 +02002469 while (*argument!=0) {
2470 switch(*argument)
2471 {
2472 case 'h':
2473 return FUZ_usage(programName);
Yann Collet736788f2017-01-19 12:12:50 -08002474
Yann Colletd7883a22016-08-12 16:48:02 +02002475 case 'v':
2476 argument++;
Yann Collet736788f2017-01-19 12:12:50 -08002477 g_displayLevel++;
Yann Colletd7883a22016-08-12 16:48:02 +02002478 break;
Yann Collet736788f2017-01-19 12:12:50 -08002479
Yann Colletd7883a22016-08-12 16:48:02 +02002480 case 'q':
2481 argument++;
2482 g_displayLevel--;
2483 break;
Yann Collet736788f2017-01-19 12:12:50 -08002484
Yann Colletd7883a22016-08-12 16:48:02 +02002485 case 'p': /* pause at the end */
2486 argument++;
2487 mainPause = 1;
2488 break;
2489
Yann Collet736788f2017-01-19 12:12:50 -08002490 case 'i': /* limit tests by nb of iterations (default) */
Yann Colletd7883a22016-08-12 16:48:02 +02002491 argument++;
Yann Colletef9999f2016-09-01 16:44:48 -07002492 nbTests=0; g_clockTime=0;
Yann Colletd7883a22016-08-12 16:48:02 +02002493 while ((*argument>='0') && (*argument<='9')) {
2494 nbTests *= 10;
2495 nbTests += *argument - '0';
2496 argument++;
2497 }
2498 break;
2499
Yann Collet736788f2017-01-19 12:12:50 -08002500 case 'T': /* limit tests by time */
Yann Colletd7883a22016-08-12 16:48:02 +02002501 argument++;
Yann Colletef9999f2016-09-01 16:44:48 -07002502 nbTests=0; g_clockTime=0;
Yann Colletd7883a22016-08-12 16:48:02 +02002503 while ((*argument>='0') && (*argument<='9')) {
Yann Colletef9999f2016-09-01 16:44:48 -07002504 g_clockTime *= 10;
2505 g_clockTime += *argument - '0';
Yann Colletd7883a22016-08-12 16:48:02 +02002506 argument++;
2507 }
Yann Colletbd88f632017-11-27 12:15:23 -08002508 if (*argument=='m') { /* -T1m == -T60 */
2509 g_clockTime *=60, argument++;
2510 if (*argument=='n') argument++; /* -T1mn == -T60 */
2511 } else if (*argument=='s') argument++; /* -T10s == -T10 */
Nick Terrell9a2f6f42017-11-29 19:11:12 -08002512 g_clockTime *= SEC_TO_MICRO;
Yann Colletd7883a22016-08-12 16:48:02 +02002513 break;
2514
Yann Collet736788f2017-01-19 12:12:50 -08002515 case 's': /* manually select seed */
Yann Colletd7883a22016-08-12 16:48:02 +02002516 argument++;
Yann Colletd7883a22016-08-12 16:48:02 +02002517 seedset=1;
Yann Colletbd88f632017-11-27 12:15:23 -08002518 seed=0;
Yann Colletd7883a22016-08-12 16:48:02 +02002519 while ((*argument>='0') && (*argument<='9')) {
2520 seed *= 10;
2521 seed += *argument - '0';
2522 argument++;
2523 }
2524 break;
2525
Yann Collet736788f2017-01-19 12:12:50 -08002526 case 't': /* select starting test number */
Yann Colletd7883a22016-08-12 16:48:02 +02002527 argument++;
2528 testNb=0;
2529 while ((*argument>='0') && (*argument<='9')) {
2530 testNb *= 10;
2531 testNb += *argument - '0';
2532 argument++;
2533 }
2534 break;
2535
2536 case 'P': /* compressibility % */
2537 argument++;
2538 proba=0;
2539 while ((*argument>='0') && (*argument<='9')) {
2540 proba *= 10;
2541 proba += *argument - '0';
2542 argument++;
2543 }
2544 if (proba<0) proba=0;
2545 if (proba>100) proba=100;
2546 break;
2547
2548 default:
2549 return FUZ_usage(programName);
2550 }
2551 } } } /* for(argNb=1; argNb<argc; argNb++) */
2552
2553 /* Get Seed */
Yann Colletbb855812016-08-25 19:11:11 +02002554 DISPLAY("Starting zstream tester (%i-bits, %s)\n", (int)(sizeof(size_t)*8), ZSTD_VERSION_STRING);
Yann Colletd7883a22016-08-12 16:48:02 +02002555
Yann Colletef9999f2016-09-01 16:44:48 -07002556 if (!seedset) {
2557 time_t const t = time(NULL);
2558 U32 const h = XXH32(&t, sizeof(t), 1);
2559 seed = h % 10000;
2560 }
2561
Yann Colletededcfc2018-12-21 16:19:44 -08002562 DISPLAY("Seed = %u\n", (unsigned)seed);
Yann Colletd7883a22016-08-12 16:48:02 +02002563 if (proba!=FUZ_COMPRESSIBILITY_DEFAULT) DISPLAY("Compressibility : %i%%\n", proba);
2564
2565 if (nbTests<=0) nbTests=1;
2566
2567 if (testNb==0) {
Yann Colletbd88f632017-11-27 12:15:23 -08002568 result = basicUnitTests(0, ((double)proba) / 100); /* constant seed for predictability */
Yann Collet4616fad2017-07-10 17:16:41 -07002569 }
Yann Colletd7883a22016-08-12 16:48:02 +02002570
Yann Collet01743a32017-06-16 17:56:41 -07002571 if (!result) {
2572 switch(selected_api)
2573 {
2574 case simple_api :
2575 result = fuzzerTests(seed, nbTests, testNb, ((double)proba) / 100, bigTests);
2576 break;
Yann Collet01743a32017-06-16 17:56:41 -07002577 case advanced_api :
Yann Colletc9e8ee92018-06-18 19:20:37 -07002578 result = fuzzerTests_newAPI(seed, nbTests, testNb, ((double)proba) / 100, bigTests);
Yann Collet01743a32017-06-16 17:56:41 -07002579 break;
2580 default :
2581 assert(0); /* impossible */
2582 }
2583 }
Yann Colletd7883a22016-08-12 16:48:02 +02002584
2585 if (mainPause) {
2586 int unused;
2587 DISPLAY("Press Enter \n");
2588 unused = getchar();
2589 (void)unused;
2590 }
2591 return result;
2592}