blob: 86d4c6bebb359f04b8e45a4978fc7d248d3c8952 [file] [log] [blame]
Yann Collet4ded9e52016-08-30 10:04:33 -07001/**
2 * Copyright (c) 2016-present, Yann Collet, Facebook, Inc.
3 * All rights reserved.
4 *
5 * This source code is licensed under the BSD-style license found in the
6 * LICENSE file in the root directory of this source tree. An additional grant
7 * of patent rights can be found in the PATENTS file in the same directory.
8 */
Yann Collet4856a002015-01-24 01:58:16 +01009
Yann Collet4856a002015-01-24 01:58:16 +010010
Yann Collet0d9ce042016-03-19 13:21:08 +010011/*-************************************
Yann Collet4856a002015-01-24 01:58:16 +010012* Compiler specific
13**************************************/
14#ifdef _MSC_VER /* Visual Studio */
Przemyslaw Skibinski97a258d2016-12-21 14:00:41 +010015# define _CRT_SECURE_NO_WARNINGS /* fgets */
Przemyslaw Skibinski2f6ccee2016-12-21 13:23:34 +010016# pragma warning(disable : 4127) /* disable: C4127: conditional expression is constant */
cyanb8806312016-05-30 18:20:46 +020017# pragma warning(disable : 4204) /* disable: C4204: non-constant aggregate initializer */
Yann Collet4856a002015-01-24 01:58:16 +010018#endif
19
Yann Collet4856a002015-01-24 01:58:16 +010020
Yann Collet0d9ce042016-03-19 13:21:08 +010021/*-************************************
Yann Collet4856a002015-01-24 01:58:16 +010022* Includes
23**************************************/
Yann Collet6fa05a22016-07-20 14:58:49 +020024#include <stdlib.h> /* free */
25#include <stdio.h> /* fgets, sscanf */
Yann Collet6fa05a22016-07-20 14:58:49 +020026#include <string.h> /* strcmp */
27#include <time.h> /* clock_t */
Yann Colletd4f4e582016-06-27 01:31:35 +020028#define ZSTD_STATIC_LINKING_ONLY /* ZSTD_compressContinue, ZSTD_compressBlock */
Yann Collet6fa05a22016-07-20 14:58:49 +020029#include "zstd.h" /* ZSTD_VERSION_STRING */
Yann Collete7a41a52016-12-05 16:21:06 -080030#include "zstd_errors.h" /* ZSTD_getErrorCode */
Yann Collet6fa05a22016-07-20 14:58:49 +020031#include "zdict.h" /* ZDICT_trainFromBuffer */
32#include "datagen.h" /* RDG_genBuffer */
Przemyslaw Skibinski2f6ccee2016-12-21 13:23:34 +010033#include "mem.h"
Yann Collet6c903a82016-05-28 13:34:07 +020034#define XXH_STATIC_LINKING_ONLY
Yann Collet6fa05a22016-07-20 14:58:49 +020035#include "xxhash.h" /* XXH64 */
Yann Collet4856a002015-01-24 01:58:16 +010036
37
Yann Collet0d9ce042016-03-19 13:21:08 +010038/*-************************************
39* Constants
Yann Collet4856a002015-01-24 01:58:16 +010040**************************************/
Yann Collet4856a002015-01-24 01:58:16 +010041#define KB *(1U<<10)
42#define MB *(1U<<20)
43#define GB *(1U<<30)
44
Yann Collet0d9ce042016-03-19 13:21:08 +010045static const U32 FUZ_compressibility_default = 50;
Yann Collet110cc142015-11-19 12:02:28 +010046static const U32 nbTestsDefault = 30000;
Yann Collet4856a002015-01-24 01:58:16 +010047
48
Yann Collet0d9ce042016-03-19 13:21:08 +010049/*-************************************
Yann Collet4856a002015-01-24 01:58:16 +010050* Display Macros
51**************************************/
52#define DISPLAY(...) fprintf(stderr, __VA_ARGS__)
53#define DISPLAYLEVEL(l, ...) if (g_displayLevel>=l) { DISPLAY(__VA_ARGS__); }
54static U32 g_displayLevel = 2;
55
56#define DISPLAYUPDATE(l, ...) if (g_displayLevel>=l) { \
Yann Colletea63bb72016-04-08 15:25:32 +020057 if ((FUZ_clockSpan(g_displayClock) > g_refreshRate) || (g_displayLevel>=4)) \
58 { g_displayClock = clock(); DISPLAY(__VA_ARGS__); \
Yann Collet4856a002015-01-24 01:58:16 +010059 if (g_displayLevel>=4) fflush(stdout); } }
Yann Collet64deef32016-09-14 00:16:07 +020060static const clock_t g_refreshRate = CLOCKS_PER_SEC / 6;
Yann Colletea63bb72016-04-08 15:25:32 +020061static clock_t g_displayClock = 0;
Yann Collet553cf6a2015-12-04 17:25:26 +010062
Yann Collet4856a002015-01-24 01:58:16 +010063
Yann Collet0d9ce042016-03-19 13:21:08 +010064/*-*******************************************************
Yann Collet4856a002015-01-24 01:58:16 +010065* Fuzzer functions
66*********************************************************/
Yann Collete93add02016-02-15 17:44:14 +010067#define MIN(a,b) ((a)<(b)?(a):(b))
Yann Collet110cc142015-11-19 12:02:28 +010068
Yann Colletea63bb72016-04-08 15:25:32 +020069static clock_t FUZ_clockSpan(clock_t cStart)
Yann Collet4856a002015-01-24 01:58:16 +010070{
Yann Colletea63bb72016-04-08 15:25:32 +020071 return clock() - cStart; /* works even when overflow; max span ~ 30mn */
Yann Collet4856a002015-01-24 01:58:16 +010072}
73
74
Yann Colletc0a9bf32016-05-30 01:56:08 +020075#define FUZ_rotl32(x,r) ((x << r) | (x >> (32 - r)))
76static unsigned FUZ_rand(unsigned* src)
Yann Collet4856a002015-01-24 01:58:16 +010077{
Yann Collet0d9ce042016-03-19 13:21:08 +010078 static const U32 prime1 = 2654435761U;
79 static const U32 prime2 = 2246822519U;
Yann Collet4856a002015-01-24 01:58:16 +010080 U32 rand32 = *src;
81 rand32 *= prime1;
82 rand32 += prime2;
83 rand32 = FUZ_rotl32(rand32, 13);
84 *src = rand32;
85 return rand32 >> 5;
86}
87
Yann Collet997f9ee2015-08-21 02:44:20 +010088static unsigned FUZ_highbit32(U32 v32)
Yann Collet4856a002015-01-24 01:58:16 +010089{
90 unsigned nbBits = 0;
91 if (v32==0) return 0;
Yann Colletc0a9bf32016-05-30 01:56:08 +020092 while (v32) v32 >>= 1, nbBits++;
Yann Collet4856a002015-01-24 01:58:16 +010093 return nbBits;
94}
Yann Collet4856a002015-01-24 01:58:16 +010095
96
Yann Colletcb327632016-08-23 00:30:31 +020097/*=============================================
98* Basic Unit tests
99=============================================*/
100
Yann Colletd4f4e582016-06-27 01:31:35 +0200101#define CHECK_V(var, fn) size_t const var = fn; if (ZSTD_isError(var)) goto _output_error
102#define CHECK(fn) { CHECK_V(err, fn); }
103#define CHECKPLUS(var, fn, more) { CHECK_V(var, fn); more; }
Yann Collet4856a002015-01-24 01:58:16 +0100104static int basicUnitTests(U32 seed, double compressibility)
105{
Yann Collet30009522016-05-30 16:17:33 +0200106 size_t const CNBuffSize = 5 MB;
Yann Colletd2858e92016-05-30 15:10:09 +0200107 void* const CNBuffer = malloc(CNBuffSize);
108 void* const compressedBuffer = malloc(ZSTD_compressBound(CNBuffSize));
109 void* const decodedBuffer = malloc(CNBuffSize);
Yann Colletc0a9bf32016-05-30 01:56:08 +0200110 int testResult = 0;
Yann Collet4856a002015-01-24 01:58:16 +0100111 U32 testNb=0;
Yann Colletc0a9bf32016-05-30 01:56:08 +0200112 size_t cSize;
Yann Collet4856a002015-01-24 01:58:16 +0100113
Yann Colletc0a9bf32016-05-30 01:56:08 +0200114 /* Create compressible noise */
Yann Colletd1d210f2016-03-19 12:12:07 +0100115 if (!CNBuffer || !compressedBuffer || !decodedBuffer) {
Yann Collet94f998b2015-07-04 23:10:40 -0800116 DISPLAY("Not enough memory, aborting\n");
117 testResult = 1;
118 goto _end;
119 }
Yann Colletd2858e92016-05-30 15:10:09 +0200120 RDG_genBuffer(CNBuffer, CNBuffSize, compressibility, 0., seed);
Yann Collet4856a002015-01-24 01:58:16 +0100121
Yann Colletd5d9bc32015-08-23 23:13:49 +0100122 /* Basic tests */
Yann Collet9a69ec42016-08-01 16:25:58 +0200123 DISPLAYLEVEL(4, "test%3i : ZSTD_getErrorName : ", testNb++);
124 { const char* errorString = ZSTD_getErrorName(0);
125 DISPLAYLEVEL(4, "OK : %s \n", errorString);
126 }
127
128 DISPLAYLEVEL(4, "test%3i : ZSTD_getErrorName with wrong value : ", testNb++);
129 { const char* errorString = ZSTD_getErrorName(499);
130 DISPLAYLEVEL(4, "OK : %s \n", errorString);
131 }
132
Yann Colletd2858e92016-05-30 15:10:09 +0200133 DISPLAYLEVEL(4, "test%3i : compress %u bytes : ", testNb++, (U32)CNBuffSize);
134 CHECKPLUS(r, ZSTD_compress(compressedBuffer, ZSTD_compressBound(CNBuffSize),
135 CNBuffer, CNBuffSize, 1),
Yann Colletc0a9bf32016-05-30 01:56:08 +0200136 cSize=r );
Yann Colletd2858e92016-05-30 15:10:09 +0200137 DISPLAYLEVEL(4, "OK (%u bytes : %.2f%%)\n", (U32)cSize, (double)cSize/CNBuffSize*100);
Yann Collet4856a002015-01-24 01:58:16 +0100138
Yann Colletf323bf72016-07-07 13:14:21 +0200139 DISPLAYLEVEL(4, "test%3i : decompressed size test : ", testNb++);
140 { unsigned long long const rSize = ZSTD_getDecompressedSize(compressedBuffer, cSize);
141 if (rSize != CNBuffSize) goto _output_error;
142 }
143 DISPLAYLEVEL(4, "OK \n");
144
Yann Colletd2858e92016-05-30 15:10:09 +0200145 DISPLAYLEVEL(4, "test%3i : decompress %u bytes : ", testNb++, (U32)CNBuffSize);
Yann Colletc991cc12016-07-28 00:55:43 +0200146 { size_t const r = ZSTD_decompress(decodedBuffer, CNBuffSize, compressedBuffer, cSize);
147 if (r != CNBuffSize) goto _output_error; }
Yann Collet4856a002015-01-24 01:58:16 +0100148 DISPLAYLEVEL(4, "OK \n");
149
Yann Colletc0a9bf32016-05-30 01:56:08 +0200150 DISPLAYLEVEL(4, "test%3i : check decompressed result : ", testNb++);
151 { size_t u;
Yann Colletd2858e92016-05-30 15:10:09 +0200152 for (u=0; u<CNBuffSize; u++) {
Yann Colletc0a9bf32016-05-30 01:56:08 +0200153 if (((BYTE*)decodedBuffer)[u] != ((BYTE*)CNBuffer)[u]) goto _output_error;;
154 } }
155 DISPLAYLEVEL(4, "OK \n");
Yann Collet4856a002015-01-24 01:58:16 +0100156
157 DISPLAYLEVEL(4, "test%3i : decompress with 1 missing byte : ", testNb++);
Yann Colletd2858e92016-05-30 15:10:09 +0200158 { size_t const r = ZSTD_decompress(decodedBuffer, CNBuffSize, compressedBuffer, cSize-1);
Yann Colletc0a9bf32016-05-30 01:56:08 +0200159 if (!ZSTD_isError(r)) goto _output_error;
160 if (ZSTD_getErrorCode((size_t)r) != ZSTD_error_srcSize_wrong) goto _output_error; }
Yann Collet4856a002015-01-24 01:58:16 +0100161 DISPLAYLEVEL(4, "OK \n");
162
163 DISPLAYLEVEL(4, "test%3i : decompress with 1 too much byte : ", testNb++);
Yann Colletd2858e92016-05-30 15:10:09 +0200164 { size_t const r = ZSTD_decompress(decodedBuffer, CNBuffSize, compressedBuffer, cSize+1);
Yann Colletc0a9bf32016-05-30 01:56:08 +0200165 if (!ZSTD_isError(r)) goto _output_error;
166 if (ZSTD_getErrorCode(r) != ZSTD_error_srcSize_wrong) goto _output_error; }
Yann Collet4856a002015-01-24 01:58:16 +0100167 DISPLAYLEVEL(4, "OK \n");
168
Yann Collet389648c2016-04-12 19:13:08 +0200169 /* Dictionary and CCtx Duplication tests */
Yann Colletc0a9bf32016-05-30 01:56:08 +0200170 { ZSTD_CCtx* const ctxOrig = ZSTD_createCCtx();
171 ZSTD_CCtx* const ctxDuplicated = ZSTD_createCCtx();
172 ZSTD_DCtx* const dctx = ZSTD_createDCtx();
173 static const size_t dictSize = 551;
Yann Collet60096272016-01-08 17:27:50 +0100174
Yann Collet887e7da2016-04-11 20:12:27 +0200175 DISPLAYLEVEL(4, "test%3i : copy context too soon : ", testNb++);
Yann Collet97b378a2016-09-21 17:20:19 +0200176 { size_t const copyResult = ZSTD_copyCCtx(ctxDuplicated, ctxOrig, 0);
Yann Colletc0a9bf32016-05-30 01:56:08 +0200177 if (!ZSTD_isError(copyResult)) goto _output_error; } /* error must be detected */
Yann Collet887e7da2016-04-11 20:12:27 +0200178 DISPLAYLEVEL(4, "OK \n");
179
Yann Collet60096272016-01-08 17:27:50 +0100180 DISPLAYLEVEL(4, "test%3i : load dictionary into context : ", testNb++);
Yann Colletc0a9bf32016-05-30 01:56:08 +0200181 CHECK( ZSTD_compressBegin_usingDict(ctxOrig, CNBuffer, dictSize, 2) );
Yann Collet97b378a2016-09-21 17:20:19 +0200182 CHECK( ZSTD_copyCCtx(ctxDuplicated, ctxOrig, CNBuffSize - dictSize) );
Yann Collet60096272016-01-08 17:27:50 +0100183 DISPLAYLEVEL(4, "OK \n");
184
Yann Collet30009522016-05-30 16:17:33 +0200185 DISPLAYLEVEL(4, "test%3i : compress with flat dictionary : ", testNb++);
Yann Collet60096272016-01-08 17:27:50 +0100186 cSize = 0;
Yann Collet62470b42016-07-28 15:29:08 +0200187 CHECKPLUS(r, ZSTD_compressEnd(ctxOrig, compressedBuffer, ZSTD_compressBound(CNBuffSize),
Yann Colletd2858e92016-05-30 15:10:09 +0200188 (const char*)CNBuffer + dictSize, CNBuffSize - dictSize),
Yann Colletc0a9bf32016-05-30 01:56:08 +0200189 cSize += r);
Yann Colletd2858e92016-05-30 15:10:09 +0200190 DISPLAYLEVEL(4, "OK (%u bytes : %.2f%%)\n", (U32)cSize, (double)cSize/CNBuffSize*100);
Yann Collet60096272016-01-08 17:27:50 +0100191
Yann Collet30009522016-05-30 16:17:33 +0200192 DISPLAYLEVEL(4, "test%3i : frame built with flat dictionary should be decompressible : ", testNb++);
Yann Colletc0a9bf32016-05-30 01:56:08 +0200193 CHECKPLUS(r, ZSTD_decompress_usingDict(dctx,
Yann Colletd2858e92016-05-30 15:10:09 +0200194 decodedBuffer, CNBuffSize,
Yann Colletc0a9bf32016-05-30 01:56:08 +0200195 compressedBuffer, cSize,
196 CNBuffer, dictSize),
Yann Colletd2858e92016-05-30 15:10:09 +0200197 if (r != CNBuffSize - dictSize) goto _output_error);
Yann Collet60096272016-01-08 17:27:50 +0100198 DISPLAYLEVEL(4, "OK \n");
199
200 DISPLAYLEVEL(4, "test%3i : compress with duplicated context : ", testNb++);
Yann Collet389648c2016-04-12 19:13:08 +0200201 { size_t const cSizeOrig = cSize;
202 cSize = 0;
Yann Collet62470b42016-07-28 15:29:08 +0200203 CHECKPLUS(r, ZSTD_compressEnd(ctxDuplicated, compressedBuffer, ZSTD_compressBound(CNBuffSize),
Yann Colletd2858e92016-05-30 15:10:09 +0200204 (const char*)CNBuffer + dictSize, CNBuffSize - dictSize),
Yann Colletc0a9bf32016-05-30 01:56:08 +0200205 cSize += r);
Yann Collet227cc392016-07-15 11:27:09 +0200206 if (cSize != cSizeOrig) goto _output_error; /* should be identical ==> same size */
Yann Collet389648c2016-04-12 19:13:08 +0200207 }
Yann Colletd2858e92016-05-30 15:10:09 +0200208 DISPLAYLEVEL(4, "OK (%u bytes : %.2f%%)\n", (U32)cSize, (double)cSize/CNBuffSize*100);
Yann Collet60096272016-01-08 17:27:50 +0100209
210 DISPLAYLEVEL(4, "test%3i : frame built with duplicated context should be decompressible : ", testNb++);
Yann Colletc0a9bf32016-05-30 01:56:08 +0200211 CHECKPLUS(r, ZSTD_decompress_usingDict(dctx,
Yann Colletd2858e92016-05-30 15:10:09 +0200212 decodedBuffer, CNBuffSize,
Yann Collet60096272016-01-08 17:27:50 +0100213 compressedBuffer, cSize,
Yann Colletc0a9bf32016-05-30 01:56:08 +0200214 CNBuffer, dictSize),
Yann Colletd2858e92016-05-30 15:10:09 +0200215 if (r != CNBuffSize - dictSize) goto _output_error);
Yann Collet60096272016-01-08 17:27:50 +0100216 DISPLAYLEVEL(4, "OK \n");
Yann Collet541dc7c2016-04-12 18:00:20 +0200217
218 DISPLAYLEVEL(4, "test%3i : check content size on duplicated context : ", testNb++);
Yann Colletd2858e92016-05-30 15:10:09 +0200219 { size_t const testSize = CNBuffSize / 3;
Yann Collet6c6e1752016-06-27 15:28:45 +0200220 { ZSTD_parameters p = ZSTD_getParams(2, testSize, dictSize);
221 p.fParams.contentSizeFlag = 1;
Yann Colletd2858e92016-05-30 15:10:09 +0200222 CHECK( ZSTD_compressBegin_advanced(ctxOrig, CNBuffer, dictSize, p, testSize-1) );
Yann Collet33341de2016-05-29 23:09:51 +0200223 }
Yann Collet97b378a2016-09-21 17:20:19 +0200224 CHECK( ZSTD_copyCCtx(ctxDuplicated, ctxOrig, testSize) );
Yann Colletc0a9bf32016-05-30 01:56:08 +0200225
Yann Collet97b378a2016-09-21 17:20:19 +0200226 CHECKPLUS(r, ZSTD_compressEnd(ctxDuplicated, compressedBuffer, ZSTD_compressBound(testSize),
227 (const char*)CNBuffer + dictSize, testSize),
Yann Colletc0a9bf32016-05-30 01:56:08 +0200228 cSize = r);
Yann Collet541dc7c2016-04-12 18:00:20 +0200229 { ZSTD_frameParams fp;
Yann Collet33341de2016-05-29 23:09:51 +0200230 if (ZSTD_getFrameParams(&fp, compressedBuffer, cSize)) goto _output_error;
Yann Collet541dc7c2016-04-12 18:00:20 +0200231 if ((fp.frameContentSize != testSize) && (fp.frameContentSize != 0)) goto _output_error;
232 } }
233 DISPLAYLEVEL(4, "OK \n");
234
235 ZSTD_freeCCtx(ctxOrig);
236 ZSTD_freeCCtx(ctxDuplicated);
237 ZSTD_freeDCtx(dctx);
Yann Collet60096272016-01-08 17:27:50 +0100238 }
239
Yann Collet30009522016-05-30 16:17:33 +0200240 /* Dictionary and dictBuilder tests */
241 { ZSTD_CCtx* const cctx = ZSTD_createCCtx();
242 ZSTD_DCtx* const dctx = ZSTD_createDCtx();
243 size_t dictSize = 16 KB;
244 void* dictBuffer = malloc(dictSize);
245 size_t const totalSampleSize = 1 MB;
246 size_t const sampleUnitSize = 8 KB;
Yann Colletb81cbba2016-05-30 22:29:45 +0200247 U32 const nbSamples = (U32)(totalSampleSize / sampleUnitSize);
Yann Collet30009522016-05-30 16:17:33 +0200248 size_t* const samplesSizes = (size_t*) malloc(nbSamples * sizeof(size_t));
Yann Colletf586bdf2016-12-06 06:11:46 +0100249 U32 dictID;
Yann Collet30009522016-05-30 16:17:33 +0200250
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
Yann Colletda3fbcb2016-08-19 14:23:58 +0200264 DISPLAYLEVEL(4, "test%3i : check dictID : ", testNb++);
Yann Colletf586bdf2016-12-06 06:11:46 +0100265 dictID = ZDICT_getDictID(dictBuffer, dictSize);
266 if (dictID==0) goto _output_error;
267 DISPLAYLEVEL(4, "OK : %u \n", dictID);
Yann Colletda3fbcb2016-08-19 14:23:58 +0200268
Yann Collet30009522016-05-30 16:17:33 +0200269 DISPLAYLEVEL(4, "test%3i : compress with dictionary : ", testNb++);
270 cSize = ZSTD_compress_usingDict(cctx, compressedBuffer, ZSTD_compressBound(CNBuffSize),
271 CNBuffer, CNBuffSize,
272 dictBuffer, dictSize, 4);
273 if (ZSTD_isError(cSize)) goto _output_error;
274 DISPLAYLEVEL(4, "OK (%u bytes : %.2f%%)\n", (U32)cSize, (double)cSize/CNBuffSize*100);
275
Yann Collete7a41a52016-12-05 16:21:06 -0800276 DISPLAYLEVEL(4, "test%3i : retrieve dictID from dictionary : ", testNb++);
Yann Colletf586bdf2016-12-06 06:11:46 +0100277 { U32 const did = ZSTD_getDictID_fromDict(dictBuffer, dictSize);
278 if (did != dictID) goto _output_error; /* non-conformant (content-only) dictionary */
Yann Collete7a41a52016-12-05 16:21:06 -0800279 }
280 DISPLAYLEVEL(4, "OK \n");
281
282 DISPLAYLEVEL(4, "test%3i : retrieve dictID from frame : ", testNb++);
Yann Colletf586bdf2016-12-06 06:11:46 +0100283 { U32 const did = ZSTD_getDictID_fromFrame(compressedBuffer, cSize);
284 if (did != dictID) goto _output_error; /* non-conformant (content-only) dictionary */
Yann Collete7a41a52016-12-05 16:21:06 -0800285 }
286 DISPLAYLEVEL(4, "OK \n");
287
Yann Collet30009522016-05-30 16:17:33 +0200288 DISPLAYLEVEL(4, "test%3i : frame built with dictionary should be decompressible : ", testNb++);
289 CHECKPLUS(r, ZSTD_decompress_usingDict(dctx,
290 decodedBuffer, CNBuffSize,
291 compressedBuffer, cSize,
292 dictBuffer, dictSize),
293 if (r != CNBuffSize) goto _output_error);
294 DISPLAYLEVEL(4, "OK \n");
295
296 DISPLAYLEVEL(4, "test%3i : compress without dictID : ", testNb++);
Yann Collet6c6e1752016-06-27 15:28:45 +0200297 { ZSTD_parameters p = ZSTD_getParams(3, CNBuffSize, dictSize);
298 p.fParams.noDictIDFlag = 1;
Yann Collet30009522016-05-30 16:17:33 +0200299 cSize = ZSTD_compress_advanced(cctx, compressedBuffer, ZSTD_compressBound(CNBuffSize),
300 CNBuffer, CNBuffSize,
301 dictBuffer, dictSize, p);
302 if (ZSTD_isError(cSize)) goto _output_error;
303 }
304 DISPLAYLEVEL(4, "OK (%u bytes : %.2f%%)\n", (U32)cSize, (double)cSize/CNBuffSize*100);
305
306 DISPLAYLEVEL(4, "test%3i : frame built without dictID should be decompressible : ", testNb++);
307 CHECKPLUS(r, ZSTD_decompress_usingDict(dctx,
308 decodedBuffer, CNBuffSize,
309 compressedBuffer, cSize,
310 dictBuffer, dictSize),
311 if (r != CNBuffSize) goto _output_error);
312 DISPLAYLEVEL(4, "OK \n");
313
314 ZSTD_freeCCtx(cctx);
315 ZSTD_freeDCtx(dctx);
316 free(dictBuffer);
317 free(samplesSizes);
318 }
319
Yann Collet4856a002015-01-24 01:58:16 +0100320 /* Decompression defense tests */
321 DISPLAYLEVEL(4, "test%3i : Check input length for magic number : ", testNb++);
Yann Colletd2858e92016-05-30 15:10:09 +0200322 { size_t const r = ZSTD_decompress(decodedBuffer, CNBuffSize, CNBuffer, 3);
Yann Colletc0a9bf32016-05-30 01:56:08 +0200323 if (!ZSTD_isError(r)) goto _output_error;
324 if (r != (size_t)-ZSTD_error_srcSize_wrong) goto _output_error; }
Yann Collet4856a002015-01-24 01:58:16 +0100325 DISPLAYLEVEL(4, "OK \n");
326
327 DISPLAYLEVEL(4, "test%3i : Check magic Number : ", testNb++);
328 ((char*)(CNBuffer))[0] = 1;
Yann Colletd2858e92016-05-30 15:10:09 +0200329 { size_t const r = ZSTD_decompress(decodedBuffer, CNBuffSize, CNBuffer, 4);
Yann Collet33341de2016-05-29 23:09:51 +0200330 if (!ZSTD_isError(r)) goto _output_error; }
Yann Collet4856a002015-01-24 01:58:16 +0100331 DISPLAYLEVEL(4, "OK \n");
332
Yann Colletbf42c8e2016-01-09 01:08:23 +0100333 /* block API tests */
Yann Colletd1d210f2016-03-19 12:12:07 +0100334 { ZSTD_CCtx* const cctx = ZSTD_createCCtx();
Yann Colletbf42c8e2016-01-09 01:08:23 +0100335 ZSTD_DCtx* const dctx = ZSTD_createDCtx();
Yann Colletd3d2db52016-07-15 12:20:26 +0200336 static const size_t dictSize = 65 KB;
337 static const size_t blockSize = 100 KB; /* won't cause pb with small dict size */
Yann Colletd4f4e582016-06-27 01:31:35 +0200338 size_t cSize2;
Yann Colletbf42c8e2016-01-09 01:08:23 +0100339
340 /* basic block compression */
341 DISPLAYLEVEL(4, "test%3i : Block compression test : ", testNb++);
Yann Colletc0a9bf32016-05-30 01:56:08 +0200342 CHECK( ZSTD_compressBegin(cctx, 5) );
Yann Colletbf42c8e2016-01-09 01:08:23 +0100343 cSize = ZSTD_compressBlock(cctx, compressedBuffer, ZSTD_compressBound(blockSize), CNBuffer, blockSize);
344 if (ZSTD_isError(cSize)) goto _output_error;
345 DISPLAYLEVEL(4, "OK \n");
346
347 DISPLAYLEVEL(4, "test%3i : Block decompression test : ", testNb++);
Yann Colletc0a9bf32016-05-30 01:56:08 +0200348 CHECK( ZSTD_decompressBegin(dctx) );
Yann Colletd4f4e582016-06-27 01:31:35 +0200349 { CHECK_V(r, ZSTD_decompressBlock(dctx, decodedBuffer, CNBuffSize, compressedBuffer, cSize) );
Yann Colletd2858e92016-05-30 15:10:09 +0200350 if (r != blockSize) goto _output_error; }
Yann Colletbf42c8e2016-01-09 01:08:23 +0100351 DISPLAYLEVEL(4, "OK \n");
352
Yann Colletb0125102016-01-09 02:00:10 +0100353 /* dictionary block compression */
354 DISPLAYLEVEL(4, "test%3i : Dictionary Block compression test : ", testNb++);
Yann Colletc0a9bf32016-05-30 01:56:08 +0200355 CHECK( ZSTD_compressBegin_usingDict(cctx, CNBuffer, dictSize, 5) );
Yann Colletb0125102016-01-09 02:00:10 +0100356 cSize = ZSTD_compressBlock(cctx, compressedBuffer, ZSTD_compressBound(blockSize), (char*)CNBuffer+dictSize, blockSize);
357 if (ZSTD_isError(cSize)) goto _output_error;
Yann Colletd4f4e582016-06-27 01:31:35 +0200358 cSize2 = ZSTD_compressBlock(cctx, (char*)compressedBuffer+cSize, ZSTD_compressBound(blockSize), (char*)CNBuffer+dictSize+blockSize, blockSize);
359 if (ZSTD_isError(cSize2)) goto _output_error;
Yann Colletaa2628d2016-07-07 15:28:41 +0200360 memcpy((char*)compressedBuffer+cSize, (char*)CNBuffer+dictSize+blockSize, blockSize); /* fake non-compressed block */
361 cSize2 = ZSTD_compressBlock(cctx, (char*)compressedBuffer+cSize+blockSize, ZSTD_compressBound(blockSize),
362 (char*)CNBuffer+dictSize+2*blockSize, blockSize);
363 if (ZSTD_isError(cSize2)) goto _output_error;
Yann Colletb0125102016-01-09 02:00:10 +0100364 DISPLAYLEVEL(4, "OK \n");
365
366 DISPLAYLEVEL(4, "test%3i : Dictionary Block decompression test : ", testNb++);
Yann Colletc0a9bf32016-05-30 01:56:08 +0200367 CHECK( ZSTD_decompressBegin_usingDict(dctx, CNBuffer, dictSize) );
Yann Colletd4f4e582016-06-27 01:31:35 +0200368 { CHECK_V( r, ZSTD_decompressBlock(dctx, decodedBuffer, CNBuffSize, compressedBuffer, cSize) );
369 if (r != blockSize) goto _output_error; }
Yann Colletaa2628d2016-07-07 15:28:41 +0200370 ZSTD_insertBlock(dctx, (char*)decodedBuffer+blockSize, blockSize); /* insert non-compressed block into dctx history */
371 { CHECK_V( r, ZSTD_decompressBlock(dctx, (char*)decodedBuffer+2*blockSize, CNBuffSize, (char*)compressedBuffer+cSize+blockSize, cSize2) );
Yann Colletc0a9bf32016-05-30 01:56:08 +0200372 if (r != blockSize) goto _output_error; }
Yann Colletb0125102016-01-09 02:00:10 +0100373 DISPLAYLEVEL(4, "OK \n");
374
Yann Colletbf42c8e2016-01-09 01:08:23 +0100375 ZSTD_freeCCtx(cctx);
376 ZSTD_freeDCtx(dctx);
377 }
378
Yann Collet213089c2015-06-18 07:43:16 -0800379 /* long rle test */
Yann Colletd1d210f2016-03-19 12:12:07 +0100380 { size_t sampleSize = 0;
Yann Collet213089c2015-06-18 07:43:16 -0800381 DISPLAYLEVEL(4, "test%3i : Long RLE test : ", testNb++);
Yann Colletc0a9bf32016-05-30 01:56:08 +0200382 RDG_genBuffer(CNBuffer, sampleSize, compressibility, 0., seed+1);
Yann Collet213089c2015-06-18 07:43:16 -0800383 memset((char*)CNBuffer+sampleSize, 'B', 256 KB - 1);
384 sampleSize += 256 KB - 1;
Yann Colletc0a9bf32016-05-30 01:56:08 +0200385 RDG_genBuffer((char*)CNBuffer+sampleSize, 96 KB, compressibility, 0., seed+2);
Yann Collet213089c2015-06-18 07:43:16 -0800386 sampleSize += 96 KB;
Yann Collet5be2dd22015-11-11 13:43:58 +0100387 cSize = ZSTD_compress(compressedBuffer, ZSTD_compressBound(sampleSize), CNBuffer, sampleSize, 1);
Yann Collet213089c2015-06-18 07:43:16 -0800388 if (ZSTD_isError(cSize)) goto _output_error;
Yann Colletd4f4e582016-06-27 01:31:35 +0200389 { CHECK_V(regenSize, ZSTD_decompress(decodedBuffer, sampleSize, compressedBuffer, cSize));
Yann Colletc0a9bf32016-05-30 01:56:08 +0200390 if (regenSize!=sampleSize) goto _output_error; }
Yann Collet213089c2015-06-18 07:43:16 -0800391 DISPLAYLEVEL(4, "OK \n");
392 }
393
Yann Colletc0a9bf32016-05-30 01:56:08 +0200394 /* All zeroes test (test bug #137) */
Yann Collet4ba85342016-03-07 20:01:45 +0100395 #define ZEROESLENGTH 100
396 DISPLAYLEVEL(4, "test%3i : compress %u zeroes : ", testNb++, ZEROESLENGTH);
397 memset(CNBuffer, 0, ZEROESLENGTH);
Yann Colletd4f4e582016-06-27 01:31:35 +0200398 { CHECK_V(r, ZSTD_compress(compressedBuffer, ZSTD_compressBound(ZEROESLENGTH), CNBuffer, ZEROESLENGTH, 1) );
Yann Colletc0a9bf32016-05-30 01:56:08 +0200399 cSize = r; }
Yann Collet4ba85342016-03-07 20:01:45 +0100400 DISPLAYLEVEL(4, "OK (%u bytes : %.2f%%)\n", (U32)cSize, (double)cSize/ZEROESLENGTH*100);
401
402 DISPLAYLEVEL(4, "test%3i : decompress %u zeroes : ", testNb++, ZEROESLENGTH);
Yann Colletd4f4e582016-06-27 01:31:35 +0200403 { CHECK_V(r, ZSTD_decompress(decodedBuffer, ZEROESLENGTH, compressedBuffer, cSize) );
Yann Colletc0a9bf32016-05-30 01:56:08 +0200404 if (r != ZEROESLENGTH) goto _output_error; }
Yann Collet4ba85342016-03-07 20:01:45 +0100405 DISPLAYLEVEL(4, "OK \n");
406
407 /* nbSeq limit test */
Yann Colletd1d210f2016-03-19 12:12:07 +0100408 #define _3BYTESTESTLENGTH 131000
409 #define NB3BYTESSEQLOG 9
410 #define NB3BYTESSEQ (1 << NB3BYTESSEQLOG)
411 #define NB3BYTESSEQMASK (NB3BYTESSEQ-1)
Yann Collet0d9ce042016-03-19 13:21:08 +0100412 /* creates a buffer full of 3-bytes sequences */
Yann Colletd1d210f2016-03-19 12:12:07 +0100413 { BYTE _3BytesSeqs[NB3BYTESSEQ][3];
Yann Collet0d9ce042016-03-19 13:21:08 +0100414 U32 rSeed = 1;
Yann Collet4ba85342016-03-07 20:01:45 +0100415
Yann Collet0d9ce042016-03-19 13:21:08 +0100416 /* create batch of 3-bytes sequences */
Yann Colletf323bf72016-07-07 13:14:21 +0200417 { int i;
418 for (i=0; i < NB3BYTESSEQ; i++) {
419 _3BytesSeqs[i][0] = (BYTE)(FUZ_rand(&rSeed) & 255);
420 _3BytesSeqs[i][1] = (BYTE)(FUZ_rand(&rSeed) & 255);
421 _3BytesSeqs[i][2] = (BYTE)(FUZ_rand(&rSeed) & 255);
422 } }
Yann Collet4ba85342016-03-07 20:01:45 +0100423
Yann Collet0d9ce042016-03-19 13:21:08 +0100424 /* randomly fills CNBuffer with prepared 3-bytes sequences */
Yann Colletf323bf72016-07-07 13:14:21 +0200425 { int i;
426 for (i=0; i < _3BYTESTESTLENGTH; i += 3) { /* note : CNBuffer size > _3BYTESTESTLENGTH+3 */
427 U32 const id = FUZ_rand(&rSeed) & NB3BYTESSEQMASK;
428 ((BYTE*)CNBuffer)[i+0] = _3BytesSeqs[id][0];
429 ((BYTE*)CNBuffer)[i+1] = _3BytesSeqs[id][1];
430 ((BYTE*)CNBuffer)[i+2] = _3BytesSeqs[id][2];
431 } } }
Yann Collet0d9ce042016-03-19 13:21:08 +0100432 DISPLAYLEVEL(4, "test%3i : compress lots 3-bytes sequences : ", testNb++);
Yann Colletd4f4e582016-06-27 01:31:35 +0200433 { CHECK_V(r, ZSTD_compress(compressedBuffer, ZSTD_compressBound(_3BYTESTESTLENGTH),
Yann Colletc0a9bf32016-05-30 01:56:08 +0200434 CNBuffer, _3BYTESTESTLENGTH, 19) );
435 cSize = r; }
Yann Collet0d9ce042016-03-19 13:21:08 +0100436 DISPLAYLEVEL(4, "OK (%u bytes : %.2f%%)\n", (U32)cSize, (double)cSize/_3BYTESTESTLENGTH*100);
Yann Collet4ba85342016-03-07 20:01:45 +0100437
Yann Collet0d9ce042016-03-19 13:21:08 +0100438 DISPLAYLEVEL(4, "test%3i : decompress lots 3-bytes sequence : ", testNb++);
Yann Colletd4f4e582016-06-27 01:31:35 +0200439 { CHECK_V(r, ZSTD_decompress(decodedBuffer, _3BYTESTESTLENGTH, compressedBuffer, cSize) );
Yann Colletc0a9bf32016-05-30 01:56:08 +0200440 if (r != _3BYTESTESTLENGTH) goto _output_error; }
Yann Collet0d9ce042016-03-19 13:21:08 +0100441 DISPLAYLEVEL(4, "OK \n");
Yann Collet4ba85342016-03-07 20:01:45 +0100442
Yann Collet4856a002015-01-24 01:58:16 +0100443_end:
444 free(CNBuffer);
445 free(compressedBuffer);
446 free(decodedBuffer);
447 return testResult;
448
449_output_error:
450 testResult = 1;
451 DISPLAY("Error detected in Unit tests ! \n");
452 goto _end;
453}
454
455
456static size_t findDiff(const void* buf1, const void* buf2, size_t max)
457{
Yann Collet213089c2015-06-18 07:43:16 -0800458 const BYTE* b1 = (const BYTE*)buf1;
459 const BYTE* b2 = (const BYTE*)buf2;
Yann Colletc0a9bf32016-05-30 01:56:08 +0200460 size_t u;
461 for (u=0; u<max; u++) {
462 if (b1[u] != b2[u]) break;
Yann Collet4856a002015-01-24 01:58:16 +0100463 }
Yann Colletc0a9bf32016-05-30 01:56:08 +0200464 return u;
Yann Collet4856a002015-01-24 01:58:16 +0100465}
466
Yann Collet1fce6e02016-04-08 20:26:33 +0200467
468static size_t FUZ_rLogLength(U32* seed, U32 logLength)
469{
470 size_t const lengthMask = ((size_t)1 << logLength) - 1;
471 return (lengthMask+1) + (FUZ_rand(seed) & lengthMask);
472}
473
474static size_t FUZ_randomLength(U32* seed, U32 maxLog)
475{
476 U32 const logLength = FUZ_rand(seed) % maxLog;
477 return FUZ_rLogLength(seed, logLength);
478}
479
Yann Colletc0a9bf32016-05-30 01:56:08 +0200480#undef CHECK
Yann Collet0d9ce042016-03-19 13:21:08 +0100481#define CHECK(cond, ...) if (cond) { DISPLAY("Error => "); DISPLAY(__VA_ARGS__); \
482 DISPLAY(" (seed %u, test nb %u) \n", seed, testNb); goto _output_error; }
Yann Collet4856a002015-01-24 01:58:16 +0100483
Yann Colletea63bb72016-04-08 15:25:32 +0200484static int fuzzerTests(U32 seed, U32 nbTests, unsigned startTest, U32 const maxDurationS, double compressibility)
Yann Collet4856a002015-01-24 01:58:16 +0100485{
Yann Collet1fce6e02016-04-08 20:26:33 +0200486 static const U32 maxSrcLog = 23;
487 static const U32 maxSampleLog = 22;
Yann Colletc0a9bf32016-05-30 01:56:08 +0200488 size_t const srcBufferSize = (size_t)1<<maxSrcLog;
489 size_t const dstBufferSize = (size_t)1<<maxSampleLog;
490 size_t const cBufferSize = ZSTD_compressBound(dstBufferSize);
Yann Colletd5d9bc32015-08-23 23:13:49 +0100491 BYTE* cNoiseBuffer[5];
Yann Colletc0a9bf32016-05-30 01:56:08 +0200492 BYTE* srcBuffer; /* jumping pointer */
493 BYTE* const cBuffer = (BYTE*) malloc (cBufferSize);
494 BYTE* const dstBuffer = (BYTE*) malloc (dstBufferSize);
495 BYTE* const mirrorBuffer = (BYTE*) malloc (dstBufferSize);
Yann Colletd2858e92016-05-30 15:10:09 +0200496 ZSTD_CCtx* const refCtx = ZSTD_createCCtx();
497 ZSTD_CCtx* const ctx = ZSTD_createCCtx();
498 ZSTD_DCtx* const dctx = ZSTD_createDCtx();
Yann Collet30009522016-05-30 16:17:33 +0200499 U32 result = 0;
500 U32 testNb = 0;
501 U32 coreSeed = seed, lseed = 0;
Yann Colletd2858e92016-05-30 15:10:09 +0200502 clock_t const startClock = clock();
Yann Colletea63bb72016-04-08 15:25:32 +0200503 clock_t const maxClockSpan = maxDurationS * CLOCKS_PER_SEC;
Yann Collet4856a002015-01-24 01:58:16 +0100504
505 /* allocation */
Yann Colletd5d9bc32015-08-23 23:13:49 +0100506 cNoiseBuffer[0] = (BYTE*)malloc (srcBufferSize);
507 cNoiseBuffer[1] = (BYTE*)malloc (srcBufferSize);
508 cNoiseBuffer[2] = (BYTE*)malloc (srcBufferSize);
509 cNoiseBuffer[3] = (BYTE*)malloc (srcBufferSize);
510 cNoiseBuffer[4] = (BYTE*)malloc (srcBufferSize);
Yann Collete47c4e52015-12-05 09:23:53 +0100511 CHECK (!cNoiseBuffer[0] || !cNoiseBuffer[1] || !cNoiseBuffer[2] || !cNoiseBuffer[3] || !cNoiseBuffer[4]
Yann Colletecd651b2016-01-07 15:35:18 +0100512 || !dstBuffer || !mirrorBuffer || !cBuffer || !refCtx || !ctx || !dctx,
Yann Colletd5d9bc32015-08-23 23:13:49 +0100513 "Not enough memory, fuzzer tests cancelled");
Yann Collet4856a002015-01-24 01:58:16 +0100514
Yann Colletd5d9bc32015-08-23 23:13:49 +0100515 /* Create initial samples */
516 RDG_genBuffer(cNoiseBuffer[0], srcBufferSize, 0.00, 0., coreSeed); /* pure noise */
517 RDG_genBuffer(cNoiseBuffer[1], srcBufferSize, 0.05, 0., coreSeed); /* barely compressible */
518 RDG_genBuffer(cNoiseBuffer[2], srcBufferSize, compressibility, 0., coreSeed);
519 RDG_genBuffer(cNoiseBuffer[3], srcBufferSize, 0.95, 0., coreSeed); /* highly compressible */
520 RDG_genBuffer(cNoiseBuffer[4], srcBufferSize, 1.00, 0., coreSeed); /* sparse content */
521 srcBuffer = cNoiseBuffer[2];
Yann Collet4856a002015-01-24 01:58:16 +0100522
523 /* catch up testNb */
Yann Collet546c9b12016-03-19 12:47:52 +0100524 for (testNb=1; testNb < startTest; testNb++) FUZ_rand(&coreSeed);
Yann Collet4856a002015-01-24 01:58:16 +0100525
Yann Collet546c9b12016-03-19 12:47:52 +0100526 /* main test loop */
Yann Colletea63bb72016-04-08 15:25:32 +0200527 for ( ; (testNb <= nbTests) || (FUZ_clockSpan(startClock) < maxClockSpan); testNb++ ) {
Yann Colletc0a9bf32016-05-30 01:56:08 +0200528 size_t sampleSize, maxTestSize, totalTestSize;
529 size_t cSize, totalCSize, totalGenSize;
Yann Collet6c903a82016-05-28 13:34:07 +0200530 XXH64_state_t xxhState;
Yann Collet1fce6e02016-04-08 20:26:33 +0200531 U64 crcOrig;
Yann Collet110cc142015-11-19 12:02:28 +0100532 BYTE* sampleBuffer;
Yann Collet4bfe4152015-12-06 13:18:37 +0100533 const BYTE* dict;
534 size_t dictSize;
Yann Collet4856a002015-01-24 01:58:16 +0100535
Yann Collet546c9b12016-03-19 12:47:52 +0100536 /* notification */
537 if (nbTests >= testNb) { DISPLAYUPDATE(2, "\r%6u/%6u ", testNb, nbTests); }
Yann Collet4c0b44f2016-11-01 11:13:22 -0700538 else { DISPLAYUPDATE(2, "\r%6u ", testNb); }
Yann Collet1c2ddba2015-12-04 17:45:35 +0100539
Yann Collet4856a002015-01-24 01:58:16 +0100540 FUZ_rand(&coreSeed);
Yann Collet0d9ce042016-03-19 13:21:08 +0100541 { U32 const prime1 = 2654435761U; lseed = coreSeed ^ prime1; }
Yann Collet1fce6e02016-04-08 20:26:33 +0200542
543 /* srcBuffer selection [0-4] */
544 { U32 buffNb = FUZ_rand(&lseed) & 0x7F;
545 if (buffNb & 7) buffNb=2; /* most common : compressible (P) */
546 else {
547 buffNb >>= 3;
548 if (buffNb & 7) {
549 const U32 tnb[2] = { 1, 3 }; /* barely/highly compressible */
550 buffNb = tnb[buffNb >> 3];
551 } else {
552 const U32 tnb[2] = { 0, 4 }; /* not compressible / sparse */
553 buffNb = tnb[buffNb >> 3];
554 } }
555 srcBuffer = cNoiseBuffer[buffNb];
556 }
557
558 /* select src segment */
Yann Colletd2858e92016-05-30 15:10:09 +0200559 sampleSize = FUZ_randomLength(&lseed, maxSampleLog);
Yann Collet4856a002015-01-24 01:58:16 +0100560
Yann Collet110cc142015-11-19 12:02:28 +0100561 /* create sample buffer (to catch read error with valgrind & sanitizers) */
562 sampleBuffer = (BYTE*)malloc(sampleSize);
Yann Colletd2858e92016-05-30 15:10:09 +0200563 CHECK(sampleBuffer==NULL, "not enough memory for sample buffer");
Yann Colletc0a9bf32016-05-30 01:56:08 +0200564 { size_t const sampleStart = FUZ_rand(&lseed) % (srcBufferSize - sampleSize);
565 memcpy(sampleBuffer, srcBuffer + sampleStart, sampleSize); }
Yann Collet110cc142015-11-19 12:02:28 +0100566 crcOrig = XXH64(sampleBuffer, sampleSize, 0);
567
Yann Collet1fce6e02016-04-08 20:26:33 +0200568 /* compression tests */
Yann Colletd2858e92016-05-30 15:10:09 +0200569 { unsigned const cLevel = (FUZ_rand(&lseed) % (ZSTD_maxCLevel() - (FUZ_highbit32((U32)sampleSize)/3))) + 1;
Yann Collet1fce6e02016-04-08 20:26:33 +0200570 cSize = ZSTD_compressCCtx(ctx, cBuffer, cBufferSize, sampleBuffer, sampleSize, cLevel);
Yann Colleta7737f62016-09-06 09:44:59 +0200571 CHECK(ZSTD_isError(cSize), "ZSTD_compressCCtx failed : %s", ZSTD_getErrorName(cSize));
Yann Collet4856a002015-01-24 01:58:16 +0100572
Yann Collet1fce6e02016-04-08 20:26:33 +0200573 /* compression failure test : too small dest buffer */
574 if (cSize > 3) {
575 const size_t missing = (FUZ_rand(&lseed) % (cSize-2)) + 1; /* no problem, as cSize > 4 (frameHeaderSizer) */
576 const size_t tooSmallSize = cSize - missing;
577 const U32 endMark = 0x4DC2B1A9;
578 memcpy(dstBuffer+tooSmallSize, &endMark, 4);
579 { size_t const errorCode = ZSTD_compressCCtx(ctx, dstBuffer, tooSmallSize, sampleBuffer, sampleSize, cLevel);
580 CHECK(!ZSTD_isError(errorCode), "ZSTD_compressCCtx should have failed ! (buffer too small : %u < %u)", (U32)tooSmallSize, (U32)cSize); }
581 { U32 endCheck; memcpy(&endCheck, dstBuffer+tooSmallSize, 4);
582 CHECK(endCheck != endMark, "ZSTD_compressCCtx : dst buffer overflow"); }
Yann Colletd2858e92016-05-30 15:10:09 +0200583 } }
Yann Collet1fce6e02016-04-08 20:26:33 +0200584
Yann Colletf323bf72016-07-07 13:14:21 +0200585 /* Decompressed size test */
586 { unsigned long long const rSize = ZSTD_getDecompressedSize(cBuffer, cSize);
587 CHECK(rSize != sampleSize, "decompressed size incorrect");
588 }
589
Yann Collet546c9b12016-03-19 12:47:52 +0100590 /* frame header decompression test */
Yann Collet346bffb2016-03-15 15:24:52 +0100591 { ZSTD_frameParams dParams;
592 size_t const check = ZSTD_getFrameParams(&dParams, cBuffer, cSize);
593 CHECK(ZSTD_isError(check), "Frame Parameters extraction failed");
594 CHECK(dParams.frameContentSize != sampleSize, "Frame content size incorrect");
595 }
596
Yann Collet546c9b12016-03-19 12:47:52 +0100597 /* successful decompression test */
Yann Collet1fce6e02016-04-08 20:26:33 +0200598 { size_t const margin = (FUZ_rand(&lseed) & 1) ? 0 : (FUZ_rand(&lseed) & 31) + 1;
Yann Colletc0a9bf32016-05-30 01:56:08 +0200599 size_t const dSize = ZSTD_decompress(dstBuffer, sampleSize + margin, cBuffer, cSize);
Yann Collet546c9b12016-03-19 12:47:52 +0100600 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 +0200601 { U64 const crcDest = XXH64(dstBuffer, sampleSize, 0);
602 CHECK(crcOrig != crcDest, "decompression result corrupted (pos %u / %u)", (U32)findDiff(sampleBuffer, dstBuffer, sampleSize), (U32)sampleSize);
603 } }
Yann Collet110cc142015-11-19 12:02:28 +0100604
605 free(sampleBuffer); /* no longer useful after this point */
Yann Colletf3cb79b2015-08-20 00:02:43 +0100606
607 /* truncated src decompression test */
Yann Collet1fce6e02016-04-08 20:26:33 +0200608 { size_t const missing = (FUZ_rand(&lseed) % (cSize-2)) + 1; /* no problem, as cSize > 4 (frameHeaderSizer) */
609 size_t const tooSmallSize = cSize - missing;
Yann Colletd2858e92016-05-30 15:10:09 +0200610 void* cBufferTooSmall = malloc(tooSmallSize); /* valgrind will catch read overflows */
Yann Colletf3cb79b2015-08-20 00:02:43 +0100611 CHECK(cBufferTooSmall == NULL, "not enough memory !");
Yann Colletd5d9bc32015-08-23 23:13:49 +0100612 memcpy(cBufferTooSmall, cBuffer, tooSmallSize);
Yann Collet1fce6e02016-04-08 20:26:33 +0200613 { size_t const errorCode = ZSTD_decompress(dstBuffer, dstBufferSize, cBufferTooSmall, tooSmallSize);
614 CHECK(!ZSTD_isError(errorCode), "ZSTD_decompress should have failed ! (truncated src buffer)"); }
Yann Colletf3cb79b2015-08-20 00:02:43 +0100615 free(cBufferTooSmall);
616 }
617
618 /* too small dst decompression test */
Yann Colletd1d210f2016-03-19 12:12:07 +0100619 if (sampleSize > 3) {
Yann Colletea63bb72016-04-08 15:25:32 +0200620 size_t const missing = (FUZ_rand(&lseed) % (sampleSize-2)) + 1; /* no problem, as cSize > 4 (frameHeaderSizer) */
621 size_t const tooSmallSize = sampleSize - missing;
Yann Colletf3cb79b2015-08-20 00:02:43 +0100622 static const BYTE token = 0xA9;
623 dstBuffer[tooSmallSize] = token;
Yann Collet1fce6e02016-04-08 20:26:33 +0200624 { size_t const errorCode = ZSTD_decompress(dstBuffer, tooSmallSize, cBuffer, cSize);
625 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 +0100626 CHECK(dstBuffer[tooSmallSize] != token, "ZSTD_decompress : dst buffer overflow");
627 }
Yann Collet997f9ee2015-08-21 02:44:20 +0100628
629 /* noisy src decompression test */
Yann Colletd1d210f2016-03-19 12:12:07 +0100630 if (cSize > 6) {
631 /* insert noise into src */
632 { U32 const maxNbBits = FUZ_highbit32((U32)(cSize-4));
633 size_t pos = 4; /* preserve magic number (too easy to detect) */
634 for (;;) {
635 /* keep some original src */
636 { U32 const nbBits = FUZ_rand(&lseed) % maxNbBits;
637 size_t const mask = (1<<nbBits) - 1;
638 size_t const skipLength = FUZ_rand(&lseed) & mask;
639 pos += skipLength;
640 }
641 if (pos <= cSize) break;
642 /* add noise */
Yann Collet33341de2016-05-29 23:09:51 +0200643 { U32 const nbBitsCodes = FUZ_rand(&lseed) % maxNbBits;
644 U32 const nbBits = nbBitsCodes ? nbBitsCodes-1 : 0;
645 size_t const mask = (1<<nbBits) - 1;
646 size_t const rNoiseLength = (FUZ_rand(&lseed) & mask) + 1;
647 size_t const noiseLength = MIN(rNoiseLength, cSize-pos);
648 size_t const noiseStart = FUZ_rand(&lseed) % (srcBufferSize - noiseLength);
Yann Colletd1d210f2016-03-19 12:12:07 +0100649 memcpy(cBuffer + pos, srcBuffer + noiseStart, noiseLength);
650 pos += noiseLength;
651 } } }
Yann Collet997f9ee2015-08-21 02:44:20 +0100652
653 /* decompress noisy source */
Yann Colletd1d210f2016-03-19 12:12:07 +0100654 { U32 const endMark = 0xA9B1C3D6;
Yann Collet997f9ee2015-08-21 02:44:20 +0100655 memcpy(dstBuffer+sampleSize, &endMark, 4);
Yann Collet1fce6e02016-04-08 20:26:33 +0200656 { size_t const decompressResult = ZSTD_decompress(dstBuffer, sampleSize, cBuffer, cSize);
657 /* result *may* be an unlikely success, but even then, it must strictly respect dst buffer boundaries */
658 CHECK((!ZSTD_isError(decompressResult)) && (decompressResult>sampleSize),
659 "ZSTD_decompress on noisy src : result is too large : %u > %u (dst buffer)", (U32)decompressResult, (U32)sampleSize);
660 }
661 { U32 endCheck; memcpy(&endCheck, dstBuffer+sampleSize, 4);
662 CHECK(endMark!=endCheck, "ZSTD_decompress on noisy src : dst buffer overflow");
663 } } } /* noisy src decompression test */
Yann Collet417890c2015-12-04 17:16:37 +0100664
Yann Collet1fce6e02016-04-08 20:26:33 +0200665 /*===== Streaming compression test, scattered segments and dictionary =====*/
666
667 { U32 const testLog = FUZ_rand(&lseed) % maxSrcLog;
668 int const cLevel = (FUZ_rand(&lseed) % (ZSTD_maxCLevel() - (testLog/3))) + 1;
669 maxTestSize = FUZ_rLogLength(&lseed, testLog);
670 if (maxTestSize >= dstBufferSize) maxTestSize = dstBufferSize-1;
671
Yann Colletc0a9bf32016-05-30 01:56:08 +0200672 dictSize = FUZ_randomLength(&lseed, maxSampleLog); /* needed also for decompression */
673 dict = srcBuffer + (FUZ_rand(&lseed) % (srcBufferSize - dictSize));
Yann Collet1fce6e02016-04-08 20:26:33 +0200674
Yann Colletf2a3b6e2016-05-31 18:13:56 +0200675 if (FUZ_rand(&lseed) & 0xF) {
Yann Collet33341de2016-05-29 23:09:51 +0200676 size_t const errorCode = ZSTD_compressBegin_usingDict(refCtx, dict, dictSize, cLevel);
677 CHECK (ZSTD_isError(errorCode), "ZSTD_compressBegin_usingDict error : %s", ZSTD_getErrorName(errorCode));
678 } else {
cyanb8806312016-05-30 18:20:46 +0200679 ZSTD_compressionParameters const cPar = ZSTD_getCParams(cLevel, 0, dictSize);
Yann Colletf2a3b6e2016-05-31 18:13:56 +0200680 ZSTD_frameParameters const fpar = { FUZ_rand(&lseed)&1 /* contentSizeFlag */,
681 !(FUZ_rand(&lseed)&3) /* contentChecksumFlag*/,
682 0 /*NodictID*/ }; /* note : since dictionary is fake, dictIDflag has no impact */
cyanb8806312016-05-30 18:20:46 +0200683 ZSTD_parameters p;
684 size_t errorCode;
685 p.cParams = cPar; p.fParams = fpar;
686 errorCode = ZSTD_compressBegin_advanced(refCtx, dict, dictSize, p, 0);
Yann Collet33341de2016-05-29 23:09:51 +0200687 CHECK (ZSTD_isError(errorCode), "ZSTD_compressBegin_advanced error : %s", ZSTD_getErrorName(errorCode));
688 }
Yann Collet97b378a2016-09-21 17:20:19 +0200689 { size_t const errorCode = ZSTD_copyCCtx(ctx, refCtx, 0);
690 CHECK (ZSTD_isError(errorCode), "ZSTD_copyCCtx error : %s", ZSTD_getErrorName(errorCode));
691 } }
Yann Collet6c903a82016-05-28 13:34:07 +0200692 XXH64_reset(&xxhState, 0);
Yann Colletd2858e92016-05-30 15:10:09 +0200693 { U32 const nbChunks = (FUZ_rand(&lseed) & 127) + 2;
694 U32 n;
695 for (totalTestSize=0, cSize=0, n=0 ; n<nbChunks ; n++) {
696 size_t const segmentSize = FUZ_randomLength(&lseed, maxSampleLog);
697 size_t const segmentStart = FUZ_rand(&lseed) % (srcBufferSize - segmentSize);
Yann Collet417890c2015-12-04 17:16:37 +0100698
Yann Colletd2858e92016-05-30 15:10:09 +0200699 if (cBufferSize-cSize < ZSTD_compressBound(segmentSize)) break; /* avoid invalid dstBufferTooSmall */
700 if (totalTestSize+segmentSize > maxTestSize) break;
Yann Collet417890c2015-12-04 17:16:37 +0100701
Yann Colletd2858e92016-05-30 15:10:09 +0200702 { size_t const compressResult = ZSTD_compressContinue(ctx, cBuffer+cSize, cBufferSize-cSize, srcBuffer+segmentStart, segmentSize);
703 CHECK (ZSTD_isError(compressResult), "multi-segments compression error : %s", ZSTD_getErrorName(compressResult));
704 cSize += compressResult;
705 }
706 XXH64_update(&xxhState, srcBuffer+segmentStart, segmentSize);
707 memcpy(mirrorBuffer + totalTestSize, srcBuffer+segmentStart, segmentSize);
708 totalTestSize += segmentSize;
709 } }
710
Yann Collet62470b42016-07-28 15:29:08 +0200711 { size_t const flushResult = ZSTD_compressEnd(ctx, cBuffer+cSize, cBufferSize-cSize, NULL, 0);
Yann Collet1fce6e02016-04-08 20:26:33 +0200712 CHECK (ZSTD_isError(flushResult), "multi-segments epilogue error : %s", ZSTD_getErrorName(flushResult));
713 cSize += flushResult;
714 }
Yann Collet6c903a82016-05-28 13:34:07 +0200715 crcOrig = XXH64_digest(&xxhState);
Yann Collete47c4e52015-12-05 09:23:53 +0100716
717 /* streaming decompression test */
Yann Collet33341de2016-05-29 23:09:51 +0200718 if (dictSize<8) dictSize=0, dict=NULL; /* disable dictionary */
Yann Collet1fce6e02016-04-08 20:26:33 +0200719 { size_t const errorCode = ZSTD_decompressBegin_usingDict(dctx, dict, dictSize);
Yann Collet30009522016-05-30 16:17:33 +0200720 CHECK (ZSTD_isError(errorCode), "ZSTD_decompressBegin_usingDict error : %s", ZSTD_getErrorName(errorCode)); }
Yann Collete47c4e52015-12-05 09:23:53 +0100721 totalCSize = 0;
722 totalGenSize = 0;
Yann Colletd1d210f2016-03-19 12:12:07 +0100723 while (totalCSize < cSize) {
Yann Collet1fce6e02016-04-08 20:26:33 +0200724 size_t const inSize = ZSTD_nextSrcSizeToDecompress(dctx);
725 size_t const genSize = ZSTD_decompressContinue(dctx, dstBuffer+totalGenSize, dstBufferSize-totalGenSize, cBuffer+totalCSize, inSize);
Yann Collet45dc3562016-07-12 09:47:31 +0200726 CHECK (ZSTD_isError(genSize), "ZSTD_decompressContinue error : %s", ZSTD_getErrorName(genSize));
Yann Collete47c4e52015-12-05 09:23:53 +0100727 totalGenSize += genSize;
728 totalCSize += inSize;
729 }
730 CHECK (ZSTD_nextSrcSizeToDecompress(dctx) != 0, "frame not fully decoded");
Yann Colletc0a9bf32016-05-30 01:56:08 +0200731 CHECK (totalGenSize != totalTestSize, "streaming decompressed data : wrong size")
Yann Collete47c4e52015-12-05 09:23:53 +0100732 CHECK (totalCSize != cSize, "compressed data should be fully read")
Yann Collet1fce6e02016-04-08 20:26:33 +0200733 { U64 const crcDest = XXH64(dstBuffer, totalTestSize, 0);
734 if (crcDest!=crcOrig) {
735 size_t const errorPos = findDiff(mirrorBuffer, dstBuffer, totalTestSize);
Yann Colletd2858e92016-05-30 15:10:09 +0200736 CHECK (1, "streaming decompressed data corrupted : byte %u / %u (%02X!=%02X)",
Yann Collet1fce6e02016-04-08 20:26:33 +0200737 (U32)errorPos, (U32)totalTestSize, dstBuffer[errorPos], mirrorBuffer[errorPos]);
738 } }
739 } /* for ( ; (testNb <= nbTests) */
Yann Collet1c2ddba2015-12-04 17:45:35 +0100740 DISPLAY("\r%u fuzzer tests completed \n", testNb-1);
Yann Collet4856a002015-01-24 01:58:16 +0100741
742_cleanup:
Yann Colletecd651b2016-01-07 15:35:18 +0100743 ZSTD_freeCCtx(refCtx);
Yann Collet2f648e52015-10-29 18:23:38 +0100744 ZSTD_freeCCtx(ctx);
Yann Collete47c4e52015-12-05 09:23:53 +0100745 ZSTD_freeDCtx(dctx);
Yann Colletd5d9bc32015-08-23 23:13:49 +0100746 free(cNoiseBuffer[0]);
747 free(cNoiseBuffer[1]);
748 free(cNoiseBuffer[2]);
749 free(cNoiseBuffer[3]);
750 free(cNoiseBuffer[4]);
Yann Collet4856a002015-01-24 01:58:16 +0100751 free(cBuffer);
752 free(dstBuffer);
Yann Collete47c4e52015-12-05 09:23:53 +0100753 free(mirrorBuffer);
Yann Collet4856a002015-01-24 01:58:16 +0100754 return result;
755
756_output_error:
757 result = 1;
758 goto _cleanup;
759}
760
761
Yann Colletd1d210f2016-03-19 12:12:07 +0100762/*_*******************************************************
Yann Collet4856a002015-01-24 01:58:16 +0100763* Command line
764*********************************************************/
Yann Colletd1d210f2016-03-19 12:12:07 +0100765int FUZ_usage(const char* programName)
Yann Collet4856a002015-01-24 01:58:16 +0100766{
767 DISPLAY( "Usage :\n");
768 DISPLAY( " %s [args]\n", programName);
769 DISPLAY( "\n");
770 DISPLAY( "Arguments :\n");
771 DISPLAY( " -i# : Nb of tests (default:%u) \n", nbTestsDefault);
772 DISPLAY( " -s# : Select seed (default:prompt user)\n");
773 DISPLAY( " -t# : Select starting test number (default:0)\n");
Yann Collet0d9ce042016-03-19 13:21:08 +0100774 DISPLAY( " -P# : Select compressibility in %% (default:%u%%)\n", FUZ_compressibility_default);
Yann Collet4856a002015-01-24 01:58:16 +0100775 DISPLAY( " -v : verbose\n");
Yann Collete9853b22015-08-07 19:07:32 +0100776 DISPLAY( " -p : pause at the end\n");
Yann Collet4856a002015-01-24 01:58:16 +0100777 DISPLAY( " -h : display help and exit\n");
778 return 0;
779}
780
781
Yann Colletd1d210f2016-03-19 12:12:07 +0100782int main(int argc, const char** argv)
Yann Collet4856a002015-01-24 01:58:16 +0100783{
784 U32 seed=0;
785 int seedset=0;
786 int argNb;
787 int nbTests = nbTestsDefault;
788 int testNb = 0;
Yann Collet0d9ce042016-03-19 13:21:08 +0100789 U32 proba = FUZ_compressibility_default;
Yann Collet4856a002015-01-24 01:58:16 +0100790 int result=0;
791 U32 mainPause = 0;
Yann Collet0d9ce042016-03-19 13:21:08 +0100792 U32 maxDuration = 0;
Yann Colletea63bb72016-04-08 15:25:32 +0200793 const char* programName = argv[0];
Yann Collet4856a002015-01-24 01:58:16 +0100794
795 /* Check command line */
Yann Colletd1d210f2016-03-19 12:12:07 +0100796 for (argNb=1; argNb<argc; argNb++) {
797 const char* argument = argv[argNb];
Yann Collet4856a002015-01-24 01:58:16 +0100798 if(!argument) continue; /* Protection if argument empty */
799
800 /* Handle commands. Aggregated commands are allowed */
Yann Colletd1d210f2016-03-19 12:12:07 +0100801 if (argument[0]=='-') {
Yann Collet4856a002015-01-24 01:58:16 +0100802 argument++;
Yann Colletd1d210f2016-03-19 12:12:07 +0100803 while (*argument!=0) {
Yann Collet4856a002015-01-24 01:58:16 +0100804 switch(*argument)
805 {
806 case 'h':
807 return FUZ_usage(programName);
808 case 'v':
809 argument++;
810 g_displayLevel=4;
811 break;
812 case 'q':
813 argument++;
814 g_displayLevel--;
815 break;
816 case 'p': /* pause at the end */
817 argument++;
818 mainPause = 1;
819 break;
820
821 case 'i':
Yann Collet0d9ce042016-03-19 13:21:08 +0100822 argument++; maxDuration=0;
Yann Collet4856a002015-01-24 01:58:16 +0100823 nbTests=0;
Yann Colletd1d210f2016-03-19 12:12:07 +0100824 while ((*argument>='0') && (*argument<='9')) {
Yann Collet4856a002015-01-24 01:58:16 +0100825 nbTests *= 10;
826 nbTests += *argument - '0';
827 argument++;
828 }
829 break;
830
Yann Collet553cf6a2015-12-04 17:25:26 +0100831 case 'T':
832 argument++;
Yann Collet0d9ce042016-03-19 13:21:08 +0100833 nbTests=0; maxDuration=0;
Yann Colletd1d210f2016-03-19 12:12:07 +0100834 while ((*argument>='0') && (*argument<='9')) {
Yann Collet0d9ce042016-03-19 13:21:08 +0100835 maxDuration *= 10;
836 maxDuration += *argument - '0';
Yann Collet553cf6a2015-12-04 17:25:26 +0100837 argument++;
838 }
Yann Collet0d9ce042016-03-19 13:21:08 +0100839 if (*argument=='m') maxDuration *=60, argument++;
Yann Collet553cf6a2015-12-04 17:25:26 +0100840 if (*argument=='n') argument++;
Yann Collet553cf6a2015-12-04 17:25:26 +0100841 break;
842
Yann Collet4856a002015-01-24 01:58:16 +0100843 case 's':
844 argument++;
845 seed=0;
846 seedset=1;
Yann Colletd1d210f2016-03-19 12:12:07 +0100847 while ((*argument>='0') && (*argument<='9')) {
Yann Collet4856a002015-01-24 01:58:16 +0100848 seed *= 10;
849 seed += *argument - '0';
850 argument++;
851 }
852 break;
853
854 case 't':
855 argument++;
856 testNb=0;
Yann Colletd1d210f2016-03-19 12:12:07 +0100857 while ((*argument>='0') && (*argument<='9')) {
Yann Collet4856a002015-01-24 01:58:16 +0100858 testNb *= 10;
859 testNb += *argument - '0';
860 argument++;
861 }
862 break;
863
864 case 'P': /* compressibility % */
865 argument++;
866 proba=0;
Yann Colletd1d210f2016-03-19 12:12:07 +0100867 while ((*argument>='0') && (*argument<='9')) {
Yann Collet4856a002015-01-24 01:58:16 +0100868 proba *= 10;
869 proba += *argument - '0';
870 argument++;
871 }
Yann Collet4856a002015-01-24 01:58:16 +0100872 if (proba>100) proba=100;
873 break;
874
875 default:
876 return FUZ_usage(programName);
Yann Colletd1d210f2016-03-19 12:12:07 +0100877 } } } } /* for (argNb=1; argNb<argc; argNb++) */
Yann Collet4856a002015-01-24 01:58:16 +0100878
879 /* Get Seed */
Yann Collet45f84ab2016-05-20 12:34:40 +0200880 DISPLAY("Starting zstd tester (%i-bits, %s)\n", (int)(sizeof(size_t)*8), ZSTD_VERSION_STRING);
Yann Collet4856a002015-01-24 01:58:16 +0100881
Yann Collet3f01c882016-06-16 13:38:10 +0200882 if (!seedset) {
883 time_t const t = time(NULL);
884 U32 const h = XXH32(&t, sizeof(t), 1);
885 seed = h % 10000;
886 }
887
Yann Collet4856a002015-01-24 01:58:16 +0100888 DISPLAY("Seed = %u\n", seed);
Yann Collet0d9ce042016-03-19 13:21:08 +0100889 if (proba!=FUZ_compressibility_default) DISPLAY("Compressibility : %u%%\n", proba);
Yann Collet4856a002015-01-24 01:58:16 +0100890
Yann Collet803c05e2016-06-16 11:32:57 +0200891 if (nbTests < testNb) nbTests = testNb;
892
Yann Colletd1d210f2016-03-19 12:12:07 +0100893 if (testNb==0)
894 result = basicUnitTests(0, ((double)proba) / 100); /* constant seed for predictability */
Yann Collet4856a002015-01-24 01:58:16 +0100895 if (!result)
Yann Collet0d9ce042016-03-19 13:21:08 +0100896 result = fuzzerTests(seed, nbTests, testNb, maxDuration, ((double)proba) / 100);
Yann Colletd1d210f2016-03-19 12:12:07 +0100897 if (mainPause) {
Yann Colletb5e06dc2015-07-04 23:20:56 -0800898 int unused;
Yann Collet4856a002015-01-24 01:58:16 +0100899 DISPLAY("Press Enter \n");
Yann Colletb5e06dc2015-07-04 23:20:56 -0800900 unused = getchar();
901 (void)unused;
Yann Collet4856a002015-01-24 01:58:16 +0100902 }
903 return result;
904}