blob: b92c21f1bda722f01da3c04b6d0f8926b5b19b47 [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 */
Yann Colletea63bb72016-04-08 15:25:32 +020042#include <time.h> /* clock_t */
Yann Collet45f84ab2016-05-20 12:34:40 +020043#include "zstd_static.h" /* ZSTD_VERSION_STRING */
Yann Colletd5d9bc32015-08-23 23:13:49 +010044#include "datagen.h" /* RDG_genBuffer */
Yann Collet353c5d22015-10-21 14:39:26 +010045#include "mem.h"
Yann Collet6c903a82016-05-28 13:34:07 +020046#define XXH_STATIC_LINKING_ONLY
47#include "xxhash.h" /* XXH64 */
Yann Collet4856a002015-01-24 01:58:16 +010048
49
Yann Collet0d9ce042016-03-19 13:21:08 +010050/*-************************************
51* Constants
Yann Collet4856a002015-01-24 01:58:16 +010052**************************************/
Yann Collet4856a002015-01-24 01:58:16 +010053#define KB *(1U<<10)
54#define MB *(1U<<20)
55#define GB *(1U<<30)
56
Yann Collet0d9ce042016-03-19 13:21:08 +010057static const size_t COMPRESSIBLE_NOISE_LENGTH = 10 MB; /* capital, used to be a macro */
58static const U32 FUZ_compressibility_default = 50;
Yann Collet110cc142015-11-19 12:02:28 +010059static const U32 nbTestsDefault = 30000;
Yann Collet4856a002015-01-24 01:58:16 +010060
61
Yann Collet0d9ce042016-03-19 13:21:08 +010062/*-************************************
Yann Collet4856a002015-01-24 01:58:16 +010063* Display Macros
64**************************************/
65#define DISPLAY(...) fprintf(stderr, __VA_ARGS__)
66#define DISPLAYLEVEL(l, ...) if (g_displayLevel>=l) { DISPLAY(__VA_ARGS__); }
67static U32 g_displayLevel = 2;
68
69#define DISPLAYUPDATE(l, ...) if (g_displayLevel>=l) { \
Yann Colletea63bb72016-04-08 15:25:32 +020070 if ((FUZ_clockSpan(g_displayClock) > g_refreshRate) || (g_displayLevel>=4)) \
71 { g_displayClock = clock(); DISPLAY(__VA_ARGS__); \
Yann Collet4856a002015-01-24 01:58:16 +010072 if (g_displayLevel>=4) fflush(stdout); } }
Yann Colletea63bb72016-04-08 15:25:32 +020073static const clock_t g_refreshRate = CLOCKS_PER_SEC * 150 / 1000;
74static clock_t g_displayClock = 0;
Yann Collet553cf6a2015-12-04 17:25:26 +010075
Yann Collet4856a002015-01-24 01:58:16 +010076
Yann Collet0d9ce042016-03-19 13:21:08 +010077/*-*******************************************************
Yann Collet4856a002015-01-24 01:58:16 +010078* Fuzzer functions
79*********************************************************/
Yann Collete93add02016-02-15 17:44:14 +010080#define MIN(a,b) ((a)<(b)?(a):(b))
Yann Collet110cc142015-11-19 12:02:28 +010081#define MAX(a,b) ((a)>(b)?(a):(b))
82
Yann Colletea63bb72016-04-08 15:25:32 +020083static clock_t FUZ_clockSpan(clock_t cStart)
Yann Collet4856a002015-01-24 01:58:16 +010084{
Yann Colletea63bb72016-04-08 15:25:32 +020085 return clock() - cStart; /* works even when overflow; max span ~ 30mn */
Yann Collet4856a002015-01-24 01:58:16 +010086}
87
88
89# define FUZ_rotl32(x,r) ((x << r) | (x >> (32 - r)))
Yann Collet33341de2016-05-29 23:09:51 +020090unsigned FUZ_rand(unsigned* src)
Yann Collet4856a002015-01-24 01:58:16 +010091{
Yann Collet0d9ce042016-03-19 13:21:08 +010092 static const U32 prime1 = 2654435761U;
93 static const U32 prime2 = 2246822519U;
Yann Collet4856a002015-01-24 01:58:16 +010094 U32 rand32 = *src;
95 rand32 *= prime1;
96 rand32 += prime2;
97 rand32 = FUZ_rotl32(rand32, 13);
98 *src = rand32;
99 return rand32 >> 5;
100}
101
102
Yann Collet997f9ee2015-08-21 02:44:20 +0100103static unsigned FUZ_highbit32(U32 v32)
Yann Collet4856a002015-01-24 01:58:16 +0100104{
105 unsigned nbBits = 0;
106 if (v32==0) return 0;
Yann Collet0d9ce042016-03-19 13:21:08 +0100107 while (v32) {
Yann Collet4856a002015-01-24 01:58:16 +0100108 v32 >>= 1;
109 nbBits ++;
110 }
111 return nbBits;
112}
Yann Collet4856a002015-01-24 01:58:16 +0100113
114
115static int basicUnitTests(U32 seed, double compressibility)
116{
117 int testResult = 0;
Yann Collet33341de2016-05-29 23:09:51 +0200118 void* const CNBuffer = malloc(COMPRESSIBLE_NOISE_LENGTH);
119 void* const compressedBuffer = malloc(ZSTD_compressBound(COMPRESSIBLE_NOISE_LENGTH));
120 void* const decodedBuffer = malloc(COMPRESSIBLE_NOISE_LENGTH);
Yann Collet4856a002015-01-24 01:58:16 +0100121 U32 randState = seed;
122 size_t result, cSize;
123 U32 testNb=0;
124
Yann Colletd5d9bc32015-08-23 23:13:49 +0100125 /* Create compressible test buffer */
Yann Colletd1d210f2016-03-19 12:12:07 +0100126 if (!CNBuffer || !compressedBuffer || !decodedBuffer) {
Yann Collet94f998b2015-07-04 23:10:40 -0800127 DISPLAY("Not enough memory, aborting\n");
128 testResult = 1;
129 goto _end;
130 }
Yann Colletd5d9bc32015-08-23 23:13:49 +0100131 RDG_genBuffer(CNBuffer, COMPRESSIBLE_NOISE_LENGTH, compressibility, 0., randState);
Yann Collet4856a002015-01-24 01:58:16 +0100132
Yann Colletd5d9bc32015-08-23 23:13:49 +0100133 /* Basic tests */
Yann Collet0d9ce042016-03-19 13:21:08 +0100134 DISPLAYLEVEL(4, "test%3i : compress %u bytes : ", testNb++, (U32)COMPRESSIBLE_NOISE_LENGTH);
Yann Collet5be2dd22015-11-11 13:43:58 +0100135 result = ZSTD_compress(compressedBuffer, ZSTD_compressBound(COMPRESSIBLE_NOISE_LENGTH), CNBuffer, COMPRESSIBLE_NOISE_LENGTH, 1);
Yann Collet4856a002015-01-24 01:58:16 +0100136 if (ZSTD_isError(result)) goto _output_error;
137 cSize = result;
138 DISPLAYLEVEL(4, "OK (%u bytes : %.2f%%)\n", (U32)cSize, (double)cSize/COMPRESSIBLE_NOISE_LENGTH*100);
139
Yann Collet0d9ce042016-03-19 13:21:08 +0100140 DISPLAYLEVEL(4, "test%3i : decompress %u bytes : ", testNb++, (U32)COMPRESSIBLE_NOISE_LENGTH);
Yann Collet4856a002015-01-24 01:58:16 +0100141 result = ZSTD_decompress(decodedBuffer, COMPRESSIBLE_NOISE_LENGTH, compressedBuffer, cSize);
142 if (ZSTD_isError(result)) goto _output_error;
Yann Collet4ec29982016-03-04 19:09:28 +0100143 if (result != COMPRESSIBLE_NOISE_LENGTH) goto _output_error;
Yann Collet4856a002015-01-24 01:58:16 +0100144 DISPLAYLEVEL(4, "OK \n");
145
Yann Colletd1d210f2016-03-19 12:12:07 +0100146 { size_t i;
Yann Collet4856a002015-01-24 01:58:16 +0100147 DISPLAYLEVEL(4, "test%3i : check decompressed result : ", testNb++);
Yann Colletd1d210f2016-03-19 12:12:07 +0100148 for (i=0; i<COMPRESSIBLE_NOISE_LENGTH; i++) {
Yann Collet4856a002015-01-24 01:58:16 +0100149 if (((BYTE*)decodedBuffer)[i] != ((BYTE*)CNBuffer)[i]) goto _output_error;;
150 }
151 DISPLAYLEVEL(4, "OK \n");
152 }
153
154 DISPLAYLEVEL(4, "test%3i : decompress with 1 missing byte : ", testNb++);
155 result = ZSTD_decompress(decodedBuffer, COMPRESSIBLE_NOISE_LENGTH, compressedBuffer, cSize-1);
156 if (!ZSTD_isError(result)) goto _output_error;
Yann Collet977f1f32016-01-21 15:38:47 +0100157 if (result != (size_t)-ZSTD_error_srcSize_wrong) goto _output_error;
Yann Collet4856a002015-01-24 01:58:16 +0100158 DISPLAYLEVEL(4, "OK \n");
159
160 DISPLAYLEVEL(4, "test%3i : decompress with 1 too much byte : ", testNb++);
161 result = ZSTD_decompress(decodedBuffer, COMPRESSIBLE_NOISE_LENGTH, compressedBuffer, cSize+1);
162 if (!ZSTD_isError(result)) goto _output_error;
Yann Collet977f1f32016-01-21 15:38:47 +0100163 if (result != (size_t)-ZSTD_error_srcSize_wrong) goto _output_error;
Yann Collet4856a002015-01-24 01:58:16 +0100164 DISPLAYLEVEL(4, "OK \n");
165
Yann Collet389648c2016-04-12 19:13:08 +0200166 /* Dictionary and CCtx Duplication tests */
Yann Colletd1d210f2016-03-19 12:12:07 +0100167 { ZSTD_CCtx* ctxOrig = ZSTD_createCCtx();
Yann Collet60096272016-01-08 17:27:50 +0100168 ZSTD_CCtx* ctxDuplicated = ZSTD_createCCtx();
169 ZSTD_DCtx* dctx = ZSTD_createDCtx();
Yann Collet541dc7c2016-04-12 18:00:20 +0200170 size_t const dictSize = 500;
Yann Collet60096272016-01-08 17:27:50 +0100171
Yann Collet887e7da2016-04-11 20:12:27 +0200172 DISPLAYLEVEL(4, "test%3i : copy context too soon : ", testNb++);
Yann Collet389648c2016-04-12 19:13:08 +0200173 { size_t const copyResult = ZSTD_copyCCtx(ctxDuplicated, ctxOrig);
174 if (!ZSTD_isError(copyResult)) goto _output_error; } /* error should be detected */
Yann Collet887e7da2016-04-11 20:12:27 +0200175 DISPLAYLEVEL(4, "OK \n");
176
Yann Collet60096272016-01-08 17:27:50 +0100177 DISPLAYLEVEL(4, "test%3i : load dictionary into context : ", testNb++);
Yann Collet887e7da2016-04-11 20:12:27 +0200178 { size_t const initResult = ZSTD_compressBegin_usingDict(ctxOrig, CNBuffer, dictSize, 2);
179 if (ZSTD_isError(initResult)) goto _output_error; }
180 { size_t const copyResult = ZSTD_copyCCtx(ctxDuplicated, ctxOrig);
181 if (ZSTD_isError(copyResult)) goto _output_error; }
Yann Collet60096272016-01-08 17:27:50 +0100182 DISPLAYLEVEL(4, "OK \n");
183
184 DISPLAYLEVEL(4, "test%3i : compress with dictionary : ", testNb++);
185 cSize = 0;
186 result = ZSTD_compressContinue(ctxOrig, compressedBuffer, ZSTD_compressBound(COMPRESSIBLE_NOISE_LENGTH), (const char*)CNBuffer + dictSize, COMPRESSIBLE_NOISE_LENGTH - dictSize);
187 if (ZSTD_isError(result)) goto _output_error;
188 cSize += result;
189 result = ZSTD_compressEnd(ctxOrig, (char*)compressedBuffer+cSize, ZSTD_compressBound(COMPRESSIBLE_NOISE_LENGTH)-cSize);
190 if (ZSTD_isError(result)) goto _output_error;
191 cSize += result;
192 DISPLAYLEVEL(4, "OK (%u bytes : %.2f%%)\n", (U32)cSize, (double)cSize/COMPRESSIBLE_NOISE_LENGTH*100);
193
194 DISPLAYLEVEL(4, "test%3i : frame built with dictionary should be decompressible : ", testNb++);
195 result = ZSTD_decompress_usingDict(dctx,
196 decodedBuffer, COMPRESSIBLE_NOISE_LENGTH,
197 compressedBuffer, cSize,
198 CNBuffer, dictSize);
199 if (ZSTD_isError(result)) goto _output_error;
Yann Colletbf42c8e2016-01-09 01:08:23 +0100200 if (result != COMPRESSIBLE_NOISE_LENGTH - dictSize) goto _output_error;
Yann Collet60096272016-01-08 17:27:50 +0100201 DISPLAYLEVEL(4, "OK \n");
202
203 DISPLAYLEVEL(4, "test%3i : compress with duplicated context : ", testNb++);
Yann Collet389648c2016-04-12 19:13:08 +0200204 { size_t const cSizeOrig = cSize;
205 cSize = 0;
206 result = ZSTD_compressContinue(ctxDuplicated, compressedBuffer, ZSTD_compressBound(COMPRESSIBLE_NOISE_LENGTH), (const char*)CNBuffer + dictSize, COMPRESSIBLE_NOISE_LENGTH - dictSize);
207 if (ZSTD_isError(result)) goto _output_error;
208 cSize += result;
209 result = ZSTD_compressEnd(ctxDuplicated, (char*)compressedBuffer+cSize, ZSTD_compressBound(COMPRESSIBLE_NOISE_LENGTH)-cSize);
210 if (ZSTD_isError(result)) goto _output_error;
211 cSize += result;
212 if (cSize != cSizeOrig) goto _output_error; /* should be identical == have same size */
213 }
Yann Collet60096272016-01-08 17:27:50 +0100214 DISPLAYLEVEL(4, "OK (%u bytes : %.2f%%)\n", (U32)cSize, (double)cSize/COMPRESSIBLE_NOISE_LENGTH*100);
215
216 DISPLAYLEVEL(4, "test%3i : frame built with duplicated context should be decompressible : ", testNb++);
217 result = ZSTD_decompress_usingDict(dctx,
218 decodedBuffer, COMPRESSIBLE_NOISE_LENGTH,
219 compressedBuffer, cSize,
220 CNBuffer, dictSize);
221 if (ZSTD_isError(result)) goto _output_error;
Yann Colletbf42c8e2016-01-09 01:08:23 +0100222 if (result != COMPRESSIBLE_NOISE_LENGTH - dictSize) goto _output_error;
Yann Collet60096272016-01-08 17:27:50 +0100223 DISPLAYLEVEL(4, "OK \n");
Yann Collet541dc7c2016-04-12 18:00:20 +0200224
225 DISPLAYLEVEL(4, "test%3i : check content size on duplicated context : ", testNb++);
226 { size_t const testSize = COMPRESSIBLE_NOISE_LENGTH / 3;
Yann Collet33341de2016-05-29 23:09:51 +0200227 { ZSTD_parameters const p = (ZSTD_parameters) { ZSTD_getCParams(2, testSize, dictSize), { 1, 0 } };
228 size_t const initResult = ZSTD_compressBegin_advanced(ctxOrig, CNBuffer, dictSize, p, testSize-1);
229 if (ZSTD_isError(initResult)) goto _output_error;
230 }
Yann Collet541dc7c2016-04-12 18:00:20 +0200231 { size_t const copyResult = ZSTD_copyCCtx(ctxDuplicated, ctxOrig);
232 if (ZSTD_isError(copyResult)) goto _output_error; }
233 cSize = ZSTD_compressContinue(ctxDuplicated, compressedBuffer, ZSTD_compressBound(testSize), (const char*)CNBuffer + dictSize, COMPRESSIBLE_NOISE_LENGTH - dictSize);
234 if (ZSTD_isError(cSize)) goto _output_error;
235 { ZSTD_frameParams fp;
Yann Collet33341de2016-05-29 23:09:51 +0200236 if (ZSTD_getFrameParams(&fp, compressedBuffer, cSize)) goto _output_error;
Yann Collet541dc7c2016-04-12 18:00:20 +0200237 if ((fp.frameContentSize != testSize) && (fp.frameContentSize != 0)) goto _output_error;
238 } }
239 DISPLAYLEVEL(4, "OK \n");
240
241 ZSTD_freeCCtx(ctxOrig);
242 ZSTD_freeCCtx(ctxDuplicated);
243 ZSTD_freeDCtx(dctx);
Yann Collet60096272016-01-08 17:27:50 +0100244 }
245
Yann Collet4856a002015-01-24 01:58:16 +0100246 /* Decompression defense tests */
247 DISPLAYLEVEL(4, "test%3i : Check input length for magic number : ", testNb++);
248 result = ZSTD_decompress(decodedBuffer, COMPRESSIBLE_NOISE_LENGTH, CNBuffer, 3);
249 if (!ZSTD_isError(result)) goto _output_error;
Yann Collet977f1f32016-01-21 15:38:47 +0100250 if (result != (size_t)-ZSTD_error_srcSize_wrong) goto _output_error;
Yann Collet4856a002015-01-24 01:58:16 +0100251 DISPLAYLEVEL(4, "OK \n");
252
253 DISPLAYLEVEL(4, "test%3i : Check magic Number : ", testNb++);
254 ((char*)(CNBuffer))[0] = 1;
Yann Collet33341de2016-05-29 23:09:51 +0200255 { size_t const r = ZSTD_decompress(decodedBuffer, COMPRESSIBLE_NOISE_LENGTH, CNBuffer, 4);
256 if (!ZSTD_isError(r)) goto _output_error; }
Yann Collet4856a002015-01-24 01:58:16 +0100257 DISPLAYLEVEL(4, "OK \n");
258
Yann Colletbf42c8e2016-01-09 01:08:23 +0100259 /* block API tests */
Yann Colletd1d210f2016-03-19 12:12:07 +0100260 { ZSTD_CCtx* const cctx = ZSTD_createCCtx();
Yann Colletbf42c8e2016-01-09 01:08:23 +0100261 ZSTD_DCtx* const dctx = ZSTD_createDCtx();
Yann Collet33341de2016-05-29 23:09:51 +0200262 static const size_t blockSize = 100 KB;
263 static const size_t dictSize = 16 KB;
Yann Colletbf42c8e2016-01-09 01:08:23 +0100264
265 /* basic block compression */
266 DISPLAYLEVEL(4, "test%3i : Block compression test : ", testNb++);
Yann Collet33341de2016-05-29 23:09:51 +0200267 { size_t const r = ZSTD_compressBegin(cctx, 5);
268 if (ZSTD_isError(r)) goto _output_error; }
Yann Colletbf42c8e2016-01-09 01:08:23 +0100269 cSize = ZSTD_compressBlock(cctx, compressedBuffer, ZSTD_compressBound(blockSize), CNBuffer, blockSize);
270 if (ZSTD_isError(cSize)) goto _output_error;
271 DISPLAYLEVEL(4, "OK \n");
272
273 DISPLAYLEVEL(4, "test%3i : Block decompression test : ", testNb++);
Yann Collet7b51a292016-01-26 15:58:49 +0100274 result = ZSTD_decompressBegin(dctx);
Yann Colletbf42c8e2016-01-09 01:08:23 +0100275 if (ZSTD_isError(result)) goto _output_error;
276 result = ZSTD_decompressBlock(dctx, decodedBuffer, COMPRESSIBLE_NOISE_LENGTH, compressedBuffer, cSize);
277 if (ZSTD_isError(result)) goto _output_error;
278 if (result != blockSize) goto _output_error;
279 DISPLAYLEVEL(4, "OK \n");
280
Yann Colletb0125102016-01-09 02:00:10 +0100281 /* dictionary block compression */
282 DISPLAYLEVEL(4, "test%3i : Dictionary Block compression test : ", testNb++);
Yann Collet1c8e1942016-01-26 16:31:22 +0100283 result = ZSTD_compressBegin_usingDict(cctx, CNBuffer, dictSize, 5);
Yann Colletb0125102016-01-09 02:00:10 +0100284 if (ZSTD_isError(result)) goto _output_error;
285 cSize = ZSTD_compressBlock(cctx, compressedBuffer, ZSTD_compressBound(blockSize), (char*)CNBuffer+dictSize, blockSize);
286 if (ZSTD_isError(cSize)) goto _output_error;
287 DISPLAYLEVEL(4, "OK \n");
288
289 DISPLAYLEVEL(4, "test%3i : Dictionary Block decompression test : ", testNb++);
Yann Collet7b51a292016-01-26 15:58:49 +0100290 result = ZSTD_decompressBegin_usingDict(dctx, CNBuffer, dictSize);
Yann Colletb0125102016-01-09 02:00:10 +0100291 if (ZSTD_isError(result)) goto _output_error;
Yann Colletb0125102016-01-09 02:00:10 +0100292 result = ZSTD_decompressBlock(dctx, decodedBuffer, COMPRESSIBLE_NOISE_LENGTH, compressedBuffer, cSize);
293 if (ZSTD_isError(result)) goto _output_error;
294 if (result != blockSize) goto _output_error;
295 DISPLAYLEVEL(4, "OK \n");
296
Yann Colletbf42c8e2016-01-09 01:08:23 +0100297 ZSTD_freeCCtx(cctx);
298 ZSTD_freeDCtx(dctx);
299 }
300
Yann Collet213089c2015-06-18 07:43:16 -0800301 /* long rle test */
Yann Colletd1d210f2016-03-19 12:12:07 +0100302 { size_t sampleSize = 0;
Yann Collet213089c2015-06-18 07:43:16 -0800303 DISPLAYLEVEL(4, "test%3i : Long RLE test : ", testNb++);
Yann Colletd5d9bc32015-08-23 23:13:49 +0100304 RDG_genBuffer(CNBuffer, sampleSize, compressibility, 0., randState);
Yann Collet213089c2015-06-18 07:43:16 -0800305 memset((char*)CNBuffer+sampleSize, 'B', 256 KB - 1);
306 sampleSize += 256 KB - 1;
Yann Colletd5d9bc32015-08-23 23:13:49 +0100307 RDG_genBuffer((char*)CNBuffer+sampleSize, 96 KB, compressibility, 0., randState);
Yann Collet213089c2015-06-18 07:43:16 -0800308 sampleSize += 96 KB;
Yann Collet5be2dd22015-11-11 13:43:58 +0100309 cSize = ZSTD_compress(compressedBuffer, ZSTD_compressBound(sampleSize), CNBuffer, sampleSize, 1);
Yann Collet213089c2015-06-18 07:43:16 -0800310 if (ZSTD_isError(cSize)) goto _output_error;
311 result = ZSTD_decompress(decodedBuffer, sampleSize, compressedBuffer, cSize);
312 if (ZSTD_isError(result)) goto _output_error;
313 if (result!=sampleSize) goto _output_error;
314 DISPLAYLEVEL(4, "OK \n");
315 }
316
Yann Collet4ba85342016-03-07 20:01:45 +0100317 /* All zeroes test (#137 verif) */
318 #define ZEROESLENGTH 100
319 DISPLAYLEVEL(4, "test%3i : compress %u zeroes : ", testNb++, ZEROESLENGTH);
320 memset(CNBuffer, 0, ZEROESLENGTH);
321 result = ZSTD_compress(compressedBuffer, ZSTD_compressBound(ZEROESLENGTH), CNBuffer, ZEROESLENGTH, 1);
322 if (ZSTD_isError(result)) goto _output_error;
323 cSize = result;
324 DISPLAYLEVEL(4, "OK (%u bytes : %.2f%%)\n", (U32)cSize, (double)cSize/ZEROESLENGTH*100);
325
326 DISPLAYLEVEL(4, "test%3i : decompress %u zeroes : ", testNb++, ZEROESLENGTH);
327 result = ZSTD_decompress(decodedBuffer, ZEROESLENGTH, compressedBuffer, cSize);
328 if (ZSTD_isError(result)) goto _output_error;
329 if (result != ZEROESLENGTH) goto _output_error;
330 DISPLAYLEVEL(4, "OK \n");
331
332 /* nbSeq limit test */
Yann Colletd1d210f2016-03-19 12:12:07 +0100333 #define _3BYTESTESTLENGTH 131000
334 #define NB3BYTESSEQLOG 9
335 #define NB3BYTESSEQ (1 << NB3BYTESSEQLOG)
336 #define NB3BYTESSEQMASK (NB3BYTESSEQ-1)
Yann Collet0d9ce042016-03-19 13:21:08 +0100337 /* creates a buffer full of 3-bytes sequences */
Yann Colletd1d210f2016-03-19 12:12:07 +0100338 { BYTE _3BytesSeqs[NB3BYTESSEQ][3];
Yann Collet0d9ce042016-03-19 13:21:08 +0100339 U32 rSeed = 1;
Yann Collet4ba85342016-03-07 20:01:45 +0100340
Yann Collet0d9ce042016-03-19 13:21:08 +0100341 /* create batch of 3-bytes sequences */
Yann Colletd1d210f2016-03-19 12:12:07 +0100342 { int i; for (i=0; i < NB3BYTESSEQ; i++) {
Yann Collet0d9ce042016-03-19 13:21:08 +0100343 _3BytesSeqs[i][0] = (BYTE)(FUZ_rand(&rSeed) & 255);
344 _3BytesSeqs[i][1] = (BYTE)(FUZ_rand(&rSeed) & 255);
345 _3BytesSeqs[i][2] = (BYTE)(FUZ_rand(&rSeed) & 255);
Yann Colletd1d210f2016-03-19 12:12:07 +0100346 }}
Yann Collet4ba85342016-03-07 20:01:45 +0100347
Yann Collet0d9ce042016-03-19 13:21:08 +0100348 /* randomly fills CNBuffer with prepared 3-bytes sequences */
349 { int i; for (i=0; i < _3BYTESTESTLENGTH; ) { /* note : CNBuffer size > _3BYTESTESTLENGTH+3 */
350 U32 id = FUZ_rand(&rSeed) & NB3BYTESSEQMASK;
Yann Collet4ba85342016-03-07 20:01:45 +0100351 ((BYTE*)CNBuffer)[i+0] = _3BytesSeqs[id][0];
352 ((BYTE*)CNBuffer)[i+1] = _3BytesSeqs[id][1];
353 ((BYTE*)CNBuffer)[i+2] = _3BytesSeqs[id][2];
354 i += 3;
Yann Collet0d9ce042016-03-19 13:21:08 +0100355 } }}
356 DISPLAYLEVEL(4, "test%3i : compress lots 3-bytes sequences : ", testNb++);
357 result = ZSTD_compress(compressedBuffer, ZSTD_compressBound(_3BYTESTESTLENGTH), CNBuffer, _3BYTESTESTLENGTH, 19);
358 if (ZSTD_isError(result)) goto _output_error;
359 cSize = result;
360 DISPLAYLEVEL(4, "OK (%u bytes : %.2f%%)\n", (U32)cSize, (double)cSize/_3BYTESTESTLENGTH*100);
Yann Collet4ba85342016-03-07 20:01:45 +0100361
Yann Collet0d9ce042016-03-19 13:21:08 +0100362 DISPLAYLEVEL(4, "test%3i : decompress lots 3-bytes sequence : ", testNb++);
363 result = ZSTD_decompress(decodedBuffer, _3BYTESTESTLENGTH, compressedBuffer, cSize);
364 if (ZSTD_isError(result)) goto _output_error;
365 if (result != _3BYTESTESTLENGTH) goto _output_error;
366 DISPLAYLEVEL(4, "OK \n");
Yann Collet4ba85342016-03-07 20:01:45 +0100367
Yann Collet4856a002015-01-24 01:58:16 +0100368_end:
369 free(CNBuffer);
370 free(compressedBuffer);
371 free(decodedBuffer);
372 return testResult;
373
374_output_error:
375 testResult = 1;
376 DISPLAY("Error detected in Unit tests ! \n");
377 goto _end;
378}
379
380
381static size_t findDiff(const void* buf1, const void* buf2, size_t max)
382{
Yann Collet213089c2015-06-18 07:43:16 -0800383 const BYTE* b1 = (const BYTE*)buf1;
384 const BYTE* b2 = (const BYTE*)buf2;
Yann Collet4856a002015-01-24 01:58:16 +0100385 size_t i;
Yann Colletd1d210f2016-03-19 12:12:07 +0100386 for (i=0; i<max; i++) {
Yann Collet4856a002015-01-24 01:58:16 +0100387 if (b1[i] != b2[i]) break;
388 }
389 return i;
390}
391
Yann Collet1fce6e02016-04-08 20:26:33 +0200392
393static size_t FUZ_rLogLength(U32* seed, U32 logLength)
394{
395 size_t const lengthMask = ((size_t)1 << logLength) - 1;
396 return (lengthMask+1) + (FUZ_rand(seed) & lengthMask);
397}
398
399static size_t FUZ_randomLength(U32* seed, U32 maxLog)
400{
401 U32 const logLength = FUZ_rand(seed) % maxLog;
402 return FUZ_rLogLength(seed, logLength);
403}
404
Yann Collet0d9ce042016-03-19 13:21:08 +0100405#define CHECK(cond, ...) if (cond) { DISPLAY("Error => "); DISPLAY(__VA_ARGS__); \
406 DISPLAY(" (seed %u, test nb %u) \n", seed, testNb); goto _output_error; }
Yann Collet4856a002015-01-24 01:58:16 +0100407
Yann Colletea63bb72016-04-08 15:25:32 +0200408static int fuzzerTests(U32 seed, U32 nbTests, unsigned startTest, U32 const maxDurationS, double compressibility)
Yann Collet4856a002015-01-24 01:58:16 +0100409{
Yann Collet1fce6e02016-04-08 20:26:33 +0200410 static const U32 maxSrcLog = 23;
411 static const U32 maxSampleLog = 22;
Yann Colletd5d9bc32015-08-23 23:13:49 +0100412 BYTE* cNoiseBuffer[5];
Yann Collet4856a002015-01-24 01:58:16 +0100413 BYTE* srcBuffer;
414 BYTE* cBuffer;
415 BYTE* dstBuffer;
Yann Collete47c4e52015-12-05 09:23:53 +0100416 BYTE* mirrorBuffer;
Yann Collet4856a002015-01-24 01:58:16 +0100417 size_t srcBufferSize = (size_t)1<<maxSrcLog;
418 size_t dstBufferSize = (size_t)1<<maxSampleLog;
419 size_t cBufferSize = ZSTD_compressBound(dstBufferSize);
420 U32 result = 0;
421 U32 testNb = 0;
422 U32 coreSeed = seed, lseed = 0;
Yann Colletecd651b2016-01-07 15:35:18 +0100423 ZSTD_CCtx* refCtx;
Yann Collet2f648e52015-10-29 18:23:38 +0100424 ZSTD_CCtx* ctx;
Yann Collete47c4e52015-12-05 09:23:53 +0100425 ZSTD_DCtx* dctx;
Yann Colletea63bb72016-04-08 15:25:32 +0200426 clock_t startClock = clock();
427 clock_t const maxClockSpan = maxDurationS * CLOCKS_PER_SEC;
Yann Collet4856a002015-01-24 01:58:16 +0100428
429 /* allocation */
Yann Colletecd651b2016-01-07 15:35:18 +0100430 refCtx = ZSTD_createCCtx();
Yann Collet2f648e52015-10-29 18:23:38 +0100431 ctx = ZSTD_createCCtx();
Yann Collete47c4e52015-12-05 09:23:53 +0100432 dctx= ZSTD_createDCtx();
Yann Colletd5d9bc32015-08-23 23:13:49 +0100433 cNoiseBuffer[0] = (BYTE*)malloc (srcBufferSize);
434 cNoiseBuffer[1] = (BYTE*)malloc (srcBufferSize);
435 cNoiseBuffer[2] = (BYTE*)malloc (srcBufferSize);
436 cNoiseBuffer[3] = (BYTE*)malloc (srcBufferSize);
437 cNoiseBuffer[4] = (BYTE*)malloc (srcBufferSize);
Yann Collet213089c2015-06-18 07:43:16 -0800438 dstBuffer = (BYTE*)malloc (dstBufferSize);
Yann Collete47c4e52015-12-05 09:23:53 +0100439 mirrorBuffer = (BYTE*)malloc (dstBufferSize);
Yann Collet213089c2015-06-18 07:43:16 -0800440 cBuffer = (BYTE*)malloc (cBufferSize);
Yann Collete47c4e52015-12-05 09:23:53 +0100441 CHECK (!cNoiseBuffer[0] || !cNoiseBuffer[1] || !cNoiseBuffer[2] || !cNoiseBuffer[3] || !cNoiseBuffer[4]
Yann Colletecd651b2016-01-07 15:35:18 +0100442 || !dstBuffer || !mirrorBuffer || !cBuffer || !refCtx || !ctx || !dctx,
Yann Colletd5d9bc32015-08-23 23:13:49 +0100443 "Not enough memory, fuzzer tests cancelled");
Yann Collet4856a002015-01-24 01:58:16 +0100444
Yann Colletd5d9bc32015-08-23 23:13:49 +0100445 /* Create initial samples */
446 RDG_genBuffer(cNoiseBuffer[0], srcBufferSize, 0.00, 0., coreSeed); /* pure noise */
447 RDG_genBuffer(cNoiseBuffer[1], srcBufferSize, 0.05, 0., coreSeed); /* barely compressible */
448 RDG_genBuffer(cNoiseBuffer[2], srcBufferSize, compressibility, 0., coreSeed);
449 RDG_genBuffer(cNoiseBuffer[3], srcBufferSize, 0.95, 0., coreSeed); /* highly compressible */
450 RDG_genBuffer(cNoiseBuffer[4], srcBufferSize, 1.00, 0., coreSeed); /* sparse content */
451 srcBuffer = cNoiseBuffer[2];
Yann Collet4856a002015-01-24 01:58:16 +0100452
453 /* catch up testNb */
Yann Collet546c9b12016-03-19 12:47:52 +0100454 for (testNb=1; testNb < startTest; testNb++) FUZ_rand(&coreSeed);
Yann Collet4856a002015-01-24 01:58:16 +0100455
Yann Collet546c9b12016-03-19 12:47:52 +0100456 /* main test loop */
Yann Colletea63bb72016-04-08 15:25:32 +0200457 for ( ; (testNb <= nbTests) || (FUZ_clockSpan(startClock) < maxClockSpan); testNb++ ) {
Yann Collet417890c2015-12-04 17:16:37 +0100458 size_t sampleSize, sampleStart, maxTestSize, totalTestSize;
Yann Collet1fce6e02016-04-08 20:26:33 +0200459 size_t cSize, dSize, totalCSize, totalGenSize;
460 U32 sampleSizeLog, nbChunks, n;
Yann Collet6c903a82016-05-28 13:34:07 +0200461 XXH64_state_t xxhState;
Yann Collet1fce6e02016-04-08 20:26:33 +0200462 U64 crcOrig;
Yann Collet110cc142015-11-19 12:02:28 +0100463 BYTE* sampleBuffer;
Yann Collet4bfe4152015-12-06 13:18:37 +0100464 const BYTE* dict;
465 size_t dictSize;
Yann Collet4856a002015-01-24 01:58:16 +0100466
Yann Collet546c9b12016-03-19 12:47:52 +0100467 /* notification */
468 if (nbTests >= testNb) { DISPLAYUPDATE(2, "\r%6u/%6u ", testNb, nbTests); }
Yann Collet1c2ddba2015-12-04 17:45:35 +0100469 else { DISPLAYUPDATE(2, "\r%6u ", testNb); }
470
Yann Collet4856a002015-01-24 01:58:16 +0100471 FUZ_rand(&coreSeed);
Yann Collet0d9ce042016-03-19 13:21:08 +0100472 { U32 const prime1 = 2654435761U; lseed = coreSeed ^ prime1; }
Yann Collet1fce6e02016-04-08 20:26:33 +0200473
474 /* srcBuffer selection [0-4] */
475 { U32 buffNb = FUZ_rand(&lseed) & 0x7F;
476 if (buffNb & 7) buffNb=2; /* most common : compressible (P) */
477 else {
478 buffNb >>= 3;
479 if (buffNb & 7) {
480 const U32 tnb[2] = { 1, 3 }; /* barely/highly compressible */
481 buffNb = tnb[buffNb >> 3];
482 } else {
483 const U32 tnb[2] = { 0, 4 }; /* not compressible / sparse */
484 buffNb = tnb[buffNb >> 3];
485 } }
486 srcBuffer = cNoiseBuffer[buffNb];
487 }
488
489 /* select src segment */
Yann Collet4856a002015-01-24 01:58:16 +0100490 sampleSizeLog = FUZ_rand(&lseed) % maxSampleLog;
Yann Collet1fce6e02016-04-08 20:26:33 +0200491 sampleSize = FUZ_rLogLength(&lseed, sampleSizeLog);
Yann Collet4856a002015-01-24 01:58:16 +0100492 sampleStart = FUZ_rand(&lseed) % (srcBufferSize - sampleSize);
Yann Collet4856a002015-01-24 01:58:16 +0100493
Yann Collet110cc142015-11-19 12:02:28 +0100494 /* create sample buffer (to catch read error with valgrind & sanitizers) */
495 sampleBuffer = (BYTE*)malloc(sampleSize);
496 CHECK (sampleBuffer==NULL, "not enough memory for sample buffer");
497 memcpy(sampleBuffer, srcBuffer + sampleStart, sampleSize);
498 crcOrig = XXH64(sampleBuffer, sampleSize, 0);
499
Yann Collet1fce6e02016-04-08 20:26:33 +0200500 /* compression tests */
501 { int const cLevel = (FUZ_rand(&lseed) % (ZSTD_maxCLevel() - (sampleSizeLog/3))) + 1;
502 cSize = ZSTD_compressCCtx(ctx, cBuffer, cBufferSize, sampleBuffer, sampleSize, cLevel);
503 CHECK(ZSTD_isError(cSize), "ZSTD_compressCCtx failed");
Yann Collet4856a002015-01-24 01:58:16 +0100504
Yann Collet1fce6e02016-04-08 20:26:33 +0200505 /* compression failure test : too small dest buffer */
506 if (cSize > 3) {
507 const size_t missing = (FUZ_rand(&lseed) % (cSize-2)) + 1; /* no problem, as cSize > 4 (frameHeaderSizer) */
508 const size_t tooSmallSize = cSize - missing;
509 const U32 endMark = 0x4DC2B1A9;
510 memcpy(dstBuffer+tooSmallSize, &endMark, 4);
511 { size_t const errorCode = ZSTD_compressCCtx(ctx, dstBuffer, tooSmallSize, sampleBuffer, sampleSize, cLevel);
512 CHECK(!ZSTD_isError(errorCode), "ZSTD_compressCCtx should have failed ! (buffer too small : %u < %u)", (U32)tooSmallSize, (U32)cSize); }
513 { U32 endCheck; memcpy(&endCheck, dstBuffer+tooSmallSize, 4);
514 CHECK(endCheck != endMark, "ZSTD_compressCCtx : dst buffer overflow"); }
515 }
Yann Collete9853b22015-08-07 19:07:32 +0100516 }
517
Yann Collet1fce6e02016-04-08 20:26:33 +0200518
Yann Collet546c9b12016-03-19 12:47:52 +0100519 /* frame header decompression test */
Yann Collet346bffb2016-03-15 15:24:52 +0100520 { ZSTD_frameParams dParams;
521 size_t const check = ZSTD_getFrameParams(&dParams, cBuffer, cSize);
522 CHECK(ZSTD_isError(check), "Frame Parameters extraction failed");
523 CHECK(dParams.frameContentSize != sampleSize, "Frame content size incorrect");
524 }
525
Yann Collet546c9b12016-03-19 12:47:52 +0100526 /* successful decompression test */
Yann Collet1fce6e02016-04-08 20:26:33 +0200527 { size_t const margin = (FUZ_rand(&lseed) & 1) ? 0 : (FUZ_rand(&lseed) & 31) + 1;
Yann Collet546c9b12016-03-19 12:47:52 +0100528 dSize = ZSTD_decompress(dstBuffer, sampleSize + margin, cBuffer, cSize);
529 CHECK(dSize != sampleSize, "ZSTD_decompress failed (%s) (srcSize : %u ; cSize : %u)", ZSTD_getErrorName(dSize), (U32)sampleSize, (U32)cSize);
Yann Collet1fce6e02016-04-08 20:26:33 +0200530 { U64 const crcDest = XXH64(dstBuffer, sampleSize, 0);
531 CHECK(crcOrig != crcDest, "decompression result corrupted (pos %u / %u)", (U32)findDiff(sampleBuffer, dstBuffer, sampleSize), (U32)sampleSize);
532 } }
Yann Collet110cc142015-11-19 12:02:28 +0100533
534 free(sampleBuffer); /* no longer useful after this point */
Yann Colletf3cb79b2015-08-20 00:02:43 +0100535
536 /* truncated src decompression test */
Yann Collet1fce6e02016-04-08 20:26:33 +0200537 { size_t const missing = (FUZ_rand(&lseed) % (cSize-2)) + 1; /* no problem, as cSize > 4 (frameHeaderSizer) */
538 size_t const tooSmallSize = cSize - missing;
Yann Colletf3cb79b2015-08-20 00:02:43 +0100539 void* cBufferTooSmall = malloc(tooSmallSize); /* valgrind will catch overflows */
Yann Colletf3cb79b2015-08-20 00:02:43 +0100540 CHECK(cBufferTooSmall == NULL, "not enough memory !");
Yann Colletd5d9bc32015-08-23 23:13:49 +0100541 memcpy(cBufferTooSmall, cBuffer, tooSmallSize);
Yann Collet1fce6e02016-04-08 20:26:33 +0200542 { size_t const errorCode = ZSTD_decompress(dstBuffer, dstBufferSize, cBufferTooSmall, tooSmallSize);
543 CHECK(!ZSTD_isError(errorCode), "ZSTD_decompress should have failed ! (truncated src buffer)"); }
Yann Colletf3cb79b2015-08-20 00:02:43 +0100544 free(cBufferTooSmall);
545 }
546
547 /* too small dst decompression test */
Yann Colletd1d210f2016-03-19 12:12:07 +0100548 if (sampleSize > 3) {
Yann Colletea63bb72016-04-08 15:25:32 +0200549 size_t const missing = (FUZ_rand(&lseed) % (sampleSize-2)) + 1; /* no problem, as cSize > 4 (frameHeaderSizer) */
550 size_t const tooSmallSize = sampleSize - missing;
Yann Colletf3cb79b2015-08-20 00:02:43 +0100551 static const BYTE token = 0xA9;
552 dstBuffer[tooSmallSize] = token;
Yann Collet1fce6e02016-04-08 20:26:33 +0200553 { size_t const errorCode = ZSTD_decompress(dstBuffer, tooSmallSize, cBuffer, cSize);
554 CHECK(!ZSTD_isError(errorCode), "ZSTD_decompress should have failed : %u > %u (dst buffer too small)", (U32)errorCode, (U32)tooSmallSize); }
Yann Colletf3cb79b2015-08-20 00:02:43 +0100555 CHECK(dstBuffer[tooSmallSize] != token, "ZSTD_decompress : dst buffer overflow");
556 }
Yann Collet997f9ee2015-08-21 02:44:20 +0100557
558 /* noisy src decompression test */
Yann Colletd1d210f2016-03-19 12:12:07 +0100559 if (cSize > 6) {
560 /* insert noise into src */
561 { U32 const maxNbBits = FUZ_highbit32((U32)(cSize-4));
562 size_t pos = 4; /* preserve magic number (too easy to detect) */
563 for (;;) {
564 /* keep some original src */
565 { U32 const nbBits = FUZ_rand(&lseed) % maxNbBits;
566 size_t const mask = (1<<nbBits) - 1;
567 size_t const skipLength = FUZ_rand(&lseed) & mask;
568 pos += skipLength;
569 }
570 if (pos <= cSize) break;
571 /* add noise */
Yann Collet33341de2016-05-29 23:09:51 +0200572 { U32 const nbBitsCodes = FUZ_rand(&lseed) % maxNbBits;
573 U32 const nbBits = nbBitsCodes ? nbBitsCodes-1 : 0;
574 size_t const mask = (1<<nbBits) - 1;
575 size_t const rNoiseLength = (FUZ_rand(&lseed) & mask) + 1;
576 size_t const noiseLength = MIN(rNoiseLength, cSize-pos);
577 size_t const noiseStart = FUZ_rand(&lseed) % (srcBufferSize - noiseLength);
Yann Colletd1d210f2016-03-19 12:12:07 +0100578 memcpy(cBuffer + pos, srcBuffer + noiseStart, noiseLength);
579 pos += noiseLength;
580 } } }
Yann Collet997f9ee2015-08-21 02:44:20 +0100581
582 /* decompress noisy source */
Yann Colletd1d210f2016-03-19 12:12:07 +0100583 { U32 const endMark = 0xA9B1C3D6;
Yann Collet997f9ee2015-08-21 02:44:20 +0100584 memcpy(dstBuffer+sampleSize, &endMark, 4);
Yann Collet1fce6e02016-04-08 20:26:33 +0200585 { size_t const decompressResult = ZSTD_decompress(dstBuffer, sampleSize, cBuffer, cSize);
586 /* result *may* be an unlikely success, but even then, it must strictly respect dst buffer boundaries */
587 CHECK((!ZSTD_isError(decompressResult)) && (decompressResult>sampleSize),
588 "ZSTD_decompress on noisy src : result is too large : %u > %u (dst buffer)", (U32)decompressResult, (U32)sampleSize);
589 }
590 { U32 endCheck; memcpy(&endCheck, dstBuffer+sampleSize, 4);
591 CHECK(endMark!=endCheck, "ZSTD_decompress on noisy src : dst buffer overflow");
592 } } } /* noisy src decompression test */
Yann Collet417890c2015-12-04 17:16:37 +0100593
Yann Collet1fce6e02016-04-08 20:26:33 +0200594 /*===== Streaming compression test, scattered segments and dictionary =====*/
595
596 { U32 const testLog = FUZ_rand(&lseed) % maxSrcLog;
597 int const cLevel = (FUZ_rand(&lseed) % (ZSTD_maxCLevel() - (testLog/3))) + 1;
598 maxTestSize = FUZ_rLogLength(&lseed, testLog);
599 if (maxTestSize >= dstBufferSize) maxTestSize = dstBufferSize-1;
600
601 sampleSize = FUZ_randomLength(&lseed, maxSampleLog);
602 sampleStart = FUZ_rand(&lseed) % (srcBufferSize - sampleSize);
603 dict = srcBuffer + sampleStart;
604 dictSize = sampleSize;
605
Yann Collet33341de2016-05-29 23:09:51 +0200606 if (FUZ_rand(&lseed) & 15) {
607 size_t const errorCode = ZSTD_compressBegin_usingDict(refCtx, dict, dictSize, cLevel);
608 CHECK (ZSTD_isError(errorCode), "ZSTD_compressBegin_usingDict error : %s", ZSTD_getErrorName(errorCode));
609 } else {
610 ZSTD_parameters p = (ZSTD_parameters) { ZSTD_getCParams(cLevel, 0, dictSize), { 0, 0 } };
611 size_t const errorCode = ZSTD_compressBegin_advanced(refCtx, dict, dictSize, p, 0);
612 CHECK (ZSTD_isError(errorCode), "ZSTD_compressBegin_advanced error : %s", ZSTD_getErrorName(errorCode));
613 }
Yann Collet1fce6e02016-04-08 20:26:33 +0200614 { size_t const errorCode = ZSTD_copyCCtx(ctx, refCtx);
615 CHECK (ZSTD_isError(errorCode), "ZSTD_copyCCtx error : %s", ZSTD_getErrorName(errorCode)); }
616 }
Yann Collet6c903a82016-05-28 13:34:07 +0200617 XXH64_reset(&xxhState, 0);
Yann Collet417890c2015-12-04 17:16:37 +0100618 nbChunks = (FUZ_rand(&lseed) & 127) + 2;
Yann Collet1fce6e02016-04-08 20:26:33 +0200619 for (totalTestSize=0, cSize=0, n=0 ; n<nbChunks ; n++) {
Yann Collet417890c2015-12-04 17:16:37 +0100620 sampleSizeLog = FUZ_rand(&lseed) % maxSampleLog;
621 sampleSize = (size_t)1 << sampleSizeLog;
622 sampleSize += FUZ_rand(&lseed) & (sampleSize-1);
623 sampleStart = FUZ_rand(&lseed) % (srcBufferSize - sampleSize);
624
Yann Collet1fce6e02016-04-08 20:26:33 +0200625 if (cBufferSize-cSize < ZSTD_compressBound(sampleSize)) break; /* avoid invalid dstBufferTooSmall */
Yann Collete47c4e52015-12-05 09:23:53 +0100626 if (totalTestSize+sampleSize > maxTestSize) break;
Yann Collet417890c2015-12-04 17:16:37 +0100627
Yann Collet1fce6e02016-04-08 20:26:33 +0200628 { size_t const compressResult = ZSTD_compressContinue(ctx, cBuffer+cSize, cBufferSize-cSize, srcBuffer+sampleStart, sampleSize);
629 CHECK (ZSTD_isError(compressResult), "multi-segments compression error : %s", ZSTD_getErrorName(compressResult));
630 cSize += compressResult;
631 }
Yann Collet6c903a82016-05-28 13:34:07 +0200632 XXH64_update(&xxhState, srcBuffer+sampleStart, sampleSize);
Yann Collete47c4e52015-12-05 09:23:53 +0100633 memcpy(mirrorBuffer + totalTestSize, srcBuffer+sampleStart, sampleSize);
Yann Collet417890c2015-12-04 17:16:37 +0100634 totalTestSize += sampleSize;
Yann Collet417890c2015-12-04 17:16:37 +0100635 }
Yann Collet1fce6e02016-04-08 20:26:33 +0200636 { size_t const flushResult = ZSTD_compressEnd(ctx, cBuffer+cSize, cBufferSize-cSize);
637 CHECK (ZSTD_isError(flushResult), "multi-segments epilogue error : %s", ZSTD_getErrorName(flushResult));
638 cSize += flushResult;
639 }
Yann Collet6c903a82016-05-28 13:34:07 +0200640 crcOrig = XXH64_digest(&xxhState);
Yann Collete47c4e52015-12-05 09:23:53 +0100641
642 /* streaming decompression test */
Yann Collet33341de2016-05-29 23:09:51 +0200643 if (dictSize<8) dictSize=0, dict=NULL; /* disable dictionary */
Yann Collet1fce6e02016-04-08 20:26:33 +0200644 { size_t const errorCode = ZSTD_decompressBegin_usingDict(dctx, dict, dictSize);
645 CHECK (ZSTD_isError(errorCode), "cannot init DCtx : %s", ZSTD_getErrorName(errorCode)); }
Yann Collete47c4e52015-12-05 09:23:53 +0100646 totalCSize = 0;
647 totalGenSize = 0;
Yann Colletd1d210f2016-03-19 12:12:07 +0100648 while (totalCSize < cSize) {
Yann Collet1fce6e02016-04-08 20:26:33 +0200649 size_t const inSize = ZSTD_nextSrcSizeToDecompress(dctx);
650 size_t const genSize = ZSTD_decompressContinue(dctx, dstBuffer+totalGenSize, dstBufferSize-totalGenSize, cBuffer+totalCSize, inSize);
Yann Collete47c4e52015-12-05 09:23:53 +0100651 CHECK (ZSTD_isError(genSize), "streaming decompression error : %s", ZSTD_getErrorName(genSize));
652 totalGenSize += genSize;
653 totalCSize += inSize;
654 }
655 CHECK (ZSTD_nextSrcSizeToDecompress(dctx) != 0, "frame not fully decoded");
656 CHECK (totalGenSize != totalTestSize, "decompressed data : wrong size")
657 CHECK (totalCSize != cSize, "compressed data should be fully read")
Yann Collet1fce6e02016-04-08 20:26:33 +0200658 { U64 const crcDest = XXH64(dstBuffer, totalTestSize, 0);
659 if (crcDest!=crcOrig) {
660 size_t const errorPos = findDiff(mirrorBuffer, dstBuffer, totalTestSize);
661 CHECK (crcDest!=crcOrig, "streaming decompressed data corrupted : byte %u / %u (%02X!=%02X)",
662 (U32)errorPos, (U32)totalTestSize, dstBuffer[errorPos], mirrorBuffer[errorPos]);
663 } }
664 } /* for ( ; (testNb <= nbTests) */
Yann Collet1c2ddba2015-12-04 17:45:35 +0100665 DISPLAY("\r%u fuzzer tests completed \n", testNb-1);
Yann Collet4856a002015-01-24 01:58:16 +0100666
667_cleanup:
Yann Colletecd651b2016-01-07 15:35:18 +0100668 ZSTD_freeCCtx(refCtx);
Yann Collet2f648e52015-10-29 18:23:38 +0100669 ZSTD_freeCCtx(ctx);
Yann Collete47c4e52015-12-05 09:23:53 +0100670 ZSTD_freeDCtx(dctx);
Yann Colletd5d9bc32015-08-23 23:13:49 +0100671 free(cNoiseBuffer[0]);
672 free(cNoiseBuffer[1]);
673 free(cNoiseBuffer[2]);
674 free(cNoiseBuffer[3]);
675 free(cNoiseBuffer[4]);
Yann Collet4856a002015-01-24 01:58:16 +0100676 free(cBuffer);
677 free(dstBuffer);
Yann Collete47c4e52015-12-05 09:23:53 +0100678 free(mirrorBuffer);
Yann Collet4856a002015-01-24 01:58:16 +0100679 return result;
680
681_output_error:
682 result = 1;
683 goto _cleanup;
684}
685
686
Yann Colletd1d210f2016-03-19 12:12:07 +0100687/*_*******************************************************
Yann Collet4856a002015-01-24 01:58:16 +0100688* Command line
689*********************************************************/
Yann Colletd1d210f2016-03-19 12:12:07 +0100690int FUZ_usage(const char* programName)
Yann Collet4856a002015-01-24 01:58:16 +0100691{
692 DISPLAY( "Usage :\n");
693 DISPLAY( " %s [args]\n", programName);
694 DISPLAY( "\n");
695 DISPLAY( "Arguments :\n");
696 DISPLAY( " -i# : Nb of tests (default:%u) \n", nbTestsDefault);
697 DISPLAY( " -s# : Select seed (default:prompt user)\n");
698 DISPLAY( " -t# : Select starting test number (default:0)\n");
Yann Collet0d9ce042016-03-19 13:21:08 +0100699 DISPLAY( " -P# : Select compressibility in %% (default:%u%%)\n", FUZ_compressibility_default);
Yann Collet4856a002015-01-24 01:58:16 +0100700 DISPLAY( " -v : verbose\n");
Yann Collete9853b22015-08-07 19:07:32 +0100701 DISPLAY( " -p : pause at the end\n");
Yann Collet4856a002015-01-24 01:58:16 +0100702 DISPLAY( " -h : display help and exit\n");
703 return 0;
704}
705
706
Yann Colletd1d210f2016-03-19 12:12:07 +0100707int main(int argc, const char** argv)
Yann Collet4856a002015-01-24 01:58:16 +0100708{
709 U32 seed=0;
710 int seedset=0;
711 int argNb;
712 int nbTests = nbTestsDefault;
713 int testNb = 0;
Yann Collet0d9ce042016-03-19 13:21:08 +0100714 U32 proba = FUZ_compressibility_default;
Yann Collet4856a002015-01-24 01:58:16 +0100715 int result=0;
716 U32 mainPause = 0;
Yann Collet0d9ce042016-03-19 13:21:08 +0100717 U32 maxDuration = 0;
Yann Colletea63bb72016-04-08 15:25:32 +0200718 const char* programName = argv[0];
Yann Collet4856a002015-01-24 01:58:16 +0100719
720 /* Check command line */
Yann Colletd1d210f2016-03-19 12:12:07 +0100721 for (argNb=1; argNb<argc; argNb++) {
722 const char* argument = argv[argNb];
Yann Collet4856a002015-01-24 01:58:16 +0100723 if(!argument) continue; /* Protection if argument empty */
724
725 /* Handle commands. Aggregated commands are allowed */
Yann Colletd1d210f2016-03-19 12:12:07 +0100726 if (argument[0]=='-') {
Yann Collet4856a002015-01-24 01:58:16 +0100727 argument++;
Yann Colletd1d210f2016-03-19 12:12:07 +0100728 while (*argument!=0) {
Yann Collet4856a002015-01-24 01:58:16 +0100729 switch(*argument)
730 {
731 case 'h':
732 return FUZ_usage(programName);
733 case 'v':
734 argument++;
735 g_displayLevel=4;
736 break;
737 case 'q':
738 argument++;
739 g_displayLevel--;
740 break;
741 case 'p': /* pause at the end */
742 argument++;
743 mainPause = 1;
744 break;
745
746 case 'i':
Yann Collet0d9ce042016-03-19 13:21:08 +0100747 argument++; maxDuration=0;
Yann Collet4856a002015-01-24 01:58:16 +0100748 nbTests=0;
Yann Colletd1d210f2016-03-19 12:12:07 +0100749 while ((*argument>='0') && (*argument<='9')) {
Yann Collet4856a002015-01-24 01:58:16 +0100750 nbTests *= 10;
751 nbTests += *argument - '0';
752 argument++;
753 }
754 break;
755
Yann Collet553cf6a2015-12-04 17:25:26 +0100756 case 'T':
757 argument++;
Yann Collet0d9ce042016-03-19 13:21:08 +0100758 nbTests=0; maxDuration=0;
Yann Colletd1d210f2016-03-19 12:12:07 +0100759 while ((*argument>='0') && (*argument<='9')) {
Yann Collet0d9ce042016-03-19 13:21:08 +0100760 maxDuration *= 10;
761 maxDuration += *argument - '0';
Yann Collet553cf6a2015-12-04 17:25:26 +0100762 argument++;
763 }
Yann Collet0d9ce042016-03-19 13:21:08 +0100764 if (*argument=='m') maxDuration *=60, argument++;
Yann Collet553cf6a2015-12-04 17:25:26 +0100765 if (*argument=='n') argument++;
Yann Collet553cf6a2015-12-04 17:25:26 +0100766 break;
767
Yann Collet4856a002015-01-24 01:58:16 +0100768 case 's':
769 argument++;
770 seed=0;
771 seedset=1;
Yann Colletd1d210f2016-03-19 12:12:07 +0100772 while ((*argument>='0') && (*argument<='9')) {
Yann Collet4856a002015-01-24 01:58:16 +0100773 seed *= 10;
774 seed += *argument - '0';
775 argument++;
776 }
777 break;
778
779 case 't':
780 argument++;
781 testNb=0;
Yann Colletd1d210f2016-03-19 12:12:07 +0100782 while ((*argument>='0') && (*argument<='9')) {
Yann Collet4856a002015-01-24 01:58:16 +0100783 testNb *= 10;
784 testNb += *argument - '0';
785 argument++;
786 }
787 break;
788
789 case 'P': /* compressibility % */
790 argument++;
791 proba=0;
Yann Colletd1d210f2016-03-19 12:12:07 +0100792 while ((*argument>='0') && (*argument<='9')) {
Yann Collet4856a002015-01-24 01:58:16 +0100793 proba *= 10;
794 proba += *argument - '0';
795 argument++;
796 }
Yann Collet4856a002015-01-24 01:58:16 +0100797 if (proba>100) proba=100;
798 break;
799
800 default:
801 return FUZ_usage(programName);
Yann Colletd1d210f2016-03-19 12:12:07 +0100802 } } } } /* for (argNb=1; argNb<argc; argNb++) */
Yann Collet4856a002015-01-24 01:58:16 +0100803
804 /* Get Seed */
Yann Collet45f84ab2016-05-20 12:34:40 +0200805 DISPLAY("Starting zstd tester (%i-bits, %s)\n", (int)(sizeof(size_t)*8), ZSTD_VERSION_STRING);
Yann Collet4856a002015-01-24 01:58:16 +0100806
Yann Colletea63bb72016-04-08 15:25:32 +0200807 if (!seedset) seed = (U32)(clock() % 10000);
Yann Collet4856a002015-01-24 01:58:16 +0100808 DISPLAY("Seed = %u\n", seed);
Yann Collet0d9ce042016-03-19 13:21:08 +0100809 if (proba!=FUZ_compressibility_default) DISPLAY("Compressibility : %u%%\n", proba);
Yann Collet4856a002015-01-24 01:58:16 +0100810
Yann Colletd1d210f2016-03-19 12:12:07 +0100811 if (testNb==0)
812 result = basicUnitTests(0, ((double)proba) / 100); /* constant seed for predictability */
Yann Collet4856a002015-01-24 01:58:16 +0100813 if (!result)
Yann Collet0d9ce042016-03-19 13:21:08 +0100814 result = fuzzerTests(seed, nbTests, testNb, maxDuration, ((double)proba) / 100);
Yann Colletd1d210f2016-03-19 12:12:07 +0100815 if (mainPause) {
Yann Colletb5e06dc2015-07-04 23:20:56 -0800816 int unused;
Yann Collet4856a002015-01-24 01:58:16 +0100817 DISPLAY("Press Enter \n");
Yann Colletb5e06dc2015-07-04 23:20:56 -0800818 unused = getchar();
819 (void)unused;
Yann Collet4856a002015-01-24 01:58:16 +0100820 }
821 return result;
822}