blob: 480fd30724eacd65d03404d3bd0fee39f4ca69c0 [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 */
cyanb8806312016-05-30 18:20:46 +020031# pragma warning(disable : 4204) /* disable: C4204: non-constant aggregate initializer */
Yann Collet4856a002015-01-24 01:58:16 +010032#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 Colletd3b7f8d2016-06-04 19:47:02 +020043#define ZSTD_STATIC_LINKING_ONLY /* ZSTD_compressContinue */
44#include "zstd.h" /* ZSTD_VERSION_STRING, ZSTD_getErrorCode */
Yann Collet30009522016-05-30 16:17:33 +020045#include "zdict.h" /* ZDICT_trainFromBuffer */
Yann Colletd5d9bc32015-08-23 23:13:49 +010046#include "datagen.h" /* RDG_genBuffer */
Yann Collet353c5d22015-10-21 14:39:26 +010047#include "mem.h"
Yann Collet6c903a82016-05-28 13:34:07 +020048#define XXH_STATIC_LINKING_ONLY
49#include "xxhash.h" /* XXH64 */
Yann Collet4856a002015-01-24 01:58:16 +010050
51
Yann Collet0d9ce042016-03-19 13:21:08 +010052/*-************************************
53* Constants
Yann Collet4856a002015-01-24 01:58:16 +010054**************************************/
Yann Collet4856a002015-01-24 01:58:16 +010055#define KB *(1U<<10)
56#define MB *(1U<<20)
57#define GB *(1U<<30)
58
Yann Collet0d9ce042016-03-19 13:21:08 +010059static const U32 FUZ_compressibility_default = 50;
Yann Collet110cc142015-11-19 12:02:28 +010060static const U32 nbTestsDefault = 30000;
Yann Collet4856a002015-01-24 01:58:16 +010061
62
Yann Collet0d9ce042016-03-19 13:21:08 +010063/*-************************************
Yann Collet4856a002015-01-24 01:58:16 +010064* Display Macros
65**************************************/
66#define DISPLAY(...) fprintf(stderr, __VA_ARGS__)
67#define DISPLAYLEVEL(l, ...) if (g_displayLevel>=l) { DISPLAY(__VA_ARGS__); }
68static U32 g_displayLevel = 2;
69
70#define DISPLAYUPDATE(l, ...) if (g_displayLevel>=l) { \
Yann Colletea63bb72016-04-08 15:25:32 +020071 if ((FUZ_clockSpan(g_displayClock) > g_refreshRate) || (g_displayLevel>=4)) \
72 { g_displayClock = clock(); DISPLAY(__VA_ARGS__); \
Yann Collet4856a002015-01-24 01:58:16 +010073 if (g_displayLevel>=4) fflush(stdout); } }
Yann Colletea63bb72016-04-08 15:25:32 +020074static const clock_t g_refreshRate = CLOCKS_PER_SEC * 150 / 1000;
75static clock_t g_displayClock = 0;
Yann Collet553cf6a2015-12-04 17:25:26 +010076
Yann Collet4856a002015-01-24 01:58:16 +010077
Yann Collet0d9ce042016-03-19 13:21:08 +010078/*-*******************************************************
Yann Collet4856a002015-01-24 01:58:16 +010079* Fuzzer functions
80*********************************************************/
Yann Collete93add02016-02-15 17:44:14 +010081#define MIN(a,b) ((a)<(b)?(a):(b))
Yann Collet110cc142015-11-19 12:02:28 +010082
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
Yann Colletc0a9bf32016-05-30 01:56:08 +020089#define FUZ_rotl32(x,r) ((x << r) | (x >> (32 - r)))
90static unsigned 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 Colletc0a9bf32016-05-30 01:56:08 +0200107 while (v32) v32 >>= 1, nbBits++;
Yann Collet4856a002015-01-24 01:58:16 +0100108 return nbBits;
109}
Yann Collet4856a002015-01-24 01:58:16 +0100110
111
Yann Colletc0a9bf32016-05-30 01:56:08 +0200112#define CHECKTEST(var, fn) size_t const var = fn; if (ZSTD_isError(var)) goto _output_error
113#define CHECK(fn) { CHECKTEST(err, fn); }
114#define CHECKPLUS(var, fn, more) { CHECKTEST(var, fn); more; }
Yann Collet4856a002015-01-24 01:58:16 +0100115static int basicUnitTests(U32 seed, double compressibility)
116{
Yann Collet30009522016-05-30 16:17:33 +0200117 size_t const CNBuffSize = 5 MB;
Yann Colletd2858e92016-05-30 15:10:09 +0200118 void* const CNBuffer = malloc(CNBuffSize);
119 void* const compressedBuffer = malloc(ZSTD_compressBound(CNBuffSize));
120 void* const decodedBuffer = malloc(CNBuffSize);
Yann Colletc0a9bf32016-05-30 01:56:08 +0200121 int testResult = 0;
Yann Collet4856a002015-01-24 01:58:16 +0100122 U32 testNb=0;
Yann Colletc0a9bf32016-05-30 01:56:08 +0200123 size_t cSize;
Yann Collet4856a002015-01-24 01:58:16 +0100124
Yann Colletc0a9bf32016-05-30 01:56:08 +0200125 /* Create compressible noise */
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 Colletd2858e92016-05-30 15:10:09 +0200131 RDG_genBuffer(CNBuffer, CNBuffSize, compressibility, 0., seed);
Yann Collet4856a002015-01-24 01:58:16 +0100132
Yann Colletd5d9bc32015-08-23 23:13:49 +0100133 /* Basic tests */
Yann Colletd2858e92016-05-30 15:10:09 +0200134 DISPLAYLEVEL(4, "test%3i : compress %u bytes : ", testNb++, (U32)CNBuffSize);
135 CHECKPLUS(r, ZSTD_compress(compressedBuffer, ZSTD_compressBound(CNBuffSize),
136 CNBuffer, CNBuffSize, 1),
Yann Colletc0a9bf32016-05-30 01:56:08 +0200137 cSize=r );
Yann Colletd2858e92016-05-30 15:10:09 +0200138 DISPLAYLEVEL(4, "OK (%u bytes : %.2f%%)\n", (U32)cSize, (double)cSize/CNBuffSize*100);
Yann Collet4856a002015-01-24 01:58:16 +0100139
Yann Colletd2858e92016-05-30 15:10:09 +0200140 DISPLAYLEVEL(4, "test%3i : decompress %u bytes : ", testNb++, (U32)CNBuffSize);
141 CHECKPLUS( r , ZSTD_decompress(decodedBuffer, CNBuffSize, compressedBuffer, cSize),
142 if (r != CNBuffSize) goto _output_error);
Yann Collet4856a002015-01-24 01:58:16 +0100143 DISPLAYLEVEL(4, "OK \n");
144
Yann Colletc0a9bf32016-05-30 01:56:08 +0200145 DISPLAYLEVEL(4, "test%3i : check decompressed result : ", testNb++);
146 { size_t u;
Yann Colletd2858e92016-05-30 15:10:09 +0200147 for (u=0; u<CNBuffSize; u++) {
Yann Colletc0a9bf32016-05-30 01:56:08 +0200148 if (((BYTE*)decodedBuffer)[u] != ((BYTE*)CNBuffer)[u]) goto _output_error;;
149 } }
150 DISPLAYLEVEL(4, "OK \n");
Yann Collet4856a002015-01-24 01:58:16 +0100151
152 DISPLAYLEVEL(4, "test%3i : decompress with 1 missing byte : ", testNb++);
Yann Colletd2858e92016-05-30 15:10:09 +0200153 { size_t const r = ZSTD_decompress(decodedBuffer, CNBuffSize, compressedBuffer, cSize-1);
Yann Colletc0a9bf32016-05-30 01:56:08 +0200154 if (!ZSTD_isError(r)) goto _output_error;
155 if (ZSTD_getErrorCode((size_t)r) != ZSTD_error_srcSize_wrong) goto _output_error; }
Yann Collet4856a002015-01-24 01:58:16 +0100156 DISPLAYLEVEL(4, "OK \n");
157
158 DISPLAYLEVEL(4, "test%3i : decompress with 1 too much byte : ", testNb++);
Yann Colletd2858e92016-05-30 15:10:09 +0200159 { size_t const r = ZSTD_decompress(decodedBuffer, CNBuffSize, compressedBuffer, cSize+1);
Yann Colletc0a9bf32016-05-30 01:56:08 +0200160 if (!ZSTD_isError(r)) goto _output_error;
161 if (ZSTD_getErrorCode(r) != ZSTD_error_srcSize_wrong) goto _output_error; }
Yann Collet4856a002015-01-24 01:58:16 +0100162 DISPLAYLEVEL(4, "OK \n");
163
Yann Collet389648c2016-04-12 19:13:08 +0200164 /* Dictionary and CCtx Duplication tests */
Yann Colletc0a9bf32016-05-30 01:56:08 +0200165 { ZSTD_CCtx* const ctxOrig = ZSTD_createCCtx();
166 ZSTD_CCtx* const ctxDuplicated = ZSTD_createCCtx();
167 ZSTD_DCtx* const dctx = ZSTD_createDCtx();
168 static const size_t dictSize = 551;
Yann Collet60096272016-01-08 17:27:50 +0100169
Yann Collet887e7da2016-04-11 20:12:27 +0200170 DISPLAYLEVEL(4, "test%3i : copy context too soon : ", testNb++);
Yann Collet389648c2016-04-12 19:13:08 +0200171 { size_t const copyResult = ZSTD_copyCCtx(ctxDuplicated, ctxOrig);
Yann Colletc0a9bf32016-05-30 01:56:08 +0200172 if (!ZSTD_isError(copyResult)) goto _output_error; } /* error must be detected */
Yann Collet887e7da2016-04-11 20:12:27 +0200173 DISPLAYLEVEL(4, "OK \n");
174
Yann Collet60096272016-01-08 17:27:50 +0100175 DISPLAYLEVEL(4, "test%3i : load dictionary into context : ", testNb++);
Yann Colletc0a9bf32016-05-30 01:56:08 +0200176 CHECK( ZSTD_compressBegin_usingDict(ctxOrig, CNBuffer, dictSize, 2) );
177 CHECK( ZSTD_copyCCtx(ctxDuplicated, ctxOrig) );
Yann Collet60096272016-01-08 17:27:50 +0100178 DISPLAYLEVEL(4, "OK \n");
179
Yann Collet30009522016-05-30 16:17:33 +0200180 DISPLAYLEVEL(4, "test%3i : compress with flat dictionary : ", testNb++);
Yann Collet60096272016-01-08 17:27:50 +0100181 cSize = 0;
Yann Colletd2858e92016-05-30 15:10:09 +0200182 CHECKPLUS(r, ZSTD_compressContinue(ctxOrig, compressedBuffer, ZSTD_compressBound(CNBuffSize),
183 (const char*)CNBuffer + dictSize, CNBuffSize - dictSize),
Yann Colletc0a9bf32016-05-30 01:56:08 +0200184 cSize += r);
Yann Colletd2858e92016-05-30 15:10:09 +0200185 CHECKPLUS(r, ZSTD_compressEnd(ctxOrig, (char*)compressedBuffer+cSize, ZSTD_compressBound(CNBuffSize)-cSize),
Yann Colletc0a9bf32016-05-30 01:56:08 +0200186 cSize += r);
Yann Colletd2858e92016-05-30 15:10:09 +0200187 DISPLAYLEVEL(4, "OK (%u bytes : %.2f%%)\n", (U32)cSize, (double)cSize/CNBuffSize*100);
Yann Collet60096272016-01-08 17:27:50 +0100188
Yann Collet30009522016-05-30 16:17:33 +0200189 DISPLAYLEVEL(4, "test%3i : frame built with flat dictionary should be decompressible : ", testNb++);
Yann Colletc0a9bf32016-05-30 01:56:08 +0200190 CHECKPLUS(r, ZSTD_decompress_usingDict(dctx,
Yann Colletd2858e92016-05-30 15:10:09 +0200191 decodedBuffer, CNBuffSize,
Yann Colletc0a9bf32016-05-30 01:56:08 +0200192 compressedBuffer, cSize,
193 CNBuffer, dictSize),
Yann Colletd2858e92016-05-30 15:10:09 +0200194 if (r != CNBuffSize - dictSize) goto _output_error);
Yann Collet60096272016-01-08 17:27:50 +0100195 DISPLAYLEVEL(4, "OK \n");
196
197 DISPLAYLEVEL(4, "test%3i : compress with duplicated context : ", testNb++);
Yann Collet389648c2016-04-12 19:13:08 +0200198 { size_t const cSizeOrig = cSize;
199 cSize = 0;
Yann Colletd2858e92016-05-30 15:10:09 +0200200 CHECKPLUS(r, ZSTD_compressContinue(ctxDuplicated, compressedBuffer, ZSTD_compressBound(CNBuffSize),
201 (const char*)CNBuffer + dictSize, CNBuffSize - dictSize),
Yann Colletc0a9bf32016-05-30 01:56:08 +0200202 cSize += r);
Yann Colletd2858e92016-05-30 15:10:09 +0200203 CHECKPLUS(r, ZSTD_compressEnd(ctxDuplicated, (char*)compressedBuffer+cSize, ZSTD_compressBound(CNBuffSize)-cSize),
Yann Colletc0a9bf32016-05-30 01:56:08 +0200204 cSize += r);
205 if (cSize != cSizeOrig) goto _output_error; /* should be identical ==> have same size */
Yann Collet389648c2016-04-12 19:13:08 +0200206 }
Yann Colletd2858e92016-05-30 15:10:09 +0200207 DISPLAYLEVEL(4, "OK (%u bytes : %.2f%%)\n", (U32)cSize, (double)cSize/CNBuffSize*100);
Yann Collet60096272016-01-08 17:27:50 +0100208
209 DISPLAYLEVEL(4, "test%3i : frame built with duplicated context should be decompressible : ", testNb++);
Yann Colletc0a9bf32016-05-30 01:56:08 +0200210 CHECKPLUS(r, ZSTD_decompress_usingDict(dctx,
Yann Colletd2858e92016-05-30 15:10:09 +0200211 decodedBuffer, CNBuffSize,
Yann Collet60096272016-01-08 17:27:50 +0100212 compressedBuffer, cSize,
Yann Colletc0a9bf32016-05-30 01:56:08 +0200213 CNBuffer, dictSize),
Yann Colletd2858e92016-05-30 15:10:09 +0200214 if (r != CNBuffSize - dictSize) goto _output_error);
Yann Collet60096272016-01-08 17:27:50 +0100215 DISPLAYLEVEL(4, "OK \n");
Yann Collet541dc7c2016-04-12 18:00:20 +0200216
217 DISPLAYLEVEL(4, "test%3i : check content size on duplicated context : ", testNb++);
Yann Colletd2858e92016-05-30 15:10:09 +0200218 { size_t const testSize = CNBuffSize / 3;
cyanb8806312016-05-30 18:20:46 +0200219 { ZSTD_compressionParameters const cPar = ZSTD_getCParams(2, testSize, dictSize);
Yann Colletf2a3b6e2016-05-31 18:13:56 +0200220 ZSTD_frameParameters const fPar = { 1 , 0 , 0 };
cyanb8806312016-05-30 18:20:46 +0200221 ZSTD_parameters p;
222 p.cParams = cPar; p.fParams = fPar;
Yann Colletd2858e92016-05-30 15:10:09 +0200223 CHECK( ZSTD_compressBegin_advanced(ctxOrig, CNBuffer, dictSize, p, testSize-1) );
Yann Collet33341de2016-05-29 23:09:51 +0200224 }
Yann Colletc0a9bf32016-05-30 01:56:08 +0200225 CHECK( ZSTD_copyCCtx(ctxDuplicated, ctxOrig) );
226
227 CHECKPLUS(r, ZSTD_compressContinue(ctxDuplicated, compressedBuffer, ZSTD_compressBound(testSize),
Yann Colletd2858e92016-05-30 15:10:09 +0200228 (const char*)CNBuffer + dictSize, CNBuffSize - dictSize),
Yann Colletc0a9bf32016-05-30 01:56:08 +0200229 cSize = r);
Yann Collet541dc7c2016-04-12 18:00:20 +0200230 { ZSTD_frameParams fp;
Yann Collet33341de2016-05-29 23:09:51 +0200231 if (ZSTD_getFrameParams(&fp, compressedBuffer, cSize)) goto _output_error;
Yann Collet541dc7c2016-04-12 18:00:20 +0200232 if ((fp.frameContentSize != testSize) && (fp.frameContentSize != 0)) goto _output_error;
233 } }
234 DISPLAYLEVEL(4, "OK \n");
235
236 ZSTD_freeCCtx(ctxOrig);
237 ZSTD_freeCCtx(ctxDuplicated);
238 ZSTD_freeDCtx(dctx);
Yann Collet60096272016-01-08 17:27:50 +0100239 }
240
Yann Collet30009522016-05-30 16:17:33 +0200241 /* Dictionary and dictBuilder tests */
242 { ZSTD_CCtx* const cctx = ZSTD_createCCtx();
243 ZSTD_DCtx* const dctx = ZSTD_createDCtx();
244 size_t dictSize = 16 KB;
245 void* dictBuffer = malloc(dictSize);
246 size_t const totalSampleSize = 1 MB;
247 size_t const sampleUnitSize = 8 KB;
Yann Colletb81cbba2016-05-30 22:29:45 +0200248 U32 const nbSamples = (U32)(totalSampleSize / sampleUnitSize);
Yann Collet30009522016-05-30 16:17:33 +0200249 size_t* const samplesSizes = (size_t*) malloc(nbSamples * sizeof(size_t));
250
251 if (dictBuffer==NULL || samplesSizes==NULL) {
252 free(dictBuffer);
253 free(samplesSizes);
254 goto _output_error;
255 }
256
257 DISPLAYLEVEL(4, "test%3i : dictBuilder : ", testNb++);
258 { U32 u; for (u=0; u<nbSamples; u++) samplesSizes[u] = sampleUnitSize; }
259 dictSize = ZDICT_trainFromBuffer(dictBuffer, dictSize,
260 CNBuffer, samplesSizes, nbSamples);
261 if (ZDICT_isError(dictSize)) goto _output_error;
262 DISPLAYLEVEL(4, "OK, created dictionary of size %u \n", (U32)dictSize);
263
264 DISPLAYLEVEL(4, "test%3i : compress with dictionary : ", testNb++);
265 cSize = ZSTD_compress_usingDict(cctx, compressedBuffer, ZSTD_compressBound(CNBuffSize),
266 CNBuffer, CNBuffSize,
267 dictBuffer, dictSize, 4);
268 if (ZSTD_isError(cSize)) goto _output_error;
269 DISPLAYLEVEL(4, "OK (%u bytes : %.2f%%)\n", (U32)cSize, (double)cSize/CNBuffSize*100);
270
271 DISPLAYLEVEL(4, "test%3i : frame built with dictionary should be decompressible : ", testNb++);
272 CHECKPLUS(r, ZSTD_decompress_usingDict(dctx,
273 decodedBuffer, CNBuffSize,
274 compressedBuffer, cSize,
275 dictBuffer, dictSize),
276 if (r != CNBuffSize) goto _output_error);
277 DISPLAYLEVEL(4, "OK \n");
278
279 DISPLAYLEVEL(4, "test%3i : compress without dictID : ", testNb++);
Yann Colletf2a3b6e2016-05-31 18:13:56 +0200280 { ZSTD_frameParameters const fParams = { 0 /*contentSize*/, 0 /*checksum*/, 1 /*NoDictID*/ };
cyanb8806312016-05-30 18:20:46 +0200281 ZSTD_compressionParameters const cParams = ZSTD_getCParams(3, CNBuffSize, dictSize);
282 ZSTD_parameters p;
283 p.cParams = cParams; p.fParams = fParams;
Yann Collet30009522016-05-30 16:17:33 +0200284 cSize = ZSTD_compress_advanced(cctx, compressedBuffer, ZSTD_compressBound(CNBuffSize),
285 CNBuffer, CNBuffSize,
286 dictBuffer, dictSize, p);
287 if (ZSTD_isError(cSize)) goto _output_error;
288 }
289 DISPLAYLEVEL(4, "OK (%u bytes : %.2f%%)\n", (U32)cSize, (double)cSize/CNBuffSize*100);
290
291 DISPLAYLEVEL(4, "test%3i : frame built without dictID should be decompressible : ", testNb++);
292 CHECKPLUS(r, ZSTD_decompress_usingDict(dctx,
293 decodedBuffer, CNBuffSize,
294 compressedBuffer, cSize,
295 dictBuffer, dictSize),
296 if (r != CNBuffSize) goto _output_error);
297 DISPLAYLEVEL(4, "OK \n");
298
299 ZSTD_freeCCtx(cctx);
300 ZSTD_freeDCtx(dctx);
301 free(dictBuffer);
302 free(samplesSizes);
303 }
304
Yann Collet4856a002015-01-24 01:58:16 +0100305 /* Decompression defense tests */
306 DISPLAYLEVEL(4, "test%3i : Check input length for magic number : ", testNb++);
Yann Colletd2858e92016-05-30 15:10:09 +0200307 { size_t const r = ZSTD_decompress(decodedBuffer, CNBuffSize, CNBuffer, 3);
Yann Colletc0a9bf32016-05-30 01:56:08 +0200308 if (!ZSTD_isError(r)) goto _output_error;
309 if (r != (size_t)-ZSTD_error_srcSize_wrong) goto _output_error; }
Yann Collet4856a002015-01-24 01:58:16 +0100310 DISPLAYLEVEL(4, "OK \n");
311
312 DISPLAYLEVEL(4, "test%3i : Check magic Number : ", testNb++);
313 ((char*)(CNBuffer))[0] = 1;
Yann Colletd2858e92016-05-30 15:10:09 +0200314 { size_t const r = ZSTD_decompress(decodedBuffer, CNBuffSize, CNBuffer, 4);
Yann Collet33341de2016-05-29 23:09:51 +0200315 if (!ZSTD_isError(r)) goto _output_error; }
Yann Collet4856a002015-01-24 01:58:16 +0100316 DISPLAYLEVEL(4, "OK \n");
317
Yann Colletbf42c8e2016-01-09 01:08:23 +0100318 /* block API tests */
Yann Colletd1d210f2016-03-19 12:12:07 +0100319 { ZSTD_CCtx* const cctx = ZSTD_createCCtx();
Yann Colletbf42c8e2016-01-09 01:08:23 +0100320 ZSTD_DCtx* const dctx = ZSTD_createDCtx();
Yann Collet33341de2016-05-29 23:09:51 +0200321 static const size_t blockSize = 100 KB;
322 static const size_t dictSize = 16 KB;
Yann Colletbf42c8e2016-01-09 01:08:23 +0100323
324 /* basic block compression */
325 DISPLAYLEVEL(4, "test%3i : Block compression test : ", testNb++);
Yann Colletc0a9bf32016-05-30 01:56:08 +0200326 CHECK( ZSTD_compressBegin(cctx, 5) );
Yann Colletbf42c8e2016-01-09 01:08:23 +0100327 cSize = ZSTD_compressBlock(cctx, compressedBuffer, ZSTD_compressBound(blockSize), CNBuffer, blockSize);
328 if (ZSTD_isError(cSize)) goto _output_error;
329 DISPLAYLEVEL(4, "OK \n");
330
331 DISPLAYLEVEL(4, "test%3i : Block decompression test : ", testNb++);
Yann Colletc0a9bf32016-05-30 01:56:08 +0200332 CHECK( ZSTD_decompressBegin(dctx) );
Yann Colletd2858e92016-05-30 15:10:09 +0200333 { CHECKTEST(r, ZSTD_decompressBlock(dctx, decodedBuffer, CNBuffSize, compressedBuffer, cSize) );
334 if (r != blockSize) goto _output_error; }
Yann Colletbf42c8e2016-01-09 01:08:23 +0100335 DISPLAYLEVEL(4, "OK \n");
336
Yann Colletb0125102016-01-09 02:00:10 +0100337 /* dictionary block compression */
338 DISPLAYLEVEL(4, "test%3i : Dictionary Block compression test : ", testNb++);
Yann Colletc0a9bf32016-05-30 01:56:08 +0200339 CHECK( ZSTD_compressBegin_usingDict(cctx, CNBuffer, dictSize, 5) );
Yann Colletb0125102016-01-09 02:00:10 +0100340 cSize = ZSTD_compressBlock(cctx, compressedBuffer, ZSTD_compressBound(blockSize), (char*)CNBuffer+dictSize, blockSize);
341 if (ZSTD_isError(cSize)) goto _output_error;
342 DISPLAYLEVEL(4, "OK \n");
343
344 DISPLAYLEVEL(4, "test%3i : Dictionary Block decompression test : ", testNb++);
Yann Colletc0a9bf32016-05-30 01:56:08 +0200345 CHECK( ZSTD_decompressBegin_usingDict(dctx, CNBuffer, dictSize) );
Yann Colletd2858e92016-05-30 15:10:09 +0200346 { CHECKTEST( r, ZSTD_decompressBlock(dctx, decodedBuffer, CNBuffSize, compressedBuffer, cSize) );
Yann Colletc0a9bf32016-05-30 01:56:08 +0200347 if (r != blockSize) goto _output_error; }
Yann Colletb0125102016-01-09 02:00:10 +0100348 DISPLAYLEVEL(4, "OK \n");
349
Yann Colletbf42c8e2016-01-09 01:08:23 +0100350 ZSTD_freeCCtx(cctx);
351 ZSTD_freeDCtx(dctx);
352 }
353
Yann Collet213089c2015-06-18 07:43:16 -0800354 /* long rle test */
Yann Colletd1d210f2016-03-19 12:12:07 +0100355 { size_t sampleSize = 0;
Yann Collet213089c2015-06-18 07:43:16 -0800356 DISPLAYLEVEL(4, "test%3i : Long RLE test : ", testNb++);
Yann Colletc0a9bf32016-05-30 01:56:08 +0200357 RDG_genBuffer(CNBuffer, sampleSize, compressibility, 0., seed+1);
Yann Collet213089c2015-06-18 07:43:16 -0800358 memset((char*)CNBuffer+sampleSize, 'B', 256 KB - 1);
359 sampleSize += 256 KB - 1;
Yann Colletc0a9bf32016-05-30 01:56:08 +0200360 RDG_genBuffer((char*)CNBuffer+sampleSize, 96 KB, compressibility, 0., seed+2);
Yann Collet213089c2015-06-18 07:43:16 -0800361 sampleSize += 96 KB;
Yann Collet5be2dd22015-11-11 13:43:58 +0100362 cSize = ZSTD_compress(compressedBuffer, ZSTD_compressBound(sampleSize), CNBuffer, sampleSize, 1);
Yann Collet213089c2015-06-18 07:43:16 -0800363 if (ZSTD_isError(cSize)) goto _output_error;
Yann Colletc0a9bf32016-05-30 01:56:08 +0200364 { CHECKTEST(regenSize, ZSTD_decompress(decodedBuffer, sampleSize, compressedBuffer, cSize));
365 if (regenSize!=sampleSize) goto _output_error; }
Yann Collet213089c2015-06-18 07:43:16 -0800366 DISPLAYLEVEL(4, "OK \n");
367 }
368
Yann Colletc0a9bf32016-05-30 01:56:08 +0200369 /* All zeroes test (test bug #137) */
Yann Collet4ba85342016-03-07 20:01:45 +0100370 #define ZEROESLENGTH 100
371 DISPLAYLEVEL(4, "test%3i : compress %u zeroes : ", testNb++, ZEROESLENGTH);
372 memset(CNBuffer, 0, ZEROESLENGTH);
Yann Colletc0a9bf32016-05-30 01:56:08 +0200373 { CHECKTEST(r, ZSTD_compress(compressedBuffer, ZSTD_compressBound(ZEROESLENGTH), CNBuffer, ZEROESLENGTH, 1) );
374 cSize = r; }
Yann Collet4ba85342016-03-07 20:01:45 +0100375 DISPLAYLEVEL(4, "OK (%u bytes : %.2f%%)\n", (U32)cSize, (double)cSize/ZEROESLENGTH*100);
376
377 DISPLAYLEVEL(4, "test%3i : decompress %u zeroes : ", testNb++, ZEROESLENGTH);
Yann Colletc0a9bf32016-05-30 01:56:08 +0200378 { CHECKTEST(r, ZSTD_decompress(decodedBuffer, ZEROESLENGTH, compressedBuffer, cSize) );
379 if (r != ZEROESLENGTH) goto _output_error; }
Yann Collet4ba85342016-03-07 20:01:45 +0100380 DISPLAYLEVEL(4, "OK \n");
381
382 /* nbSeq limit test */
Yann Colletd1d210f2016-03-19 12:12:07 +0100383 #define _3BYTESTESTLENGTH 131000
384 #define NB3BYTESSEQLOG 9
385 #define NB3BYTESSEQ (1 << NB3BYTESSEQLOG)
386 #define NB3BYTESSEQMASK (NB3BYTESSEQ-1)
Yann Collet0d9ce042016-03-19 13:21:08 +0100387 /* creates a buffer full of 3-bytes sequences */
Yann Colletd1d210f2016-03-19 12:12:07 +0100388 { BYTE _3BytesSeqs[NB3BYTESSEQ][3];
Yann Collet0d9ce042016-03-19 13:21:08 +0100389 U32 rSeed = 1;
Yann Collet4ba85342016-03-07 20:01:45 +0100390
Yann Collet0d9ce042016-03-19 13:21:08 +0100391 /* create batch of 3-bytes sequences */
Yann Colletd1d210f2016-03-19 12:12:07 +0100392 { int i; for (i=0; i < NB3BYTESSEQ; i++) {
Yann Collet0d9ce042016-03-19 13:21:08 +0100393 _3BytesSeqs[i][0] = (BYTE)(FUZ_rand(&rSeed) & 255);
394 _3BytesSeqs[i][1] = (BYTE)(FUZ_rand(&rSeed) & 255);
395 _3BytesSeqs[i][2] = (BYTE)(FUZ_rand(&rSeed) & 255);
Yann Colletd1d210f2016-03-19 12:12:07 +0100396 }}
Yann Collet4ba85342016-03-07 20:01:45 +0100397
Yann Collet0d9ce042016-03-19 13:21:08 +0100398 /* randomly fills CNBuffer with prepared 3-bytes sequences */
Yann Colletd2858e92016-05-30 15:10:09 +0200399 { int i; for (i=0; i < _3BYTESTESTLENGTH; i += 3) { /* note : CNBuffer size > _3BYTESTESTLENGTH+3 */
400 U32 const id = FUZ_rand(&rSeed) & NB3BYTESSEQMASK;
Yann Collet4ba85342016-03-07 20:01:45 +0100401 ((BYTE*)CNBuffer)[i+0] = _3BytesSeqs[id][0];
402 ((BYTE*)CNBuffer)[i+1] = _3BytesSeqs[id][1];
403 ((BYTE*)CNBuffer)[i+2] = _3BytesSeqs[id][2];
Yann Collet0d9ce042016-03-19 13:21:08 +0100404 } }}
405 DISPLAYLEVEL(4, "test%3i : compress lots 3-bytes sequences : ", testNb++);
Yann Colletc0a9bf32016-05-30 01:56:08 +0200406 { CHECKTEST(r, ZSTD_compress(compressedBuffer, ZSTD_compressBound(_3BYTESTESTLENGTH),
407 CNBuffer, _3BYTESTESTLENGTH, 19) );
408 cSize = r; }
Yann Collet0d9ce042016-03-19 13:21:08 +0100409 DISPLAYLEVEL(4, "OK (%u bytes : %.2f%%)\n", (U32)cSize, (double)cSize/_3BYTESTESTLENGTH*100);
Yann Collet4ba85342016-03-07 20:01:45 +0100410
Yann Collet0d9ce042016-03-19 13:21:08 +0100411 DISPLAYLEVEL(4, "test%3i : decompress lots 3-bytes sequence : ", testNb++);
Yann Colletc0a9bf32016-05-30 01:56:08 +0200412 { CHECKTEST(r, ZSTD_decompress(decodedBuffer, _3BYTESTESTLENGTH, compressedBuffer, cSize) );
413 if (r != _3BYTESTESTLENGTH) goto _output_error; }
Yann Collet0d9ce042016-03-19 13:21:08 +0100414 DISPLAYLEVEL(4, "OK \n");
Yann Collet4ba85342016-03-07 20:01:45 +0100415
Yann Collet4856a002015-01-24 01:58:16 +0100416_end:
417 free(CNBuffer);
418 free(compressedBuffer);
419 free(decodedBuffer);
420 return testResult;
421
422_output_error:
423 testResult = 1;
424 DISPLAY("Error detected in Unit tests ! \n");
425 goto _end;
426}
427
428
429static size_t findDiff(const void* buf1, const void* buf2, size_t max)
430{
Yann Collet213089c2015-06-18 07:43:16 -0800431 const BYTE* b1 = (const BYTE*)buf1;
432 const BYTE* b2 = (const BYTE*)buf2;
Yann Colletc0a9bf32016-05-30 01:56:08 +0200433 size_t u;
434 for (u=0; u<max; u++) {
435 if (b1[u] != b2[u]) break;
Yann Collet4856a002015-01-24 01:58:16 +0100436 }
Yann Colletc0a9bf32016-05-30 01:56:08 +0200437 return u;
Yann Collet4856a002015-01-24 01:58:16 +0100438}
439
Yann Collet1fce6e02016-04-08 20:26:33 +0200440
441static size_t FUZ_rLogLength(U32* seed, U32 logLength)
442{
443 size_t const lengthMask = ((size_t)1 << logLength) - 1;
444 return (lengthMask+1) + (FUZ_rand(seed) & lengthMask);
445}
446
447static size_t FUZ_randomLength(U32* seed, U32 maxLog)
448{
449 U32 const logLength = FUZ_rand(seed) % maxLog;
450 return FUZ_rLogLength(seed, logLength);
451}
452
Yann Colletc0a9bf32016-05-30 01:56:08 +0200453#undef CHECK
Yann Collet0d9ce042016-03-19 13:21:08 +0100454#define CHECK(cond, ...) if (cond) { DISPLAY("Error => "); DISPLAY(__VA_ARGS__); \
455 DISPLAY(" (seed %u, test nb %u) \n", seed, testNb); goto _output_error; }
Yann Collet4856a002015-01-24 01:58:16 +0100456
Yann Colletea63bb72016-04-08 15:25:32 +0200457static int fuzzerTests(U32 seed, U32 nbTests, unsigned startTest, U32 const maxDurationS, double compressibility)
Yann Collet4856a002015-01-24 01:58:16 +0100458{
Yann Collet1fce6e02016-04-08 20:26:33 +0200459 static const U32 maxSrcLog = 23;
460 static const U32 maxSampleLog = 22;
Yann Colletc0a9bf32016-05-30 01:56:08 +0200461 size_t const srcBufferSize = (size_t)1<<maxSrcLog;
462 size_t const dstBufferSize = (size_t)1<<maxSampleLog;
463 size_t const cBufferSize = ZSTD_compressBound(dstBufferSize);
Yann Colletd5d9bc32015-08-23 23:13:49 +0100464 BYTE* cNoiseBuffer[5];
Yann Colletc0a9bf32016-05-30 01:56:08 +0200465 BYTE* srcBuffer; /* jumping pointer */
466 BYTE* const cBuffer = (BYTE*) malloc (cBufferSize);
467 BYTE* const dstBuffer = (BYTE*) malloc (dstBufferSize);
468 BYTE* const mirrorBuffer = (BYTE*) malloc (dstBufferSize);
Yann Colletd2858e92016-05-30 15:10:09 +0200469 ZSTD_CCtx* const refCtx = ZSTD_createCCtx();
470 ZSTD_CCtx* const ctx = ZSTD_createCCtx();
471 ZSTD_DCtx* const dctx = ZSTD_createDCtx();
Yann Collet30009522016-05-30 16:17:33 +0200472 U32 result = 0;
473 U32 testNb = 0;
474 U32 coreSeed = seed, lseed = 0;
Yann Colletd2858e92016-05-30 15:10:09 +0200475 clock_t const startClock = clock();
Yann Colletea63bb72016-04-08 15:25:32 +0200476 clock_t const maxClockSpan = maxDurationS * CLOCKS_PER_SEC;
Yann Collet4856a002015-01-24 01:58:16 +0100477
478 /* allocation */
Yann Colletd5d9bc32015-08-23 23:13:49 +0100479 cNoiseBuffer[0] = (BYTE*)malloc (srcBufferSize);
480 cNoiseBuffer[1] = (BYTE*)malloc (srcBufferSize);
481 cNoiseBuffer[2] = (BYTE*)malloc (srcBufferSize);
482 cNoiseBuffer[3] = (BYTE*)malloc (srcBufferSize);
483 cNoiseBuffer[4] = (BYTE*)malloc (srcBufferSize);
Yann Collete47c4e52015-12-05 09:23:53 +0100484 CHECK (!cNoiseBuffer[0] || !cNoiseBuffer[1] || !cNoiseBuffer[2] || !cNoiseBuffer[3] || !cNoiseBuffer[4]
Yann Colletecd651b2016-01-07 15:35:18 +0100485 || !dstBuffer || !mirrorBuffer || !cBuffer || !refCtx || !ctx || !dctx,
Yann Colletd5d9bc32015-08-23 23:13:49 +0100486 "Not enough memory, fuzzer tests cancelled");
Yann Collet4856a002015-01-24 01:58:16 +0100487
Yann Colletd5d9bc32015-08-23 23:13:49 +0100488 /* Create initial samples */
489 RDG_genBuffer(cNoiseBuffer[0], srcBufferSize, 0.00, 0., coreSeed); /* pure noise */
490 RDG_genBuffer(cNoiseBuffer[1], srcBufferSize, 0.05, 0., coreSeed); /* barely compressible */
491 RDG_genBuffer(cNoiseBuffer[2], srcBufferSize, compressibility, 0., coreSeed);
492 RDG_genBuffer(cNoiseBuffer[3], srcBufferSize, 0.95, 0., coreSeed); /* highly compressible */
493 RDG_genBuffer(cNoiseBuffer[4], srcBufferSize, 1.00, 0., coreSeed); /* sparse content */
494 srcBuffer = cNoiseBuffer[2];
Yann Collet4856a002015-01-24 01:58:16 +0100495
496 /* catch up testNb */
Yann Collet546c9b12016-03-19 12:47:52 +0100497 for (testNb=1; testNb < startTest; testNb++) FUZ_rand(&coreSeed);
Yann Collet4856a002015-01-24 01:58:16 +0100498
Yann Collet546c9b12016-03-19 12:47:52 +0100499 /* main test loop */
Yann Colletea63bb72016-04-08 15:25:32 +0200500 for ( ; (testNb <= nbTests) || (FUZ_clockSpan(startClock) < maxClockSpan); testNb++ ) {
Yann Colletc0a9bf32016-05-30 01:56:08 +0200501 size_t sampleSize, maxTestSize, totalTestSize;
502 size_t cSize, totalCSize, totalGenSize;
Yann Collet6c903a82016-05-28 13:34:07 +0200503 XXH64_state_t xxhState;
Yann Collet1fce6e02016-04-08 20:26:33 +0200504 U64 crcOrig;
Yann Collet110cc142015-11-19 12:02:28 +0100505 BYTE* sampleBuffer;
Yann Collet4bfe4152015-12-06 13:18:37 +0100506 const BYTE* dict;
507 size_t dictSize;
Yann Collet4856a002015-01-24 01:58:16 +0100508
Yann Collet546c9b12016-03-19 12:47:52 +0100509 /* notification */
510 if (nbTests >= testNb) { DISPLAYUPDATE(2, "\r%6u/%6u ", testNb, nbTests); }
Yann Collet1c2ddba2015-12-04 17:45:35 +0100511 else { DISPLAYUPDATE(2, "\r%6u ", testNb); }
512
Yann Collet4856a002015-01-24 01:58:16 +0100513 FUZ_rand(&coreSeed);
Yann Collet0d9ce042016-03-19 13:21:08 +0100514 { U32 const prime1 = 2654435761U; lseed = coreSeed ^ prime1; }
Yann Collet1fce6e02016-04-08 20:26:33 +0200515
516 /* srcBuffer selection [0-4] */
517 { U32 buffNb = FUZ_rand(&lseed) & 0x7F;
518 if (buffNb & 7) buffNb=2; /* most common : compressible (P) */
519 else {
520 buffNb >>= 3;
521 if (buffNb & 7) {
522 const U32 tnb[2] = { 1, 3 }; /* barely/highly compressible */
523 buffNb = tnb[buffNb >> 3];
524 } else {
525 const U32 tnb[2] = { 0, 4 }; /* not compressible / sparse */
526 buffNb = tnb[buffNb >> 3];
527 } }
528 srcBuffer = cNoiseBuffer[buffNb];
529 }
530
531 /* select src segment */
Yann Colletd2858e92016-05-30 15:10:09 +0200532 sampleSize = FUZ_randomLength(&lseed, maxSampleLog);
Yann Collet4856a002015-01-24 01:58:16 +0100533
Yann Collet110cc142015-11-19 12:02:28 +0100534 /* create sample buffer (to catch read error with valgrind & sanitizers) */
535 sampleBuffer = (BYTE*)malloc(sampleSize);
Yann Colletd2858e92016-05-30 15:10:09 +0200536 CHECK(sampleBuffer==NULL, "not enough memory for sample buffer");
Yann Colletc0a9bf32016-05-30 01:56:08 +0200537 { size_t const sampleStart = FUZ_rand(&lseed) % (srcBufferSize - sampleSize);
538 memcpy(sampleBuffer, srcBuffer + sampleStart, sampleSize); }
Yann Collet110cc142015-11-19 12:02:28 +0100539 crcOrig = XXH64(sampleBuffer, sampleSize, 0);
540
Yann Collet1fce6e02016-04-08 20:26:33 +0200541 /* compression tests */
Yann Colletd2858e92016-05-30 15:10:09 +0200542 { unsigned const cLevel = (FUZ_rand(&lseed) % (ZSTD_maxCLevel() - (FUZ_highbit32((U32)sampleSize)/3))) + 1;
Yann Collet1fce6e02016-04-08 20:26:33 +0200543 cSize = ZSTD_compressCCtx(ctx, cBuffer, cBufferSize, sampleBuffer, sampleSize, cLevel);
544 CHECK(ZSTD_isError(cSize), "ZSTD_compressCCtx failed");
Yann Collet4856a002015-01-24 01:58:16 +0100545
Yann Collet1fce6e02016-04-08 20:26:33 +0200546 /* compression failure test : too small dest buffer */
547 if (cSize > 3) {
548 const size_t missing = (FUZ_rand(&lseed) % (cSize-2)) + 1; /* no problem, as cSize > 4 (frameHeaderSizer) */
549 const size_t tooSmallSize = cSize - missing;
550 const U32 endMark = 0x4DC2B1A9;
551 memcpy(dstBuffer+tooSmallSize, &endMark, 4);
552 { size_t const errorCode = ZSTD_compressCCtx(ctx, dstBuffer, tooSmallSize, sampleBuffer, sampleSize, cLevel);
553 CHECK(!ZSTD_isError(errorCode), "ZSTD_compressCCtx should have failed ! (buffer too small : %u < %u)", (U32)tooSmallSize, (U32)cSize); }
554 { U32 endCheck; memcpy(&endCheck, dstBuffer+tooSmallSize, 4);
555 CHECK(endCheck != endMark, "ZSTD_compressCCtx : dst buffer overflow"); }
Yann Colletd2858e92016-05-30 15:10:09 +0200556 } }
Yann Collet1fce6e02016-04-08 20:26:33 +0200557
Yann Collet546c9b12016-03-19 12:47:52 +0100558 /* frame header decompression test */
Yann Collet346bffb2016-03-15 15:24:52 +0100559 { ZSTD_frameParams dParams;
560 size_t const check = ZSTD_getFrameParams(&dParams, cBuffer, cSize);
561 CHECK(ZSTD_isError(check), "Frame Parameters extraction failed");
562 CHECK(dParams.frameContentSize != sampleSize, "Frame content size incorrect");
563 }
564
Yann Collet546c9b12016-03-19 12:47:52 +0100565 /* successful decompression test */
Yann Collet1fce6e02016-04-08 20:26:33 +0200566 { size_t const margin = (FUZ_rand(&lseed) & 1) ? 0 : (FUZ_rand(&lseed) & 31) + 1;
Yann Colletc0a9bf32016-05-30 01:56:08 +0200567 size_t const dSize = ZSTD_decompress(dstBuffer, sampleSize + margin, cBuffer, cSize);
Yann Collet546c9b12016-03-19 12:47:52 +0100568 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 +0200569 { U64 const crcDest = XXH64(dstBuffer, sampleSize, 0);
570 CHECK(crcOrig != crcDest, "decompression result corrupted (pos %u / %u)", (U32)findDiff(sampleBuffer, dstBuffer, sampleSize), (U32)sampleSize);
571 } }
Yann Collet110cc142015-11-19 12:02:28 +0100572
573 free(sampleBuffer); /* no longer useful after this point */
Yann Colletf3cb79b2015-08-20 00:02:43 +0100574
575 /* truncated src decompression test */
Yann Collet1fce6e02016-04-08 20:26:33 +0200576 { size_t const missing = (FUZ_rand(&lseed) % (cSize-2)) + 1; /* no problem, as cSize > 4 (frameHeaderSizer) */
577 size_t const tooSmallSize = cSize - missing;
Yann Colletd2858e92016-05-30 15:10:09 +0200578 void* cBufferTooSmall = malloc(tooSmallSize); /* valgrind will catch read overflows */
Yann Colletf3cb79b2015-08-20 00:02:43 +0100579 CHECK(cBufferTooSmall == NULL, "not enough memory !");
Yann Colletd5d9bc32015-08-23 23:13:49 +0100580 memcpy(cBufferTooSmall, cBuffer, tooSmallSize);
Yann Collet1fce6e02016-04-08 20:26:33 +0200581 { size_t const errorCode = ZSTD_decompress(dstBuffer, dstBufferSize, cBufferTooSmall, tooSmallSize);
582 CHECK(!ZSTD_isError(errorCode), "ZSTD_decompress should have failed ! (truncated src buffer)"); }
Yann Colletf3cb79b2015-08-20 00:02:43 +0100583 free(cBufferTooSmall);
584 }
585
586 /* too small dst decompression test */
Yann Colletd1d210f2016-03-19 12:12:07 +0100587 if (sampleSize > 3) {
Yann Colletea63bb72016-04-08 15:25:32 +0200588 size_t const missing = (FUZ_rand(&lseed) % (sampleSize-2)) + 1; /* no problem, as cSize > 4 (frameHeaderSizer) */
589 size_t const tooSmallSize = sampleSize - missing;
Yann Colletf3cb79b2015-08-20 00:02:43 +0100590 static const BYTE token = 0xA9;
591 dstBuffer[tooSmallSize] = token;
Yann Collet1fce6e02016-04-08 20:26:33 +0200592 { size_t const errorCode = ZSTD_decompress(dstBuffer, tooSmallSize, cBuffer, cSize);
593 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 +0100594 CHECK(dstBuffer[tooSmallSize] != token, "ZSTD_decompress : dst buffer overflow");
595 }
Yann Collet997f9ee2015-08-21 02:44:20 +0100596
597 /* noisy src decompression test */
Yann Colletd1d210f2016-03-19 12:12:07 +0100598 if (cSize > 6) {
599 /* insert noise into src */
600 { U32 const maxNbBits = FUZ_highbit32((U32)(cSize-4));
601 size_t pos = 4; /* preserve magic number (too easy to detect) */
602 for (;;) {
603 /* keep some original src */
604 { U32 const nbBits = FUZ_rand(&lseed) % maxNbBits;
605 size_t const mask = (1<<nbBits) - 1;
606 size_t const skipLength = FUZ_rand(&lseed) & mask;
607 pos += skipLength;
608 }
609 if (pos <= cSize) break;
610 /* add noise */
Yann Collet33341de2016-05-29 23:09:51 +0200611 { U32 const nbBitsCodes = FUZ_rand(&lseed) % maxNbBits;
612 U32 const nbBits = nbBitsCodes ? nbBitsCodes-1 : 0;
613 size_t const mask = (1<<nbBits) - 1;
614 size_t const rNoiseLength = (FUZ_rand(&lseed) & mask) + 1;
615 size_t const noiseLength = MIN(rNoiseLength, cSize-pos);
616 size_t const noiseStart = FUZ_rand(&lseed) % (srcBufferSize - noiseLength);
Yann Colletd1d210f2016-03-19 12:12:07 +0100617 memcpy(cBuffer + pos, srcBuffer + noiseStart, noiseLength);
618 pos += noiseLength;
619 } } }
Yann Collet997f9ee2015-08-21 02:44:20 +0100620
621 /* decompress noisy source */
Yann Colletd1d210f2016-03-19 12:12:07 +0100622 { U32 const endMark = 0xA9B1C3D6;
Yann Collet997f9ee2015-08-21 02:44:20 +0100623 memcpy(dstBuffer+sampleSize, &endMark, 4);
Yann Collet1fce6e02016-04-08 20:26:33 +0200624 { size_t const decompressResult = ZSTD_decompress(dstBuffer, sampleSize, cBuffer, cSize);
625 /* result *may* be an unlikely success, but even then, it must strictly respect dst buffer boundaries */
626 CHECK((!ZSTD_isError(decompressResult)) && (decompressResult>sampleSize),
627 "ZSTD_decompress on noisy src : result is too large : %u > %u (dst buffer)", (U32)decompressResult, (U32)sampleSize);
628 }
629 { U32 endCheck; memcpy(&endCheck, dstBuffer+sampleSize, 4);
630 CHECK(endMark!=endCheck, "ZSTD_decompress on noisy src : dst buffer overflow");
631 } } } /* noisy src decompression test */
Yann Collet417890c2015-12-04 17:16:37 +0100632
Yann Collet1fce6e02016-04-08 20:26:33 +0200633 /*===== Streaming compression test, scattered segments and dictionary =====*/
634
635 { U32 const testLog = FUZ_rand(&lseed) % maxSrcLog;
636 int const cLevel = (FUZ_rand(&lseed) % (ZSTD_maxCLevel() - (testLog/3))) + 1;
637 maxTestSize = FUZ_rLogLength(&lseed, testLog);
638 if (maxTestSize >= dstBufferSize) maxTestSize = dstBufferSize-1;
639
Yann Colletc0a9bf32016-05-30 01:56:08 +0200640 dictSize = FUZ_randomLength(&lseed, maxSampleLog); /* needed also for decompression */
641 dict = srcBuffer + (FUZ_rand(&lseed) % (srcBufferSize - dictSize));
Yann Collet1fce6e02016-04-08 20:26:33 +0200642
Yann Colletf2a3b6e2016-05-31 18:13:56 +0200643 if (FUZ_rand(&lseed) & 0xF) {
Yann Collet33341de2016-05-29 23:09:51 +0200644 size_t const errorCode = ZSTD_compressBegin_usingDict(refCtx, dict, dictSize, cLevel);
645 CHECK (ZSTD_isError(errorCode), "ZSTD_compressBegin_usingDict error : %s", ZSTD_getErrorName(errorCode));
646 } else {
cyanb8806312016-05-30 18:20:46 +0200647 ZSTD_compressionParameters const cPar = ZSTD_getCParams(cLevel, 0, dictSize);
Yann Colletf2a3b6e2016-05-31 18:13:56 +0200648 ZSTD_frameParameters const fpar = { FUZ_rand(&lseed)&1 /* contentSizeFlag */,
649 !(FUZ_rand(&lseed)&3) /* contentChecksumFlag*/,
650 0 /*NodictID*/ }; /* note : since dictionary is fake, dictIDflag has no impact */
cyanb8806312016-05-30 18:20:46 +0200651 ZSTD_parameters p;
652 size_t errorCode;
653 p.cParams = cPar; p.fParams = fpar;
654 errorCode = ZSTD_compressBegin_advanced(refCtx, dict, dictSize, p, 0);
Yann Collet33341de2016-05-29 23:09:51 +0200655 CHECK (ZSTD_isError(errorCode), "ZSTD_compressBegin_advanced error : %s", ZSTD_getErrorName(errorCode));
656 }
Yann Collet1fce6e02016-04-08 20:26:33 +0200657 { size_t const errorCode = ZSTD_copyCCtx(ctx, refCtx);
658 CHECK (ZSTD_isError(errorCode), "ZSTD_copyCCtx error : %s", ZSTD_getErrorName(errorCode)); }
659 }
Yann Collet6c903a82016-05-28 13:34:07 +0200660 XXH64_reset(&xxhState, 0);
Yann Colletd2858e92016-05-30 15:10:09 +0200661 { U32 const nbChunks = (FUZ_rand(&lseed) & 127) + 2;
662 U32 n;
663 for (totalTestSize=0, cSize=0, n=0 ; n<nbChunks ; n++) {
664 size_t const segmentSize = FUZ_randomLength(&lseed, maxSampleLog);
665 size_t const segmentStart = FUZ_rand(&lseed) % (srcBufferSize - segmentSize);
Yann Collet417890c2015-12-04 17:16:37 +0100666
Yann Colletd2858e92016-05-30 15:10:09 +0200667 if (cBufferSize-cSize < ZSTD_compressBound(segmentSize)) break; /* avoid invalid dstBufferTooSmall */
668 if (totalTestSize+segmentSize > maxTestSize) break;
Yann Collet417890c2015-12-04 17:16:37 +0100669
Yann Colletd2858e92016-05-30 15:10:09 +0200670 { size_t const compressResult = ZSTD_compressContinue(ctx, cBuffer+cSize, cBufferSize-cSize, srcBuffer+segmentStart, segmentSize);
671 CHECK (ZSTD_isError(compressResult), "multi-segments compression error : %s", ZSTD_getErrorName(compressResult));
672 cSize += compressResult;
673 }
674 XXH64_update(&xxhState, srcBuffer+segmentStart, segmentSize);
675 memcpy(mirrorBuffer + totalTestSize, srcBuffer+segmentStart, segmentSize);
676 totalTestSize += segmentSize;
677 } }
678
Yann Collet1fce6e02016-04-08 20:26:33 +0200679 { size_t const flushResult = ZSTD_compressEnd(ctx, cBuffer+cSize, cBufferSize-cSize);
680 CHECK (ZSTD_isError(flushResult), "multi-segments epilogue error : %s", ZSTD_getErrorName(flushResult));
681 cSize += flushResult;
682 }
Yann Collet6c903a82016-05-28 13:34:07 +0200683 crcOrig = XXH64_digest(&xxhState);
Yann Collete47c4e52015-12-05 09:23:53 +0100684
685 /* streaming decompression test */
Yann Collet33341de2016-05-29 23:09:51 +0200686 if (dictSize<8) dictSize=0, dict=NULL; /* disable dictionary */
Yann Collet1fce6e02016-04-08 20:26:33 +0200687 { size_t const errorCode = ZSTD_decompressBegin_usingDict(dctx, dict, dictSize);
Yann Collet30009522016-05-30 16:17:33 +0200688 CHECK (ZSTD_isError(errorCode), "ZSTD_decompressBegin_usingDict error : %s", ZSTD_getErrorName(errorCode)); }
Yann Collete47c4e52015-12-05 09:23:53 +0100689 totalCSize = 0;
690 totalGenSize = 0;
Yann Colletd1d210f2016-03-19 12:12:07 +0100691 while (totalCSize < cSize) {
Yann Collet1fce6e02016-04-08 20:26:33 +0200692 size_t const inSize = ZSTD_nextSrcSizeToDecompress(dctx);
693 size_t const genSize = ZSTD_decompressContinue(dctx, dstBuffer+totalGenSize, dstBufferSize-totalGenSize, cBuffer+totalCSize, inSize);
Yann Collete47c4e52015-12-05 09:23:53 +0100694 CHECK (ZSTD_isError(genSize), "streaming decompression error : %s", ZSTD_getErrorName(genSize));
695 totalGenSize += genSize;
696 totalCSize += inSize;
697 }
698 CHECK (ZSTD_nextSrcSizeToDecompress(dctx) != 0, "frame not fully decoded");
Yann Colletc0a9bf32016-05-30 01:56:08 +0200699 CHECK (totalGenSize != totalTestSize, "streaming decompressed data : wrong size")
Yann Collete47c4e52015-12-05 09:23:53 +0100700 CHECK (totalCSize != cSize, "compressed data should be fully read")
Yann Collet1fce6e02016-04-08 20:26:33 +0200701 { U64 const crcDest = XXH64(dstBuffer, totalTestSize, 0);
702 if (crcDest!=crcOrig) {
703 size_t const errorPos = findDiff(mirrorBuffer, dstBuffer, totalTestSize);
Yann Colletd2858e92016-05-30 15:10:09 +0200704 CHECK (1, "streaming decompressed data corrupted : byte %u / %u (%02X!=%02X)",
Yann Collet1fce6e02016-04-08 20:26:33 +0200705 (U32)errorPos, (U32)totalTestSize, dstBuffer[errorPos], mirrorBuffer[errorPos]);
706 } }
707 } /* for ( ; (testNb <= nbTests) */
Yann Collet1c2ddba2015-12-04 17:45:35 +0100708 DISPLAY("\r%u fuzzer tests completed \n", testNb-1);
Yann Collet4856a002015-01-24 01:58:16 +0100709
710_cleanup:
Yann Colletecd651b2016-01-07 15:35:18 +0100711 ZSTD_freeCCtx(refCtx);
Yann Collet2f648e52015-10-29 18:23:38 +0100712 ZSTD_freeCCtx(ctx);
Yann Collete47c4e52015-12-05 09:23:53 +0100713 ZSTD_freeDCtx(dctx);
Yann Colletd5d9bc32015-08-23 23:13:49 +0100714 free(cNoiseBuffer[0]);
715 free(cNoiseBuffer[1]);
716 free(cNoiseBuffer[2]);
717 free(cNoiseBuffer[3]);
718 free(cNoiseBuffer[4]);
Yann Collet4856a002015-01-24 01:58:16 +0100719 free(cBuffer);
720 free(dstBuffer);
Yann Collete47c4e52015-12-05 09:23:53 +0100721 free(mirrorBuffer);
Yann Collet4856a002015-01-24 01:58:16 +0100722 return result;
723
724_output_error:
725 result = 1;
726 goto _cleanup;
727}
728
729
Yann Colletd1d210f2016-03-19 12:12:07 +0100730/*_*******************************************************
Yann Collet4856a002015-01-24 01:58:16 +0100731* Command line
732*********************************************************/
Yann Colletd1d210f2016-03-19 12:12:07 +0100733int FUZ_usage(const char* programName)
Yann Collet4856a002015-01-24 01:58:16 +0100734{
735 DISPLAY( "Usage :\n");
736 DISPLAY( " %s [args]\n", programName);
737 DISPLAY( "\n");
738 DISPLAY( "Arguments :\n");
739 DISPLAY( " -i# : Nb of tests (default:%u) \n", nbTestsDefault);
740 DISPLAY( " -s# : Select seed (default:prompt user)\n");
741 DISPLAY( " -t# : Select starting test number (default:0)\n");
Yann Collet0d9ce042016-03-19 13:21:08 +0100742 DISPLAY( " -P# : Select compressibility in %% (default:%u%%)\n", FUZ_compressibility_default);
Yann Collet4856a002015-01-24 01:58:16 +0100743 DISPLAY( " -v : verbose\n");
Yann Collete9853b22015-08-07 19:07:32 +0100744 DISPLAY( " -p : pause at the end\n");
Yann Collet4856a002015-01-24 01:58:16 +0100745 DISPLAY( " -h : display help and exit\n");
746 return 0;
747}
748
749
Yann Colletd1d210f2016-03-19 12:12:07 +0100750int main(int argc, const char** argv)
Yann Collet4856a002015-01-24 01:58:16 +0100751{
752 U32 seed=0;
753 int seedset=0;
754 int argNb;
755 int nbTests = nbTestsDefault;
756 int testNb = 0;
Yann Collet0d9ce042016-03-19 13:21:08 +0100757 U32 proba = FUZ_compressibility_default;
Yann Collet4856a002015-01-24 01:58:16 +0100758 int result=0;
759 U32 mainPause = 0;
Yann Collet0d9ce042016-03-19 13:21:08 +0100760 U32 maxDuration = 0;
Yann Colletea63bb72016-04-08 15:25:32 +0200761 const char* programName = argv[0];
Yann Collet4856a002015-01-24 01:58:16 +0100762
763 /* Check command line */
Yann Colletd1d210f2016-03-19 12:12:07 +0100764 for (argNb=1; argNb<argc; argNb++) {
765 const char* argument = argv[argNb];
Yann Collet4856a002015-01-24 01:58:16 +0100766 if(!argument) continue; /* Protection if argument empty */
767
768 /* Handle commands. Aggregated commands are allowed */
Yann Colletd1d210f2016-03-19 12:12:07 +0100769 if (argument[0]=='-') {
Yann Collet4856a002015-01-24 01:58:16 +0100770 argument++;
Yann Colletd1d210f2016-03-19 12:12:07 +0100771 while (*argument!=0) {
Yann Collet4856a002015-01-24 01:58:16 +0100772 switch(*argument)
773 {
774 case 'h':
775 return FUZ_usage(programName);
776 case 'v':
777 argument++;
778 g_displayLevel=4;
779 break;
780 case 'q':
781 argument++;
782 g_displayLevel--;
783 break;
784 case 'p': /* pause at the end */
785 argument++;
786 mainPause = 1;
787 break;
788
789 case 'i':
Yann Collet0d9ce042016-03-19 13:21:08 +0100790 argument++; maxDuration=0;
Yann Collet4856a002015-01-24 01:58:16 +0100791 nbTests=0;
Yann Colletd1d210f2016-03-19 12:12:07 +0100792 while ((*argument>='0') && (*argument<='9')) {
Yann Collet4856a002015-01-24 01:58:16 +0100793 nbTests *= 10;
794 nbTests += *argument - '0';
795 argument++;
796 }
797 break;
798
Yann Collet553cf6a2015-12-04 17:25:26 +0100799 case 'T':
800 argument++;
Yann Collet0d9ce042016-03-19 13:21:08 +0100801 nbTests=0; maxDuration=0;
Yann Colletd1d210f2016-03-19 12:12:07 +0100802 while ((*argument>='0') && (*argument<='9')) {
Yann Collet0d9ce042016-03-19 13:21:08 +0100803 maxDuration *= 10;
804 maxDuration += *argument - '0';
Yann Collet553cf6a2015-12-04 17:25:26 +0100805 argument++;
806 }
Yann Collet0d9ce042016-03-19 13:21:08 +0100807 if (*argument=='m') maxDuration *=60, argument++;
Yann Collet553cf6a2015-12-04 17:25:26 +0100808 if (*argument=='n') argument++;
Yann Collet553cf6a2015-12-04 17:25:26 +0100809 break;
810
Yann Collet4856a002015-01-24 01:58:16 +0100811 case 's':
812 argument++;
813 seed=0;
814 seedset=1;
Yann Colletd1d210f2016-03-19 12:12:07 +0100815 while ((*argument>='0') && (*argument<='9')) {
Yann Collet4856a002015-01-24 01:58:16 +0100816 seed *= 10;
817 seed += *argument - '0';
818 argument++;
819 }
820 break;
821
822 case 't':
823 argument++;
824 testNb=0;
Yann Colletd1d210f2016-03-19 12:12:07 +0100825 while ((*argument>='0') && (*argument<='9')) {
Yann Collet4856a002015-01-24 01:58:16 +0100826 testNb *= 10;
827 testNb += *argument - '0';
828 argument++;
829 }
830 break;
831
832 case 'P': /* compressibility % */
833 argument++;
834 proba=0;
Yann Colletd1d210f2016-03-19 12:12:07 +0100835 while ((*argument>='0') && (*argument<='9')) {
Yann Collet4856a002015-01-24 01:58:16 +0100836 proba *= 10;
837 proba += *argument - '0';
838 argument++;
839 }
Yann Collet4856a002015-01-24 01:58:16 +0100840 if (proba>100) proba=100;
841 break;
842
843 default:
844 return FUZ_usage(programName);
Yann Colletd1d210f2016-03-19 12:12:07 +0100845 } } } } /* for (argNb=1; argNb<argc; argNb++) */
Yann Collet4856a002015-01-24 01:58:16 +0100846
847 /* Get Seed */
Yann Collet45f84ab2016-05-20 12:34:40 +0200848 DISPLAY("Starting zstd tester (%i-bits, %s)\n", (int)(sizeof(size_t)*8), ZSTD_VERSION_STRING);
Yann Collet4856a002015-01-24 01:58:16 +0100849
Yann Colletea63bb72016-04-08 15:25:32 +0200850 if (!seedset) seed = (U32)(clock() % 10000);
Yann Collet4856a002015-01-24 01:58:16 +0100851 DISPLAY("Seed = %u\n", seed);
Yann Collet0d9ce042016-03-19 13:21:08 +0100852 if (proba!=FUZ_compressibility_default) DISPLAY("Compressibility : %u%%\n", proba);
Yann Collet4856a002015-01-24 01:58:16 +0100853
Yann Colletd1d210f2016-03-19 12:12:07 +0100854 if (testNb==0)
855 result = basicUnitTests(0, ((double)proba) / 100); /* constant seed for predictability */
Yann Collet4856a002015-01-24 01:58:16 +0100856 if (!result)
Yann Collet0d9ce042016-03-19 13:21:08 +0100857 result = fuzzerTests(seed, nbTests, testNb, maxDuration, ((double)proba) / 100);
Yann Colletd1d210f2016-03-19 12:12:07 +0100858 if (mainPause) {
Yann Colletb5e06dc2015-07-04 23:20:56 -0800859 int unused;
Yann Collet4856a002015-01-24 01:58:16 +0100860 DISPLAY("Press Enter \n");
Yann Colletb5e06dc2015-07-04 23:20:56 -0800861 unused = getchar();
862 (void)unused;
Yann Collet4856a002015-01-24 01:58:16 +0100863 }
864 return result;
865}