blob: d53586c17e1124d565b98700547ec9f99d9b1dfb [file] [log] [blame]
Yann Collet4856a002015-01-24 01:58:16 +01001/*
2 Fuzzer test tool for zstd
Yann Collet0d9ce042016-03-19 13:21:08 +01003 Copyright (C) Yann Collet 2014-2016
Yann Collet4856a002015-01-24 01:58:16 +01004
5 GPL v2 License
6
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
11
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License along
18 with this program; if not, write to the Free Software Foundation, Inc.,
19 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20
21 You can contact the author at :
Yann Collet0d9ce042016-03-19 13:21:08 +010022 - ZSTD homepage : http://www.zstd.net
Yann Collet4856a002015-01-24 01:58:16 +010023*/
24
Yann Collet0d9ce042016-03-19 13:21:08 +010025/*-************************************
Yann Collet4856a002015-01-24 01:58:16 +010026* Compiler specific
27**************************************/
28#ifdef _MSC_VER /* Visual Studio */
29# define _CRT_SECURE_NO_WARNINGS /* fgets */
30# pragma warning(disable : 4127) /* disable: C4127: conditional expression is constant */
31# pragma warning(disable : 4146) /* disable: C4146: minus unsigned expression */
32#endif
33
Yann Collet4856a002015-01-24 01:58:16 +010034
Yann Collet0d9ce042016-03-19 13:21:08 +010035/*-************************************
Yann Collet4856a002015-01-24 01:58:16 +010036* Includes
37**************************************/
38#include <stdlib.h> /* free */
39#include <stdio.h> /* fgets, sscanf */
40#include <sys/timeb.h> /* timeb */
41#include <string.h> /* strcmp */
42#include "zstd_static.h"
Yann Colletd5d9bc32015-08-23 23:13:49 +010043#include "datagen.h" /* RDG_genBuffer */
Yann Collet4856a002015-01-24 01:58:16 +010044#include "xxhash.h" /* XXH64 */
Yann Collet353c5d22015-10-21 14:39:26 +010045#include "mem.h"
Yann Collet4856a002015-01-24 01:58:16 +010046
47
Yann Collet0d9ce042016-03-19 13:21:08 +010048/*-************************************
49* Constants
Yann Collet4856a002015-01-24 01:58:16 +010050**************************************/
51#ifndef ZSTD_VERSION
52# define ZSTD_VERSION ""
53#endif
54
55#define KB *(1U<<10)
56#define MB *(1U<<20)
57#define GB *(1U<<30)
58
Yann Collet0d9ce042016-03-19 13:21:08 +010059static const size_t COMPRESSIBLE_NOISE_LENGTH = 10 MB; /* capital, used to be a macro */
60static const U32 FUZ_compressibility_default = 50;
Yann Collet110cc142015-11-19 12:02:28 +010061static const U32 nbTestsDefault = 30000;
Yann Collet4856a002015-01-24 01:58:16 +010062
63
Yann Collet0d9ce042016-03-19 13:21:08 +010064/*-************************************
Yann Collet4856a002015-01-24 01:58:16 +010065* Display Macros
66**************************************/
67#define DISPLAY(...) fprintf(stderr, __VA_ARGS__)
68#define DISPLAYLEVEL(l, ...) if (g_displayLevel>=l) { DISPLAY(__VA_ARGS__); }
69static U32 g_displayLevel = 2;
70
71#define DISPLAYUPDATE(l, ...) if (g_displayLevel>=l) { \
Yann Collet553cf6a2015-12-04 17:25:26 +010072 if ((FUZ_GetMilliSpan(g_displayTime) > g_refreshRate) || (g_displayLevel>=4)) \
73 { g_displayTime = FUZ_GetMilliStart(); DISPLAY(__VA_ARGS__); \
Yann Collet4856a002015-01-24 01:58:16 +010074 if (g_displayLevel>=4) fflush(stdout); } }
75static const U32 g_refreshRate = 150;
Yann Collet553cf6a2015-12-04 17:25:26 +010076static U32 g_displayTime = 0;
77
Yann Collet4856a002015-01-24 01:58:16 +010078
Yann Collet0d9ce042016-03-19 13:21:08 +010079/*-*******************************************************
Yann Collet4856a002015-01-24 01:58:16 +010080* Fuzzer functions
81*********************************************************/
Yann Collete93add02016-02-15 17:44:14 +010082#define MIN(a,b) ((a)<(b)?(a):(b))
Yann Collet110cc142015-11-19 12:02:28 +010083#define MAX(a,b) ((a)>(b)?(a):(b))
84
Yann Collet4856a002015-01-24 01:58:16 +010085static U32 FUZ_GetMilliStart(void)
86{
87 struct timeb tb;
88 U32 nCount;
89 ftime( &tb );
90 nCount = (U32) (((tb.time & 0xFFFFF) * 1000) + tb.millitm);
91 return nCount;
92}
93
94
95static U32 FUZ_GetMilliSpan(U32 nTimeStart)
96{
97 U32 nCurrent = FUZ_GetMilliStart();
98 U32 nSpan = nCurrent - nTimeStart;
99 if (nTimeStart > nCurrent)
100 nSpan += 0x100000 * 1000;
101 return nSpan;
102}
103
104
105# define FUZ_rotl32(x,r) ((x << r) | (x >> (32 - r)))
106unsigned int FUZ_rand(unsigned int* src)
107{
Yann Collet0d9ce042016-03-19 13:21:08 +0100108 static const U32 prime1 = 2654435761U;
109 static const U32 prime2 = 2246822519U;
Yann Collet4856a002015-01-24 01:58:16 +0100110 U32 rand32 = *src;
111 rand32 *= prime1;
112 rand32 += prime2;
113 rand32 = FUZ_rotl32(rand32, 13);
114 *src = rand32;
115 return rand32 >> 5;
116}
117
118
Yann Collet997f9ee2015-08-21 02:44:20 +0100119static unsigned FUZ_highbit32(U32 v32)
Yann Collet4856a002015-01-24 01:58:16 +0100120{
121 unsigned nbBits = 0;
122 if (v32==0) return 0;
Yann Collet0d9ce042016-03-19 13:21:08 +0100123 while (v32) {
Yann Collet4856a002015-01-24 01:58:16 +0100124 v32 >>= 1;
125 nbBits ++;
126 }
127 return nbBits;
128}
Yann Collet4856a002015-01-24 01:58:16 +0100129
130
131static int basicUnitTests(U32 seed, double compressibility)
132{
133 int testResult = 0;
134 void* CNBuffer;
135 void* compressedBuffer;
136 void* decodedBuffer;
137 U32 randState = seed;
138 size_t result, cSize;
139 U32 testNb=0;
140
Yann Colletd5d9bc32015-08-23 23:13:49 +0100141 /* Create compressible test buffer */
Yann Collet4856a002015-01-24 01:58:16 +0100142 CNBuffer = malloc(COMPRESSIBLE_NOISE_LENGTH);
143 compressedBuffer = malloc(ZSTD_compressBound(COMPRESSIBLE_NOISE_LENGTH));
144 decodedBuffer = malloc(COMPRESSIBLE_NOISE_LENGTH);
Yann Colletd1d210f2016-03-19 12:12:07 +0100145 if (!CNBuffer || !compressedBuffer || !decodedBuffer) {
Yann Collet94f998b2015-07-04 23:10:40 -0800146 DISPLAY("Not enough memory, aborting\n");
147 testResult = 1;
148 goto _end;
149 }
Yann Colletd5d9bc32015-08-23 23:13:49 +0100150 RDG_genBuffer(CNBuffer, COMPRESSIBLE_NOISE_LENGTH, compressibility, 0., randState);
Yann Collet4856a002015-01-24 01:58:16 +0100151
Yann Colletd5d9bc32015-08-23 23:13:49 +0100152 /* Basic tests */
Yann Collet0d9ce042016-03-19 13:21:08 +0100153 DISPLAYLEVEL(4, "test%3i : compress %u bytes : ", testNb++, (U32)COMPRESSIBLE_NOISE_LENGTH);
Yann Collet5be2dd22015-11-11 13:43:58 +0100154 result = ZSTD_compress(compressedBuffer, ZSTD_compressBound(COMPRESSIBLE_NOISE_LENGTH), CNBuffer, COMPRESSIBLE_NOISE_LENGTH, 1);
Yann Collet4856a002015-01-24 01:58:16 +0100155 if (ZSTD_isError(result)) goto _output_error;
156 cSize = result;
157 DISPLAYLEVEL(4, "OK (%u bytes : %.2f%%)\n", (U32)cSize, (double)cSize/COMPRESSIBLE_NOISE_LENGTH*100);
158
Yann Collet0d9ce042016-03-19 13:21:08 +0100159 DISPLAYLEVEL(4, "test%3i : decompress %u bytes : ", testNb++, (U32)COMPRESSIBLE_NOISE_LENGTH);
Yann Collet4856a002015-01-24 01:58:16 +0100160 result = ZSTD_decompress(decodedBuffer, COMPRESSIBLE_NOISE_LENGTH, compressedBuffer, cSize);
161 if (ZSTD_isError(result)) goto _output_error;
Yann Collet4ec29982016-03-04 19:09:28 +0100162 if (result != COMPRESSIBLE_NOISE_LENGTH) goto _output_error;
Yann Collet4856a002015-01-24 01:58:16 +0100163 DISPLAYLEVEL(4, "OK \n");
164
Yann Colletd1d210f2016-03-19 12:12:07 +0100165 { size_t i;
Yann Collet4856a002015-01-24 01:58:16 +0100166 DISPLAYLEVEL(4, "test%3i : check decompressed result : ", testNb++);
Yann Colletd1d210f2016-03-19 12:12:07 +0100167 for (i=0; i<COMPRESSIBLE_NOISE_LENGTH; i++) {
Yann Collet4856a002015-01-24 01:58:16 +0100168 if (((BYTE*)decodedBuffer)[i] != ((BYTE*)CNBuffer)[i]) goto _output_error;;
169 }
170 DISPLAYLEVEL(4, "OK \n");
171 }
172
173 DISPLAYLEVEL(4, "test%3i : decompress with 1 missing byte : ", testNb++);
174 result = ZSTD_decompress(decodedBuffer, COMPRESSIBLE_NOISE_LENGTH, compressedBuffer, cSize-1);
175 if (!ZSTD_isError(result)) goto _output_error;
Yann Collet977f1f32016-01-21 15:38:47 +0100176 if (result != (size_t)-ZSTD_error_srcSize_wrong) goto _output_error;
Yann Collet4856a002015-01-24 01:58:16 +0100177 DISPLAYLEVEL(4, "OK \n");
178
179 DISPLAYLEVEL(4, "test%3i : decompress with 1 too much byte : ", testNb++);
180 result = ZSTD_decompress(decodedBuffer, COMPRESSIBLE_NOISE_LENGTH, compressedBuffer, cSize+1);
181 if (!ZSTD_isError(result)) goto _output_error;
Yann Collet977f1f32016-01-21 15:38:47 +0100182 if (result != (size_t)-ZSTD_error_srcSize_wrong) goto _output_error;
Yann Collet4856a002015-01-24 01:58:16 +0100183 DISPLAYLEVEL(4, "OK \n");
184
Yann Collet60096272016-01-08 17:27:50 +0100185 /* Dictionary and Duplication tests */
Yann Colletd1d210f2016-03-19 12:12:07 +0100186 { ZSTD_CCtx* ctxOrig = ZSTD_createCCtx();
Yann Collet60096272016-01-08 17:27:50 +0100187 ZSTD_CCtx* ctxDuplicated = ZSTD_createCCtx();
188 ZSTD_DCtx* dctx = ZSTD_createDCtx();
189 const size_t dictSize = 500;
190 size_t cSizeOrig;
191
192 DISPLAYLEVEL(4, "test%3i : load dictionary into context : ", testNb++);
Yann Collet1c8e1942016-01-26 16:31:22 +0100193 result = ZSTD_compressBegin_usingDict(ctxOrig, CNBuffer, dictSize, 2);
Yann Collet60096272016-01-08 17:27:50 +0100194 if (ZSTD_isError(result)) goto _output_error;
Yann Collet7b51a292016-01-26 15:58:49 +0100195 result = ZSTD_copyCCtx(ctxDuplicated, ctxOrig);
Yann Collet60096272016-01-08 17:27:50 +0100196 if (ZSTD_isError(result)) goto _output_error;
197 DISPLAYLEVEL(4, "OK \n");
198
199 DISPLAYLEVEL(4, "test%3i : compress with dictionary : ", testNb++);
200 cSize = 0;
201 result = ZSTD_compressContinue(ctxOrig, compressedBuffer, ZSTD_compressBound(COMPRESSIBLE_NOISE_LENGTH), (const char*)CNBuffer + dictSize, COMPRESSIBLE_NOISE_LENGTH - dictSize);
202 if (ZSTD_isError(result)) goto _output_error;
203 cSize += result;
204 result = ZSTD_compressEnd(ctxOrig, (char*)compressedBuffer+cSize, ZSTD_compressBound(COMPRESSIBLE_NOISE_LENGTH)-cSize);
205 if (ZSTD_isError(result)) goto _output_error;
206 cSize += result;
207 DISPLAYLEVEL(4, "OK (%u bytes : %.2f%%)\n", (U32)cSize, (double)cSize/COMPRESSIBLE_NOISE_LENGTH*100);
208
209 DISPLAYLEVEL(4, "test%3i : frame built with dictionary should be decompressible : ", testNb++);
210 result = ZSTD_decompress_usingDict(dctx,
211 decodedBuffer, COMPRESSIBLE_NOISE_LENGTH,
212 compressedBuffer, cSize,
213 CNBuffer, dictSize);
214 if (ZSTD_isError(result)) goto _output_error;
Yann Colletbf42c8e2016-01-09 01:08:23 +0100215 if (result != COMPRESSIBLE_NOISE_LENGTH - dictSize) goto _output_error;
Yann Collet60096272016-01-08 17:27:50 +0100216 ZSTD_freeCCtx(ctxOrig); /* if ctxOrig is read, will produce segfault */
217 DISPLAYLEVEL(4, "OK \n");
218
219 DISPLAYLEVEL(4, "test%3i : compress with duplicated context : ", testNb++);
220 cSizeOrig = cSize;
221 cSize = 0;
222 result = ZSTD_compressContinue(ctxDuplicated, compressedBuffer, ZSTD_compressBound(COMPRESSIBLE_NOISE_LENGTH), (const char*)CNBuffer + dictSize, COMPRESSIBLE_NOISE_LENGTH - dictSize);
223 if (ZSTD_isError(result)) goto _output_error;
224 cSize += result;
225 result = ZSTD_compressEnd(ctxDuplicated, (char*)compressedBuffer+cSize, ZSTD_compressBound(COMPRESSIBLE_NOISE_LENGTH)-cSize);
226 if (ZSTD_isError(result)) goto _output_error;
227 cSize += result;
228 if (cSize != cSizeOrig) goto _output_error; /* should be identical == have same size */
229 ZSTD_freeCCtx(ctxDuplicated);
230 DISPLAYLEVEL(4, "OK (%u bytes : %.2f%%)\n", (U32)cSize, (double)cSize/COMPRESSIBLE_NOISE_LENGTH*100);
231
232 DISPLAYLEVEL(4, "test%3i : frame built with duplicated context should be decompressible : ", testNb++);
233 result = ZSTD_decompress_usingDict(dctx,
234 decodedBuffer, COMPRESSIBLE_NOISE_LENGTH,
235 compressedBuffer, cSize,
236 CNBuffer, dictSize);
237 if (ZSTD_isError(result)) goto _output_error;
Yann Colletbf42c8e2016-01-09 01:08:23 +0100238 if (result != COMPRESSIBLE_NOISE_LENGTH - dictSize) goto _output_error;
Yann Collet60096272016-01-08 17:27:50 +0100239 ZSTD_freeDCtx(dctx);
240 DISPLAYLEVEL(4, "OK \n");
241 }
242
Yann Collet4856a002015-01-24 01:58:16 +0100243 /* Decompression defense tests */
244 DISPLAYLEVEL(4, "test%3i : Check input length for magic number : ", testNb++);
245 result = ZSTD_decompress(decodedBuffer, COMPRESSIBLE_NOISE_LENGTH, CNBuffer, 3);
246 if (!ZSTD_isError(result)) goto _output_error;
Yann Collet977f1f32016-01-21 15:38:47 +0100247 if (result != (size_t)-ZSTD_error_srcSize_wrong) goto _output_error;
Yann Collet4856a002015-01-24 01:58:16 +0100248 DISPLAYLEVEL(4, "OK \n");
249
250 DISPLAYLEVEL(4, "test%3i : Check magic Number : ", testNb++);
251 ((char*)(CNBuffer))[0] = 1;
252 result = ZSTD_decompress(decodedBuffer, COMPRESSIBLE_NOISE_LENGTH, CNBuffer, 4);
253 if (!ZSTD_isError(result)) goto _output_error;
Yann Collet4856a002015-01-24 01:58:16 +0100254 DISPLAYLEVEL(4, "OK \n");
255
Yann Colletbf42c8e2016-01-09 01:08:23 +0100256 /* block API tests */
Yann Colletd1d210f2016-03-19 12:12:07 +0100257 { ZSTD_CCtx* const cctx = ZSTD_createCCtx();
Yann Colletbf42c8e2016-01-09 01:08:23 +0100258 ZSTD_DCtx* const dctx = ZSTD_createDCtx();
259 const size_t blockSize = 100 KB;
Yann Colletb0125102016-01-09 02:00:10 +0100260 const size_t dictSize = 16 KB;
Yann Colletbf42c8e2016-01-09 01:08:23 +0100261
262 /* basic block compression */
263 DISPLAYLEVEL(4, "test%3i : Block compression test : ", testNb++);
264 result = ZSTD_compressBegin(cctx, 5);
265 if (ZSTD_isError(result)) goto _output_error;
266 cSize = ZSTD_compressBlock(cctx, compressedBuffer, ZSTD_compressBound(blockSize), CNBuffer, blockSize);
267 if (ZSTD_isError(cSize)) goto _output_error;
268 DISPLAYLEVEL(4, "OK \n");
269
270 DISPLAYLEVEL(4, "test%3i : Block decompression test : ", testNb++);
Yann Collet7b51a292016-01-26 15:58:49 +0100271 result = ZSTD_decompressBegin(dctx);
Yann Colletbf42c8e2016-01-09 01:08:23 +0100272 if (ZSTD_isError(result)) goto _output_error;
273 result = ZSTD_decompressBlock(dctx, decodedBuffer, COMPRESSIBLE_NOISE_LENGTH, compressedBuffer, cSize);
274 if (ZSTD_isError(result)) goto _output_error;
275 if (result != blockSize) goto _output_error;
276 DISPLAYLEVEL(4, "OK \n");
277
Yann Colletb0125102016-01-09 02:00:10 +0100278 /* dictionary block compression */
279 DISPLAYLEVEL(4, "test%3i : Dictionary Block compression test : ", testNb++);
Yann Collet1c8e1942016-01-26 16:31:22 +0100280 result = ZSTD_compressBegin_usingDict(cctx, CNBuffer, dictSize, 5);
Yann Colletb0125102016-01-09 02:00:10 +0100281 if (ZSTD_isError(result)) goto _output_error;
282 cSize = ZSTD_compressBlock(cctx, compressedBuffer, ZSTD_compressBound(blockSize), (char*)CNBuffer+dictSize, blockSize);
283 if (ZSTD_isError(cSize)) goto _output_error;
284 DISPLAYLEVEL(4, "OK \n");
285
286 DISPLAYLEVEL(4, "test%3i : Dictionary Block decompression test : ", testNb++);
Yann Collet7b51a292016-01-26 15:58:49 +0100287 result = ZSTD_decompressBegin_usingDict(dctx, CNBuffer, dictSize);
Yann Colletb0125102016-01-09 02:00:10 +0100288 if (ZSTD_isError(result)) goto _output_error;
Yann Colletb0125102016-01-09 02:00:10 +0100289 result = ZSTD_decompressBlock(dctx, decodedBuffer, COMPRESSIBLE_NOISE_LENGTH, compressedBuffer, cSize);
290 if (ZSTD_isError(result)) goto _output_error;
291 if (result != blockSize) goto _output_error;
292 DISPLAYLEVEL(4, "OK \n");
293
Yann Colletbf42c8e2016-01-09 01:08:23 +0100294 ZSTD_freeCCtx(cctx);
295 ZSTD_freeDCtx(dctx);
296 }
297
Yann Collet213089c2015-06-18 07:43:16 -0800298 /* long rle test */
Yann Colletd1d210f2016-03-19 12:12:07 +0100299 { size_t sampleSize = 0;
Yann Collet213089c2015-06-18 07:43:16 -0800300 DISPLAYLEVEL(4, "test%3i : Long RLE test : ", testNb++);
Yann Colletd5d9bc32015-08-23 23:13:49 +0100301 RDG_genBuffer(CNBuffer, sampleSize, compressibility, 0., randState);
Yann Collet213089c2015-06-18 07:43:16 -0800302 memset((char*)CNBuffer+sampleSize, 'B', 256 KB - 1);
303 sampleSize += 256 KB - 1;
Yann Colletd5d9bc32015-08-23 23:13:49 +0100304 RDG_genBuffer((char*)CNBuffer+sampleSize, 96 KB, compressibility, 0., randState);
Yann Collet213089c2015-06-18 07:43:16 -0800305 sampleSize += 96 KB;
Yann Collet5be2dd22015-11-11 13:43:58 +0100306 cSize = ZSTD_compress(compressedBuffer, ZSTD_compressBound(sampleSize), CNBuffer, sampleSize, 1);
Yann Collet213089c2015-06-18 07:43:16 -0800307 if (ZSTD_isError(cSize)) goto _output_error;
308 result = ZSTD_decompress(decodedBuffer, sampleSize, compressedBuffer, cSize);
309 if (ZSTD_isError(result)) goto _output_error;
310 if (result!=sampleSize) goto _output_error;
311 DISPLAYLEVEL(4, "OK \n");
312 }
313
Yann Collet4ba85342016-03-07 20:01:45 +0100314 /* All zeroes test (#137 verif) */
315 #define ZEROESLENGTH 100
316 DISPLAYLEVEL(4, "test%3i : compress %u zeroes : ", testNb++, ZEROESLENGTH);
317 memset(CNBuffer, 0, ZEROESLENGTH);
318 result = ZSTD_compress(compressedBuffer, ZSTD_compressBound(ZEROESLENGTH), CNBuffer, ZEROESLENGTH, 1);
319 if (ZSTD_isError(result)) goto _output_error;
320 cSize = result;
321 DISPLAYLEVEL(4, "OK (%u bytes : %.2f%%)\n", (U32)cSize, (double)cSize/ZEROESLENGTH*100);
322
323 DISPLAYLEVEL(4, "test%3i : decompress %u zeroes : ", testNb++, ZEROESLENGTH);
324 result = ZSTD_decompress(decodedBuffer, ZEROESLENGTH, compressedBuffer, cSize);
325 if (ZSTD_isError(result)) goto _output_error;
326 if (result != ZEROESLENGTH) goto _output_error;
327 DISPLAYLEVEL(4, "OK \n");
328
329 /* nbSeq limit test */
Yann Colletd1d210f2016-03-19 12:12:07 +0100330 #define _3BYTESTESTLENGTH 131000
331 #define NB3BYTESSEQLOG 9
332 #define NB3BYTESSEQ (1 << NB3BYTESSEQLOG)
333 #define NB3BYTESSEQMASK (NB3BYTESSEQ-1)
Yann Collet0d9ce042016-03-19 13:21:08 +0100334 /* creates a buffer full of 3-bytes sequences */
Yann Colletd1d210f2016-03-19 12:12:07 +0100335 { BYTE _3BytesSeqs[NB3BYTESSEQ][3];
Yann Collet0d9ce042016-03-19 13:21:08 +0100336 U32 rSeed = 1;
Yann Collet4ba85342016-03-07 20:01:45 +0100337
Yann Collet0d9ce042016-03-19 13:21:08 +0100338 /* create batch of 3-bytes sequences */
Yann Colletd1d210f2016-03-19 12:12:07 +0100339 { int i; for (i=0; i < NB3BYTESSEQ; i++) {
Yann Collet0d9ce042016-03-19 13:21:08 +0100340 _3BytesSeqs[i][0] = (BYTE)(FUZ_rand(&rSeed) & 255);
341 _3BytesSeqs[i][1] = (BYTE)(FUZ_rand(&rSeed) & 255);
342 _3BytesSeqs[i][2] = (BYTE)(FUZ_rand(&rSeed) & 255);
Yann Colletd1d210f2016-03-19 12:12:07 +0100343 }}
Yann Collet4ba85342016-03-07 20:01:45 +0100344
Yann Collet0d9ce042016-03-19 13:21:08 +0100345 /* randomly fills CNBuffer with prepared 3-bytes sequences */
346 { int i; for (i=0; i < _3BYTESTESTLENGTH; ) { /* note : CNBuffer size > _3BYTESTESTLENGTH+3 */
347 U32 id = FUZ_rand(&rSeed) & NB3BYTESSEQMASK;
Yann Collet4ba85342016-03-07 20:01:45 +0100348 ((BYTE*)CNBuffer)[i+0] = _3BytesSeqs[id][0];
349 ((BYTE*)CNBuffer)[i+1] = _3BytesSeqs[id][1];
350 ((BYTE*)CNBuffer)[i+2] = _3BytesSeqs[id][2];
351 i += 3;
Yann Collet0d9ce042016-03-19 13:21:08 +0100352 } }}
353 DISPLAYLEVEL(4, "test%3i : compress lots 3-bytes sequences : ", testNb++);
354 result = ZSTD_compress(compressedBuffer, ZSTD_compressBound(_3BYTESTESTLENGTH), CNBuffer, _3BYTESTESTLENGTH, 19);
355 if (ZSTD_isError(result)) goto _output_error;
356 cSize = result;
357 DISPLAYLEVEL(4, "OK (%u bytes : %.2f%%)\n", (U32)cSize, (double)cSize/_3BYTESTESTLENGTH*100);
Yann Collet4ba85342016-03-07 20:01:45 +0100358
Yann Collet0d9ce042016-03-19 13:21:08 +0100359 DISPLAYLEVEL(4, "test%3i : decompress lots 3-bytes sequence : ", testNb++);
360 result = ZSTD_decompress(decodedBuffer, _3BYTESTESTLENGTH, compressedBuffer, cSize);
361 if (ZSTD_isError(result)) goto _output_error;
362 if (result != _3BYTESTESTLENGTH) goto _output_error;
363 DISPLAYLEVEL(4, "OK \n");
Yann Collet4ba85342016-03-07 20:01:45 +0100364
Yann Collet4856a002015-01-24 01:58:16 +0100365_end:
366 free(CNBuffer);
367 free(compressedBuffer);
368 free(decodedBuffer);
369 return testResult;
370
371_output_error:
372 testResult = 1;
373 DISPLAY("Error detected in Unit tests ! \n");
374 goto _end;
375}
376
377
378static size_t findDiff(const void* buf1, const void* buf2, size_t max)
379{
Yann Collet213089c2015-06-18 07:43:16 -0800380 const BYTE* b1 = (const BYTE*)buf1;
381 const BYTE* b2 = (const BYTE*)buf2;
Yann Collet4856a002015-01-24 01:58:16 +0100382 size_t i;
Yann Colletd1d210f2016-03-19 12:12:07 +0100383 for (i=0; i<max; i++) {
Yann Collet4856a002015-01-24 01:58:16 +0100384 if (b1[i] != b2[i]) break;
385 }
386 return i;
387}
388
Yann Collet0d9ce042016-03-19 13:21:08 +0100389#define CHECK(cond, ...) if (cond) { DISPLAY("Error => "); DISPLAY(__VA_ARGS__); \
390 DISPLAY(" (seed %u, test nb %u) \n", seed, testNb); goto _output_error; }
Yann Collet4856a002015-01-24 01:58:16 +0100391
392static const U32 maxSrcLog = 23;
393static const U32 maxSampleLog = 22;
394
Yann Collet0d9ce042016-03-19 13:21:08 +0100395int fuzzerTests(U32 seed, U32 nbTests, unsigned startTest, U32 maxDuration, double compressibility)
Yann Collet4856a002015-01-24 01:58:16 +0100396{
Yann Colletd5d9bc32015-08-23 23:13:49 +0100397 BYTE* cNoiseBuffer[5];
Yann Collet4856a002015-01-24 01:58:16 +0100398 BYTE* srcBuffer;
399 BYTE* cBuffer;
400 BYTE* dstBuffer;
Yann Collete47c4e52015-12-05 09:23:53 +0100401 BYTE* mirrorBuffer;
Yann Collet4856a002015-01-24 01:58:16 +0100402 size_t srcBufferSize = (size_t)1<<maxSrcLog;
403 size_t dstBufferSize = (size_t)1<<maxSampleLog;
404 size_t cBufferSize = ZSTD_compressBound(dstBufferSize);
405 U32 result = 0;
406 U32 testNb = 0;
407 U32 coreSeed = seed, lseed = 0;
Yann Colletecd651b2016-01-07 15:35:18 +0100408 ZSTD_CCtx* refCtx;
Yann Collet2f648e52015-10-29 18:23:38 +0100409 ZSTD_CCtx* ctx;
Yann Collete47c4e52015-12-05 09:23:53 +0100410 ZSTD_DCtx* dctx;
Yann Collet553cf6a2015-12-04 17:25:26 +0100411 U32 startTime = FUZ_GetMilliStart();
Yann Collet4856a002015-01-24 01:58:16 +0100412
413 /* allocation */
Yann Colletecd651b2016-01-07 15:35:18 +0100414 refCtx = ZSTD_createCCtx();
Yann Collet2f648e52015-10-29 18:23:38 +0100415 ctx = ZSTD_createCCtx();
Yann Collete47c4e52015-12-05 09:23:53 +0100416 dctx= ZSTD_createDCtx();
Yann Colletd5d9bc32015-08-23 23:13:49 +0100417 cNoiseBuffer[0] = (BYTE*)malloc (srcBufferSize);
418 cNoiseBuffer[1] = (BYTE*)malloc (srcBufferSize);
419 cNoiseBuffer[2] = (BYTE*)malloc (srcBufferSize);
420 cNoiseBuffer[3] = (BYTE*)malloc (srcBufferSize);
421 cNoiseBuffer[4] = (BYTE*)malloc (srcBufferSize);
Yann Collet213089c2015-06-18 07:43:16 -0800422 dstBuffer = (BYTE*)malloc (dstBufferSize);
Yann Collete47c4e52015-12-05 09:23:53 +0100423 mirrorBuffer = (BYTE*)malloc (dstBufferSize);
Yann Collet213089c2015-06-18 07:43:16 -0800424 cBuffer = (BYTE*)malloc (cBufferSize);
Yann Collete47c4e52015-12-05 09:23:53 +0100425 CHECK (!cNoiseBuffer[0] || !cNoiseBuffer[1] || !cNoiseBuffer[2] || !cNoiseBuffer[3] || !cNoiseBuffer[4]
Yann Colletecd651b2016-01-07 15:35:18 +0100426 || !dstBuffer || !mirrorBuffer || !cBuffer || !refCtx || !ctx || !dctx,
Yann Colletd5d9bc32015-08-23 23:13:49 +0100427 "Not enough memory, fuzzer tests cancelled");
Yann Collet4856a002015-01-24 01:58:16 +0100428
Yann Colletd5d9bc32015-08-23 23:13:49 +0100429 /* Create initial samples */
430 RDG_genBuffer(cNoiseBuffer[0], srcBufferSize, 0.00, 0., coreSeed); /* pure noise */
431 RDG_genBuffer(cNoiseBuffer[1], srcBufferSize, 0.05, 0., coreSeed); /* barely compressible */
432 RDG_genBuffer(cNoiseBuffer[2], srcBufferSize, compressibility, 0., coreSeed);
433 RDG_genBuffer(cNoiseBuffer[3], srcBufferSize, 0.95, 0., coreSeed); /* highly compressible */
434 RDG_genBuffer(cNoiseBuffer[4], srcBufferSize, 1.00, 0., coreSeed); /* sparse content */
435 srcBuffer = cNoiseBuffer[2];
Yann Collet4856a002015-01-24 01:58:16 +0100436
437 /* catch up testNb */
Yann Collet546c9b12016-03-19 12:47:52 +0100438 for (testNb=1; testNb < startTest; testNb++) FUZ_rand(&coreSeed);
Yann Collet4856a002015-01-24 01:58:16 +0100439
Yann Collet546c9b12016-03-19 12:47:52 +0100440 /* main test loop */
Yann Collet0d9ce042016-03-19 13:21:08 +0100441 for ( ; (testNb <= nbTests) || (FUZ_GetMilliSpan(startTime) < maxDuration); testNb++ ) {
Yann Collet417890c2015-12-04 17:16:37 +0100442 size_t sampleSize, sampleStart, maxTestSize, totalTestSize;
Yann Collet546c9b12016-03-19 12:47:52 +0100443 size_t cSize, dSize, errorCode, totalCSize, totalGenSize;
Yann Collet417890c2015-12-04 17:16:37 +0100444 U32 sampleSizeLog, buffNb, cLevelMod, nbChunks, n;
Yann Collet5835e1b2016-01-05 01:44:36 +0100445 XXH64_CREATESTATE_STATIC(xxh64);
Yann Collet4856a002015-01-24 01:58:16 +0100446 U64 crcOrig, crcDest;
Yann Collet2f648e52015-10-29 18:23:38 +0100447 int cLevel;
Yann Collet110cc142015-11-19 12:02:28 +0100448 BYTE* sampleBuffer;
Yann Collet4bfe4152015-12-06 13:18:37 +0100449 const BYTE* dict;
450 size_t dictSize;
Yann Collet4856a002015-01-24 01:58:16 +0100451
Yann Collet546c9b12016-03-19 12:47:52 +0100452 /* notification */
453 if (nbTests >= testNb) { DISPLAYUPDATE(2, "\r%6u/%6u ", testNb, nbTests); }
Yann Collet1c2ddba2015-12-04 17:45:35 +0100454 else { DISPLAYUPDATE(2, "\r%6u ", testNb); }
455
Yann Collet4856a002015-01-24 01:58:16 +0100456 FUZ_rand(&coreSeed);
Yann Collet0d9ce042016-03-19 13:21:08 +0100457 { U32 const prime1 = 2654435761U; lseed = coreSeed ^ prime1; }
Yann Colletd5d9bc32015-08-23 23:13:49 +0100458 buffNb = FUZ_rand(&lseed) & 127;
459 if (buffNb & 7) buffNb=2;
Yann Colletd1d210f2016-03-19 12:12:07 +0100460 else {
Yann Colletd5d9bc32015-08-23 23:13:49 +0100461 buffNb >>= 3;
Yann Colletd1d210f2016-03-19 12:12:07 +0100462 if (buffNb & 7) {
Yann Colletd5d9bc32015-08-23 23:13:49 +0100463 const U32 tnb[2] = { 1, 3 };
464 buffNb = tnb[buffNb >> 3];
Yann Colletd1d210f2016-03-19 12:12:07 +0100465 } else {
Yann Colletd5d9bc32015-08-23 23:13:49 +0100466 const U32 tnb[2] = { 0, 4 };
467 buffNb = tnb[buffNb >> 3];
Yann Collet546c9b12016-03-19 12:47:52 +0100468 } }
Yann Colletd5d9bc32015-08-23 23:13:49 +0100469 srcBuffer = cNoiseBuffer[buffNb];
Yann Collet4856a002015-01-24 01:58:16 +0100470 sampleSizeLog = FUZ_rand(&lseed) % maxSampleLog;
Yann Colletf4ce8912015-08-11 14:18:45 +0100471 sampleSize = (size_t)1 << sampleSizeLog;
Yann Collet4856a002015-01-24 01:58:16 +0100472 sampleSize += FUZ_rand(&lseed) & (sampleSize-1);
473 sampleStart = FUZ_rand(&lseed) % (srcBufferSize - sampleSize);
Yann Collet4856a002015-01-24 01:58:16 +0100474
Yann Collet110cc142015-11-19 12:02:28 +0100475 /* create sample buffer (to catch read error with valgrind & sanitizers) */
476 sampleBuffer = (BYTE*)malloc(sampleSize);
477 CHECK (sampleBuffer==NULL, "not enough memory for sample buffer");
478 memcpy(sampleBuffer, srcBuffer + sampleStart, sampleSize);
479 crcOrig = XXH64(sampleBuffer, sampleSize, 0);
480
481 /* compression test */
Yann Collete93add02016-02-15 17:44:14 +0100482 cLevelMod = MIN( ZSTD_maxCLevel(), (U32)MAX(1, 55 - 3*(int)sampleSizeLog) ); /* high levels only for small samples, for manageable speed */
Yann Collet4c7aae32015-11-08 14:24:59 +0100483 cLevel = (FUZ_rand(&lseed) % cLevelMod) +1;
Yann Colletdc5e3e92015-11-20 09:23:56 +0100484 cSize = ZSTD_compressCCtx(ctx, cBuffer, cBufferSize, sampleBuffer, sampleSize, cLevel);
Yann Collet5be2dd22015-11-11 13:43:58 +0100485 CHECK(ZSTD_isError(cSize), "ZSTD_compressCCtx failed");
Yann Collet4856a002015-01-24 01:58:16 +0100486
Yann Colletf3cb79b2015-08-20 00:02:43 +0100487 /* compression failure test : too small dest buffer */
Yann Collet346bffb2016-03-15 15:24:52 +0100488 if (cSize > 3) {
Yann Colletf4ce8912015-08-11 14:18:45 +0100489 const size_t missing = (FUZ_rand(&lseed) % (cSize-2)) + 1; /* no problem, as cSize > 4 (frameHeaderSizer) */
490 const size_t tooSmallSize = cSize - missing;
Yann Collet602834f2015-08-20 07:46:10 +0100491 static const U32 endMark = 0x4DC2B1A9;
Yann Collet602834f2015-08-20 07:46:10 +0100492 memcpy(dstBuffer+tooSmallSize, &endMark, 4);
Yann Colletdc5e3e92015-11-20 09:23:56 +0100493 errorCode = ZSTD_compressCCtx(ctx, dstBuffer, tooSmallSize, sampleBuffer, sampleSize, cLevel);
Yann Collet5be2dd22015-11-11 13:43:58 +0100494 CHECK(!ZSTD_isError(errorCode), "ZSTD_compressCCtx should have failed ! (buffer too small : %u < %u)", (U32)tooSmallSize, (U32)cSize);
Yann Colletd1d210f2016-03-19 12:12:07 +0100495 { U32 endCheck; memcpy(&endCheck, dstBuffer+tooSmallSize, 4);
496 CHECK(endCheck != endMark, "ZSTD_compressCCtx : dst buffer overflow"); }
Yann Collete9853b22015-08-07 19:07:32 +0100497 }
498
Yann Collet546c9b12016-03-19 12:47:52 +0100499 /* frame header decompression test */
Yann Collet346bffb2016-03-15 15:24:52 +0100500 { ZSTD_frameParams dParams;
501 size_t const check = ZSTD_getFrameParams(&dParams, cBuffer, cSize);
502 CHECK(ZSTD_isError(check), "Frame Parameters extraction failed");
503 CHECK(dParams.frameContentSize != sampleSize, "Frame content size incorrect");
504 }
505
Yann Collet546c9b12016-03-19 12:47:52 +0100506 /* successful decompression test */
507 { size_t margin = (FUZ_rand(&lseed) & 1) ? 0 : (FUZ_rand(&lseed) & 31) + 1;
508 dSize = ZSTD_decompress(dstBuffer, sampleSize + margin, cBuffer, cSize);
509 CHECK(dSize != sampleSize, "ZSTD_decompress failed (%s) (srcSize : %u ; cSize : %u)", ZSTD_getErrorName(dSize), (U32)sampleSize, (U32)cSize);
510 crcDest = XXH64(dstBuffer, sampleSize, 0);
511 CHECK(crcOrig != crcDest, "decompression result corrupted (pos %u / %u)", (U32)findDiff(sampleBuffer, dstBuffer, sampleSize), (U32)sampleSize);
512 }
Yann Collet110cc142015-11-19 12:02:28 +0100513
514 free(sampleBuffer); /* no longer useful after this point */
Yann Colletf3cb79b2015-08-20 00:02:43 +0100515
516 /* truncated src decompression test */
Yann Colletd1d210f2016-03-19 12:12:07 +0100517 { const size_t missing = (FUZ_rand(&lseed) % (cSize-2)) + 1; /* no problem, as cSize > 4 (frameHeaderSizer) */
Yann Colletf3cb79b2015-08-20 00:02:43 +0100518 const size_t tooSmallSize = cSize - missing;
519 void* cBufferTooSmall = malloc(tooSmallSize); /* valgrind will catch overflows */
Yann Colletf3cb79b2015-08-20 00:02:43 +0100520 CHECK(cBufferTooSmall == NULL, "not enough memory !");
Yann Colletd5d9bc32015-08-23 23:13:49 +0100521 memcpy(cBufferTooSmall, cBuffer, tooSmallSize);
Yann Colletf3cb79b2015-08-20 00:02:43 +0100522 errorCode = ZSTD_decompress(dstBuffer, dstBufferSize, cBufferTooSmall, tooSmallSize);
523 CHECK(!ZSTD_isError(errorCode), "ZSTD_decompress should have failed ! (truncated src buffer)");
524 free(cBufferTooSmall);
525 }
526
527 /* too small dst decompression test */
Yann Colletd1d210f2016-03-19 12:12:07 +0100528 if (sampleSize > 3) {
Yann Colletf3cb79b2015-08-20 00:02:43 +0100529 const size_t missing = (FUZ_rand(&lseed) % (sampleSize-2)) + 1; /* no problem, as cSize > 4 (frameHeaderSizer) */
530 const size_t tooSmallSize = sampleSize - missing;
531 static const BYTE token = 0xA9;
532 dstBuffer[tooSmallSize] = token;
533 errorCode = ZSTD_decompress(dstBuffer, tooSmallSize, cBuffer, cSize);
534 CHECK(!ZSTD_isError(errorCode), "ZSTD_decompress should have failed : %u > %u (dst buffer too small)", (U32)errorCode, (U32)tooSmallSize);
535 CHECK(dstBuffer[tooSmallSize] != token, "ZSTD_decompress : dst buffer overflow");
536 }
Yann Collet997f9ee2015-08-21 02:44:20 +0100537
538 /* noisy src decompression test */
Yann Colletd1d210f2016-03-19 12:12:07 +0100539 if (cSize > 6) {
540 /* insert noise into src */
541 { U32 const maxNbBits = FUZ_highbit32((U32)(cSize-4));
542 size_t pos = 4; /* preserve magic number (too easy to detect) */
543 for (;;) {
544 /* keep some original src */
545 { U32 const nbBits = FUZ_rand(&lseed) % maxNbBits;
546 size_t const mask = (1<<nbBits) - 1;
547 size_t const skipLength = FUZ_rand(&lseed) & mask;
548 pos += skipLength;
549 }
550 if (pos <= cSize) break;
551 /* add noise */
552 { U32 nbBits = FUZ_rand(&lseed) % maxNbBits;
553 size_t mask, noiseStart, noiseLength;
554 if (nbBits>0) nbBits--;
555 mask = (1<<nbBits) - 1;
556 noiseLength = (FUZ_rand(&lseed) & mask) + 1;
557 if ( pos+noiseLength > cSize ) noiseLength = cSize-pos;
558 noiseStart = FUZ_rand(&lseed) % (srcBufferSize - noiseLength);
559 memcpy(cBuffer + pos, srcBuffer + noiseStart, noiseLength);
560 pos += noiseLength;
561 } } }
Yann Collet997f9ee2015-08-21 02:44:20 +0100562
563 /* decompress noisy source */
Yann Colletd1d210f2016-03-19 12:12:07 +0100564 { U32 const endMark = 0xA9B1C3D6;
Yann Collet997f9ee2015-08-21 02:44:20 +0100565 memcpy(dstBuffer+sampleSize, &endMark, 4);
566 errorCode = ZSTD_decompress(dstBuffer, sampleSize, cBuffer, cSize);
Yann Collet546c9b12016-03-19 12:47:52 +0100567 /* result *may* be an unlikely success, but even then, it must strictly respect dst buffer boundaries */
Yann Collet997f9ee2015-08-21 02:44:20 +0100568 CHECK((!ZSTD_isError(errorCode)) && (errorCode>sampleSize),
569 "ZSTD_decompress on noisy src : result is too large : %u > %u (dst buffer)", (U32)errorCode, (U32)sampleSize);
Yann Colletf3120412016-03-19 11:40:19 +0100570 { U32 endCheck; memcpy(&endCheck, dstBuffer+sampleSize, 4);
571 CHECK(endMark!=endCheck, "ZSTD_decompress on noisy src : dst buffer overflow"); }
Yann Colletd1d210f2016-03-19 12:12:07 +0100572 } } /* noisy src decompression test */
Yann Collet417890c2015-12-04 17:16:37 +0100573
Yann Collete47c4e52015-12-05 09:23:53 +0100574 /* Streaming compression of scattered segments test */
Yann Collet5835e1b2016-01-05 01:44:36 +0100575 XXH64_reset(xxh64, 0);
Yann Collet417890c2015-12-04 17:16:37 +0100576 nbChunks = (FUZ_rand(&lseed) & 127) + 2;
577 sampleSizeLog = FUZ_rand(&lseed) % maxSrcLog;
578 maxTestSize = (size_t)1 << sampleSizeLog;
579 maxTestSize += FUZ_rand(&lseed) & (maxTestSize-1);
Yann Collete47c4e52015-12-05 09:23:53 +0100580 if (maxTestSize >= dstBufferSize) maxTestSize = dstBufferSize-1;
Yann Collet4bfe4152015-12-06 13:18:37 +0100581
582 sampleSizeLog = FUZ_rand(&lseed) % maxSampleLog;
583 sampleSize = (size_t)1 << sampleSizeLog;
584 sampleSize += FUZ_rand(&lseed) & (sampleSize-1);
585 sampleStart = FUZ_rand(&lseed) % (srcBufferSize - sampleSize);
586 dict = srcBuffer + sampleStart;
587 dictSize = sampleSize;
588
Yann Collet1c8e1942016-01-26 16:31:22 +0100589 errorCode = ZSTD_compressBegin_usingDict(refCtx, dict, dictSize, (FUZ_rand(&lseed) % (20 - (sampleSizeLog/3))) + 1);
590 CHECK (ZSTD_isError(errorCode), "ZSTD_compressBegin_usingDict error : %s", ZSTD_getErrorName(errorCode));
Yann Collet7b51a292016-01-26 15:58:49 +0100591 errorCode = ZSTD_copyCCtx(ctx, refCtx);
Yann Collet464fa992016-02-03 01:09:46 +0100592 CHECK (ZSTD_isError(errorCode), "ZSTD_copyCCtx error : %s", ZSTD_getErrorName(errorCode));
Yann Colletecd651b2016-01-07 15:35:18 +0100593 totalTestSize = 0; cSize = 0;
Yann Colletd1d210f2016-03-19 12:12:07 +0100594 for (n=0; n<nbChunks; n++) {
Yann Collet417890c2015-12-04 17:16:37 +0100595 sampleSizeLog = FUZ_rand(&lseed) % maxSampleLog;
596 sampleSize = (size_t)1 << sampleSizeLog;
597 sampleSize += FUZ_rand(&lseed) & (sampleSize-1);
598 sampleStart = FUZ_rand(&lseed) % (srcBufferSize - sampleSize);
599
600 if (cBufferSize-cSize < ZSTD_compressBound(sampleSize))
601 /* avoid invalid dstBufferTooSmall */
602 break;
Yann Collete47c4e52015-12-05 09:23:53 +0100603 if (totalTestSize+sampleSize > maxTestSize) break;
Yann Collet417890c2015-12-04 17:16:37 +0100604
605 errorCode = ZSTD_compressContinue(ctx, cBuffer+cSize, cBufferSize-cSize, srcBuffer+sampleStart, sampleSize);
606 CHECK (ZSTD_isError(errorCode), "multi-segments compression error : %s", ZSTD_getErrorName(errorCode));
607 cSize += errorCode;
608
Yann Collet5835e1b2016-01-05 01:44:36 +0100609 XXH64_update(xxh64, srcBuffer+sampleStart, sampleSize);
Yann Collete47c4e52015-12-05 09:23:53 +0100610 memcpy(mirrorBuffer + totalTestSize, srcBuffer+sampleStart, sampleSize);
Yann Collet417890c2015-12-04 17:16:37 +0100611 totalTestSize += sampleSize;
Yann Collet417890c2015-12-04 17:16:37 +0100612 }
613 errorCode = ZSTD_compressEnd(ctx, cBuffer+cSize, cBufferSize-cSize);
614 CHECK (ZSTD_isError(errorCode), "multi-segments epilogue error : %s", ZSTD_getErrorName(errorCode));
615 cSize += errorCode;
Yann Collet5835e1b2016-01-05 01:44:36 +0100616 crcOrig = XXH64_digest(xxh64);
Yann Collete47c4e52015-12-05 09:23:53 +0100617
618 /* streaming decompression test */
Yann Collet7b51a292016-01-26 15:58:49 +0100619 errorCode = ZSTD_decompressBegin_usingDict(dctx, dict, dictSize);
Yann Collete47c4e52015-12-05 09:23:53 +0100620 CHECK (ZSTD_isError(errorCode), "cannot init DCtx : %s", ZSTD_getErrorName(errorCode));
621 totalCSize = 0;
622 totalGenSize = 0;
Yann Colletd1d210f2016-03-19 12:12:07 +0100623 while (totalCSize < cSize) {
Yann Collete47c4e52015-12-05 09:23:53 +0100624 size_t inSize = ZSTD_nextSrcSizeToDecompress(dctx);
625 size_t genSize = ZSTD_decompressContinue(dctx, dstBuffer+totalGenSize, dstBufferSize-totalGenSize, cBuffer+totalCSize, inSize);
626 CHECK (ZSTD_isError(genSize), "streaming decompression error : %s", ZSTD_getErrorName(genSize));
627 totalGenSize += genSize;
628 totalCSize += inSize;
629 }
630 CHECK (ZSTD_nextSrcSizeToDecompress(dctx) != 0, "frame not fully decoded");
631 CHECK (totalGenSize != totalTestSize, "decompressed data : wrong size")
632 CHECK (totalCSize != cSize, "compressed data should be fully read")
633 crcDest = XXH64(dstBuffer, totalTestSize, 0);
634 if (crcDest!=crcOrig)
635 errorCode = findDiff(mirrorBuffer, dstBuffer, totalTestSize);
636 CHECK (crcDest!=crcOrig, "streaming decompressed data corrupted : byte %u / %u (%02X!=%02X)",
637 (U32)errorCode, (U32)totalTestSize, dstBuffer[errorCode], mirrorBuffer[errorCode]);
Yann Collet4856a002015-01-24 01:58:16 +0100638 }
Yann Collet1c2ddba2015-12-04 17:45:35 +0100639 DISPLAY("\r%u fuzzer tests completed \n", testNb-1);
Yann Collet4856a002015-01-24 01:58:16 +0100640
641_cleanup:
Yann Colletecd651b2016-01-07 15:35:18 +0100642 ZSTD_freeCCtx(refCtx);
Yann Collet2f648e52015-10-29 18:23:38 +0100643 ZSTD_freeCCtx(ctx);
Yann Collete47c4e52015-12-05 09:23:53 +0100644 ZSTD_freeDCtx(dctx);
Yann Colletd5d9bc32015-08-23 23:13:49 +0100645 free(cNoiseBuffer[0]);
646 free(cNoiseBuffer[1]);
647 free(cNoiseBuffer[2]);
648 free(cNoiseBuffer[3]);
649 free(cNoiseBuffer[4]);
Yann Collet4856a002015-01-24 01:58:16 +0100650 free(cBuffer);
651 free(dstBuffer);
Yann Collete47c4e52015-12-05 09:23:53 +0100652 free(mirrorBuffer);
Yann Collet4856a002015-01-24 01:58:16 +0100653 return result;
654
655_output_error:
656 result = 1;
657 goto _cleanup;
658}
659
660
Yann Colletd1d210f2016-03-19 12:12:07 +0100661/*_*******************************************************
Yann Collet4856a002015-01-24 01:58:16 +0100662* Command line
663*********************************************************/
Yann Colletd1d210f2016-03-19 12:12:07 +0100664int FUZ_usage(const char* programName)
Yann Collet4856a002015-01-24 01:58:16 +0100665{
666 DISPLAY( "Usage :\n");
667 DISPLAY( " %s [args]\n", programName);
668 DISPLAY( "\n");
669 DISPLAY( "Arguments :\n");
670 DISPLAY( " -i# : Nb of tests (default:%u) \n", nbTestsDefault);
671 DISPLAY( " -s# : Select seed (default:prompt user)\n");
672 DISPLAY( " -t# : Select starting test number (default:0)\n");
Yann Collet0d9ce042016-03-19 13:21:08 +0100673 DISPLAY( " -P# : Select compressibility in %% (default:%u%%)\n", FUZ_compressibility_default);
Yann Collet4856a002015-01-24 01:58:16 +0100674 DISPLAY( " -v : verbose\n");
Yann Collete9853b22015-08-07 19:07:32 +0100675 DISPLAY( " -p : pause at the end\n");
Yann Collet4856a002015-01-24 01:58:16 +0100676 DISPLAY( " -h : display help and exit\n");
677 return 0;
678}
679
680
Yann Colletd1d210f2016-03-19 12:12:07 +0100681int main(int argc, const char** argv)
Yann Collet4856a002015-01-24 01:58:16 +0100682{
683 U32 seed=0;
684 int seedset=0;
685 int argNb;
686 int nbTests = nbTestsDefault;
687 int testNb = 0;
Yann Collet0d9ce042016-03-19 13:21:08 +0100688 U32 proba = FUZ_compressibility_default;
Yann Collet4856a002015-01-24 01:58:16 +0100689 int result=0;
690 U32 mainPause = 0;
Yann Collet0d9ce042016-03-19 13:21:08 +0100691 U32 maxDuration = 0;
Yann Colletd1d210f2016-03-19 12:12:07 +0100692 const char* programName;
Yann Collet4856a002015-01-24 01:58:16 +0100693
694 /* Check command line */
695 programName = argv[0];
Yann Colletd1d210f2016-03-19 12:12:07 +0100696 for (argNb=1; argNb<argc; argNb++) {
697 const char* argument = argv[argNb];
Yann Collet4856a002015-01-24 01:58:16 +0100698 if(!argument) continue; /* Protection if argument empty */
699
700 /* Handle commands. Aggregated commands are allowed */
Yann Colletd1d210f2016-03-19 12:12:07 +0100701 if (argument[0]=='-') {
Yann Collet4856a002015-01-24 01:58:16 +0100702 argument++;
Yann Colletd1d210f2016-03-19 12:12:07 +0100703 while (*argument!=0) {
Yann Collet4856a002015-01-24 01:58:16 +0100704 switch(*argument)
705 {
706 case 'h':
707 return FUZ_usage(programName);
708 case 'v':
709 argument++;
710 g_displayLevel=4;
711 break;
712 case 'q':
713 argument++;
714 g_displayLevel--;
715 break;
716 case 'p': /* pause at the end */
717 argument++;
718 mainPause = 1;
719 break;
720
721 case 'i':
Yann Collet0d9ce042016-03-19 13:21:08 +0100722 argument++; maxDuration=0;
Yann Collet4856a002015-01-24 01:58:16 +0100723 nbTests=0;
Yann Colletd1d210f2016-03-19 12:12:07 +0100724 while ((*argument>='0') && (*argument<='9')) {
Yann Collet4856a002015-01-24 01:58:16 +0100725 nbTests *= 10;
726 nbTests += *argument - '0';
727 argument++;
728 }
729 break;
730
Yann Collet553cf6a2015-12-04 17:25:26 +0100731 case 'T':
732 argument++;
Yann Collet0d9ce042016-03-19 13:21:08 +0100733 nbTests=0; maxDuration=0;
Yann Colletd1d210f2016-03-19 12:12:07 +0100734 while ((*argument>='0') && (*argument<='9')) {
Yann Collet0d9ce042016-03-19 13:21:08 +0100735 maxDuration *= 10;
736 maxDuration += *argument - '0';
Yann Collet553cf6a2015-12-04 17:25:26 +0100737 argument++;
738 }
Yann Collet0d9ce042016-03-19 13:21:08 +0100739 if (*argument=='m') maxDuration *=60, argument++;
Yann Collet553cf6a2015-12-04 17:25:26 +0100740 if (*argument=='n') argument++;
Yann Collet0d9ce042016-03-19 13:21:08 +0100741 maxDuration *= 1000;
Yann Collet553cf6a2015-12-04 17:25:26 +0100742 break;
743
Yann Collet4856a002015-01-24 01:58:16 +0100744 case 's':
745 argument++;
746 seed=0;
747 seedset=1;
Yann Colletd1d210f2016-03-19 12:12:07 +0100748 while ((*argument>='0') && (*argument<='9')) {
Yann Collet4856a002015-01-24 01:58:16 +0100749 seed *= 10;
750 seed += *argument - '0';
751 argument++;
752 }
753 break;
754
755 case 't':
756 argument++;
757 testNb=0;
Yann Colletd1d210f2016-03-19 12:12:07 +0100758 while ((*argument>='0') && (*argument<='9')) {
Yann Collet4856a002015-01-24 01:58:16 +0100759 testNb *= 10;
760 testNb += *argument - '0';
761 argument++;
762 }
763 break;
764
765 case 'P': /* compressibility % */
766 argument++;
767 proba=0;
Yann Colletd1d210f2016-03-19 12:12:07 +0100768 while ((*argument>='0') && (*argument<='9')) {
Yann Collet4856a002015-01-24 01:58:16 +0100769 proba *= 10;
770 proba += *argument - '0';
771 argument++;
772 }
Yann Collet4856a002015-01-24 01:58:16 +0100773 if (proba>100) proba=100;
774 break;
775
776 default:
777 return FUZ_usage(programName);
Yann Colletd1d210f2016-03-19 12:12:07 +0100778 } } } } /* for (argNb=1; argNb<argc; argNb++) */
Yann Collet4856a002015-01-24 01:58:16 +0100779
780 /* Get Seed */
781 DISPLAY("Starting zstd tester (%i-bits, %s)\n", (int)(sizeof(size_t)*8), ZSTD_VERSION);
782
783 if (!seedset) seed = FUZ_GetMilliStart() % 10000;
784 DISPLAY("Seed = %u\n", seed);
Yann Collet0d9ce042016-03-19 13:21:08 +0100785 if (proba!=FUZ_compressibility_default) DISPLAY("Compressibility : %u%%\n", proba);
Yann Collet4856a002015-01-24 01:58:16 +0100786
Yann Colletd1d210f2016-03-19 12:12:07 +0100787 if (testNb==0)
788 result = basicUnitTests(0, ((double)proba) / 100); /* constant seed for predictability */
Yann Collet4856a002015-01-24 01:58:16 +0100789 if (!result)
Yann Collet0d9ce042016-03-19 13:21:08 +0100790 result = fuzzerTests(seed, nbTests, testNb, maxDuration, ((double)proba) / 100);
Yann Colletd1d210f2016-03-19 12:12:07 +0100791 if (mainPause) {
Yann Colletb5e06dc2015-07-04 23:20:56 -0800792 int unused;
Yann Collet4856a002015-01-24 01:58:16 +0100793 DISPLAY("Press Enter \n");
Yann Colletb5e06dc2015-07-04 23:20:56 -0800794 unused = getchar();
795 (void)unused;
Yann Collet4856a002015-01-24 01:58:16 +0100796 }
797 return result;
798}