1 /*
2 frameTest - test tool for lz4frame
3 Copyright (C) Yann Collet 2014-2016
4
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 :
22 - LZ4 homepage : http://www.lz4.org
23 - LZ4 source repository : https://github.com/lz4/lz4
24 */
25
26 /*-************************************
27 * Compiler specific
28 **************************************/
29 #ifdef _MSC_VER /* Visual Studio */
30 # pragma warning(disable : 4127) /* disable: C4127: conditional expression is constant */
31 # pragma warning(disable : 4146) /* disable: C4146: minus unsigned expression */
32 #endif
33
34
35 /*-************************************
36 * Includes
37 **************************************/
38 #include "util.h" /* U32 */
39 #include <stdlib.h> /* malloc, free */
40 #include <stdio.h> /* fprintf */
41 #include <string.h> /* strcmp */
42 #include <time.h> /* clock_t, clock(), CLOCKS_PER_SEC */
43 #include <assert.h>
44 #include "lz4frame.h" /* include multiple times to test correctness/safety */
45 #include "lz4frame.h"
46 #define LZ4F_STATIC_LINKING_ONLY
47 #include "lz4frame.h"
48 #include "lz4frame.h"
49 #include "lz4.h" /* LZ4_VERSION_STRING */
50 #define XXH_STATIC_LINKING_ONLY
51 #include "xxhash.h" /* XXH64 */
52
53
54 /* unoptimized version; solves endianess & alignment issues */
FUZ_writeLE32(void * dstVoidPtr,U32 value32)55 static void FUZ_writeLE32 (void* dstVoidPtr, U32 value32)
56 {
57 BYTE* dstPtr = (BYTE*)dstVoidPtr;
58 dstPtr[0] = (BYTE)value32;
59 dstPtr[1] = (BYTE)(value32 >> 8);
60 dstPtr[2] = (BYTE)(value32 >> 16);
61 dstPtr[3] = (BYTE)(value32 >> 24);
62 }
63
64
65 /*-************************************
66 * Constants
67 **************************************/
68 #define LZ4F_MAGIC_SKIPPABLE_START 0x184D2A50U
69
70 #define KB *(1U<<10)
71 #define MB *(1U<<20)
72 #define GB *(1U<<30)
73
74 static const U32 nbTestsDefault = 256 KB;
75 #define FUZ_COMPRESSIBILITY_DEFAULT 50
76 static const U32 prime1 = 2654435761U;
77 static const U32 prime2 = 2246822519U;
78
79
80
81 /*-************************************
82 * Macros
83 **************************************/
84 #define DISPLAY(...) fprintf(stderr, __VA_ARGS__)
85 #define DISPLAYLEVEL(l, ...) if (displayLevel>=l) { DISPLAY(__VA_ARGS__); }
86 #define DISPLAYUPDATE(l, ...) if (displayLevel>=l) { \
87 if ((FUZ_GetClockSpan(g_clockTime) > refreshRate) || (displayLevel>=4)) \
88 { g_clockTime = clock(); DISPLAY(__VA_ARGS__); \
89 if (displayLevel>=4) fflush(stdout); } }
90 static const clock_t refreshRate = CLOCKS_PER_SEC / 6;
91 static clock_t g_clockTime = 0;
92
93
94 /*-***************************************
95 * Local Parameters
96 *****************************************/
97 static U32 no_prompt = 0;
98 static U32 displayLevel = 2;
99 static U32 use_pause = 0;
100
101
102 /*-*******************************************************
103 * Fuzzer functions
104 *********************************************************/
105 #define MIN(a,b) ( (a) < (b) ? (a) : (b) )
106 #define MAX(a,b) ( (a) > (b) ? (a) : (b) )
107
FUZ_GetClockSpan(clock_t clockStart)108 static clock_t FUZ_GetClockSpan(clock_t clockStart)
109 {
110 return clock() - clockStart; /* works even if overflow; max span ~ 30 mn */
111 }
112
113
114 #define FUZ_rotl32(x,r) ((x << r) | (x >> (32 - r)))
FUZ_rand(unsigned int * src)115 unsigned int FUZ_rand(unsigned int* src)
116 {
117 U32 rand32 = *src;
118 rand32 *= prime1;
119 rand32 += prime2;
120 rand32 = FUZ_rotl32(rand32, 13);
121 *src = rand32;
122 return rand32 >> 5;
123 }
124
125
126 #define FUZ_RAND15BITS (FUZ_rand(seed) & 0x7FFF)
127 #define FUZ_RANDLENGTH ( (FUZ_rand(seed) & 3) ? (FUZ_rand(seed) % 15) : (FUZ_rand(seed) % 510) + 15)
FUZ_fillCompressibleNoiseBuffer(void * buffer,size_t bufferSize,double proba,U32 * seed)128 static void FUZ_fillCompressibleNoiseBuffer(void* buffer, size_t bufferSize, double proba, U32* seed)
129 {
130 BYTE* BBuffer = (BYTE*)buffer;
131 size_t pos = 0;
132 U32 P32 = (U32)(32768 * proba);
133
134 /* First Byte */
135 BBuffer[pos++] = (BYTE)(FUZ_rand(seed));
136
137 while (pos < bufferSize) {
138 /* Select : Literal (noise) or copy (within 64K) */
139 if (FUZ_RAND15BITS < P32) {
140 /* Copy (within 64K) */
141 size_t const lengthRand = FUZ_RANDLENGTH + 4;
142 size_t const length = MIN(lengthRand, bufferSize - pos);
143 size_t const end = pos + length;
144 size_t const offsetRand = FUZ_RAND15BITS + 1;
145 size_t const offset = MIN(offsetRand, pos);
146 size_t match = pos - offset;
147 while (pos < end) BBuffer[pos++] = BBuffer[match++];
148 } else {
149 /* Literal (noise) */
150 size_t const lengthRand = FUZ_RANDLENGTH + 4;
151 size_t const length = MIN(lengthRand, bufferSize - pos);
152 size_t const end = pos + length;
153 while (pos < end) BBuffer[pos++] = (BYTE)(FUZ_rand(seed) >> 5);
154 }
155 }
156 }
157
158
FUZ_highbit(U32 v32)159 static unsigned FUZ_highbit(U32 v32)
160 {
161 unsigned nbBits = 0;
162 if (v32==0) return 0;
163 while (v32) v32 >>= 1, nbBits ++;
164 return nbBits;
165 }
166
167
168 /*-*******************************************************
169 * Tests
170 *********************************************************/
171 #define CHECK_V(v,f) v = f; if (LZ4F_isError(v)) { fprintf(stderr, "%s\n", LZ4F_getErrorName(v)); goto _output_error; }
172 #define CHECK(f) { LZ4F_errorCode_t const CHECK_V(err_ , f); }
173
basicTests(U32 seed,double compressibility)174 int basicTests(U32 seed, double compressibility)
175 {
176 #define COMPRESSIBLE_NOISE_LENGTH (2 MB)
177 void* const CNBuffer = malloc(COMPRESSIBLE_NOISE_LENGTH);
178 size_t const cBuffSize = LZ4F_compressFrameBound(COMPRESSIBLE_NOISE_LENGTH, NULL);
179 void* const compressedBuffer = malloc(cBuffSize);
180 void* const decodedBuffer = malloc(COMPRESSIBLE_NOISE_LENGTH);
181 U32 randState = seed;
182 size_t cSize, testSize;
183 LZ4F_decompressionContext_t dCtx = NULL;
184 LZ4F_compressionContext_t cctx = NULL;
185 U64 crcOrig;
186 int basicTests_error = 0;
187 LZ4F_preferences_t prefs;
188 memset(&prefs, 0, sizeof(prefs));
189
190 if (!CNBuffer || !compressedBuffer || !decodedBuffer) {
191 DISPLAY("allocation error, not enough memory to start fuzzer tests \n");
192 goto _output_error;
193 }
194 FUZ_fillCompressibleNoiseBuffer(CNBuffer, COMPRESSIBLE_NOISE_LENGTH, compressibility, &randState);
195 crcOrig = XXH64(CNBuffer, COMPRESSIBLE_NOISE_LENGTH, 1);
196
197 /* LZ4F_compressBound() : special case : srcSize == 0 */
198 DISPLAYLEVEL(3, "LZ4F_compressBound(0) = ");
199 { size_t const cBound = LZ4F_compressBound(0, NULL);
200 if (cBound < 64 KB) goto _output_error;
201 DISPLAYLEVEL(3, " %u \n", (U32)cBound);
202 }
203
204 /* Special case : null-content frame */
205 testSize = 0;
206 DISPLAYLEVEL(3, "LZ4F_compressFrame, compress null content : ");
207 CHECK_V(cSize, LZ4F_compressFrame(compressedBuffer, LZ4F_compressFrameBound(testSize, NULL), CNBuffer, testSize, NULL));
208 DISPLAYLEVEL(3, "null content encoded into a %u bytes frame \n", (unsigned)cSize);
209
210 DISPLAYLEVEL(3, "LZ4F_createDecompressionContext \n");
211 CHECK ( LZ4F_createDecompressionContext(&dCtx, LZ4F_VERSION) );
212
213 DISPLAYLEVEL(3, "LZ4F_getFrameInfo on null-content frame (#157) \n");
214 { size_t avail_in = cSize;
215 LZ4F_frameInfo_t frame_info;
216 CHECK( LZ4F_getFrameInfo(dCtx, &frame_info, compressedBuffer, &avail_in) );
217 }
218
219 DISPLAYLEVEL(3, "LZ4F_freeDecompressionContext \n");
220 CHECK( LZ4F_freeDecompressionContext(dCtx) );
221 dCtx = NULL;
222
223 /* test one-pass frame compression */
224 testSize = COMPRESSIBLE_NOISE_LENGTH;
225
226 DISPLAYLEVEL(3, "LZ4F_compressFrame, using fast level -3 : ");
227 { LZ4F_preferences_t fastCompressPrefs;
228 memset(&fastCompressPrefs, 0, sizeof(fastCompressPrefs));
229 fastCompressPrefs.compressionLevel = -3;
230 CHECK_V(cSize, LZ4F_compressFrame(compressedBuffer, LZ4F_compressFrameBound(testSize, NULL), CNBuffer, testSize, &fastCompressPrefs));
231 DISPLAYLEVEL(3, "Compressed %u bytes into a %u bytes frame \n", (U32)testSize, (U32)cSize);
232 }
233
234 DISPLAYLEVEL(3, "LZ4F_compressFrame, using default preferences : ");
235 CHECK_V(cSize, LZ4F_compressFrame(compressedBuffer, LZ4F_compressFrameBound(testSize, NULL), CNBuffer, testSize, NULL));
236 DISPLAYLEVEL(3, "Compressed %u bytes into a %u bytes frame \n", (U32)testSize, (U32)cSize);
237
238 DISPLAYLEVEL(3, "Decompression test : \n");
239 { size_t decodedBufferSize = COMPRESSIBLE_NOISE_LENGTH;
240 size_t compressedBufferSize = cSize;
241
242 CHECK( LZ4F_createDecompressionContext(&dCtx, LZ4F_VERSION) );
243
244 DISPLAYLEVEL(3, "Single Pass decompression : ");
245 CHECK( LZ4F_decompress(dCtx, decodedBuffer, &decodedBufferSize, compressedBuffer, &compressedBufferSize, NULL) );
246 { U64 const crcDest = XXH64(decodedBuffer, decodedBufferSize, 1);
247 if (crcDest != crcOrig) goto _output_error; }
248 DISPLAYLEVEL(3, "Regenerated %u bytes \n", (U32)decodedBufferSize);
249
250 DISPLAYLEVEL(3, "Reusing decompression context \n");
251 { size_t const missingBytes = 4;
252 size_t iSize = compressedBufferSize - missingBytes;
253 const BYTE* cBuff = (const BYTE*) compressedBuffer;
254 BYTE* const ostart = (BYTE*)decodedBuffer;
255 BYTE* op = ostart;
256 BYTE* const oend = (BYTE*)decodedBuffer + COMPRESSIBLE_NOISE_LENGTH;
257 size_t decResult, oSize = COMPRESSIBLE_NOISE_LENGTH;
258 DISPLAYLEVEL(3, "Missing last %u bytes : ", (U32)missingBytes);
259 CHECK_V(decResult, LZ4F_decompress(dCtx, op, &oSize, cBuff, &iSize, NULL));
260 if (decResult != missingBytes) {
261 DISPLAY("%u bytes missing != %u bytes requested \n", (U32)missingBytes, (U32)decResult);
262 goto _output_error;
263 }
264 DISPLAYLEVEL(3, "indeed, requests %u bytes \n", (unsigned)decResult);
265 cBuff += iSize;
266 iSize = decResult;
267 op += oSize;
268 oSize = (size_t)(oend-op);
269 decResult = LZ4F_decompress(dCtx, op, &oSize, cBuff, &iSize, NULL);
270 if (decResult != 0) goto _output_error; /* should finish now */
271 op += oSize;
272 if (op>oend) { DISPLAY("decompression write overflow \n"); goto _output_error; }
273 { U64 const crcDest = XXH64(decodedBuffer, op-ostart, 1);
274 if (crcDest != crcOrig) goto _output_error;
275 } }
276
277 { size_t oSize = 0;
278 size_t iSize = 0;
279 LZ4F_frameInfo_t fi;
280 const BYTE* ip = (BYTE*)compressedBuffer;
281
282 DISPLAYLEVEL(3, "Start by feeding 0 bytes, to get next input size : ");
283 CHECK( LZ4F_decompress(dCtx, NULL, &oSize, ip, &iSize, NULL) );
284 //DISPLAYLEVEL(3, " %u \n", (unsigned)errorCode);
285 DISPLAYLEVEL(3, " OK \n");
286
287 DISPLAYLEVEL(3, "LZ4F_getFrameInfo on zero-size input : ");
288 { size_t nullSize = 0;
289 size_t const fiError = LZ4F_getFrameInfo(dCtx, &fi, ip, &nullSize);
290 if (LZ4F_getErrorCode(fiError) != LZ4F_ERROR_frameHeader_incomplete) {
291 DISPLAYLEVEL(3, "incorrect error : %s != ERROR_frameHeader_incomplete \n",
292 LZ4F_getErrorName(fiError));
293 goto _output_error;
294 }
295 DISPLAYLEVEL(3, " correctly failed : %s \n", LZ4F_getErrorName(fiError));
296 }
297
298 DISPLAYLEVEL(3, "LZ4F_getFrameInfo on not enough input : ");
299 { size_t inputSize = 6;
300 size_t const fiError = LZ4F_getFrameInfo(dCtx, &fi, ip, &inputSize);
301 if (LZ4F_getErrorCode(fiError) != LZ4F_ERROR_frameHeader_incomplete) {
302 DISPLAYLEVEL(3, "incorrect error : %s != ERROR_frameHeader_incomplete \n", LZ4F_getErrorName(fiError));
303 goto _output_error;
304 }
305 DISPLAYLEVEL(3, " correctly failed : %s \n", LZ4F_getErrorName(fiError));
306 }
307
308 DISPLAYLEVEL(3, "LZ4F_getFrameInfo on enough input : ");
309 iSize = 15 - iSize;
310 CHECK( LZ4F_getFrameInfo(dCtx, &fi, ip, &iSize) );
311 DISPLAYLEVEL(3, " correctly decoded \n");
312 ip += iSize;
313 }
314
315 DISPLAYLEVEL(3, "Decode a buggy input : ");
316 assert(COMPRESSIBLE_NOISE_LENGTH > 64);
317 assert(cSize > 48);
318 memcpy(decodedBuffer, (char*)compressedBuffer+16, 32); /* save correct data */
319 memcpy((char*)compressedBuffer+16, (const char*)decodedBuffer+32, 32); /* insert noise */
320 { size_t dbSize = COMPRESSIBLE_NOISE_LENGTH;
321 size_t cbSize = cSize;
322 size_t const decompressError = LZ4F_decompress(dCtx, decodedBuffer, &dbSize,
323 compressedBuffer, &cbSize,
324 NULL);
325 if (!LZ4F_isError(decompressError)) goto _output_error;
326 DISPLAYLEVEL(3, "error detected : %s \n", LZ4F_getErrorName(decompressError));
327 }
328 memcpy((char*)compressedBuffer+16, decodedBuffer, 32); /* restore correct data */
329
330 DISPLAYLEVEL(3, "Reset decompression context, since it's left in error state \n");
331 LZ4F_resetDecompressionContext(dCtx); /* always successful */
332
333 DISPLAYLEVEL(3, "Byte after byte : ");
334 { BYTE* const ostart = (BYTE*)decodedBuffer;
335 BYTE* op = ostart;
336 BYTE* const oend = (BYTE*)decodedBuffer + COMPRESSIBLE_NOISE_LENGTH;
337 const BYTE* ip = (const BYTE*) compressedBuffer;
338 const BYTE* const iend = ip + cSize;
339 while (ip < iend) {
340 size_t oSize = oend-op;
341 size_t iSize = 1;
342 CHECK( LZ4F_decompress(dCtx, op, &oSize, ip, &iSize, NULL) );
343 op += oSize;
344 ip += iSize;
345 }
346 { U64 const crcDest = XXH64(decodedBuffer, COMPRESSIBLE_NOISE_LENGTH, 1);
347 if (crcDest != crcOrig) goto _output_error; }
348 DISPLAYLEVEL(3, "Regenerated %u/%u bytes \n", (unsigned)(op-ostart), COMPRESSIBLE_NOISE_LENGTH);
349 }
350 }
351
352 DISPLAYLEVEL(3, "Using 64 KB block : ");
353 prefs.frameInfo.blockSizeID = LZ4F_max64KB;
354 prefs.frameInfo.contentChecksumFlag = LZ4F_contentChecksumEnabled;
355 CHECK_V(cSize, LZ4F_compressFrame(compressedBuffer, LZ4F_compressFrameBound(testSize, &prefs), CNBuffer, testSize, &prefs));
356 DISPLAYLEVEL(3, "Compressed %i bytes into a %i bytes frame \n", (int)testSize, (int)cSize);
357
358 DISPLAYLEVEL(3, "without checksum : ");
359 prefs.frameInfo.contentChecksumFlag = LZ4F_noContentChecksum;
360 CHECK_V(cSize, LZ4F_compressFrame(compressedBuffer, LZ4F_compressFrameBound(testSize, &prefs), CNBuffer, testSize, &prefs));
361 DISPLAYLEVEL(3, "Compressed %i bytes into a %i bytes frame \n", (int)testSize, (int)cSize);
362
363 DISPLAYLEVEL(3, "Using 256 KB block : ");
364 prefs.frameInfo.blockSizeID = LZ4F_max256KB;
365 prefs.frameInfo.contentChecksumFlag = LZ4F_contentChecksumEnabled;
366 CHECK_V(cSize, LZ4F_compressFrame(compressedBuffer, LZ4F_compressFrameBound(testSize, &prefs), CNBuffer, testSize, &prefs));
367 DISPLAYLEVEL(3, "Compressed %i bytes into a %i bytes frame \n", (int)testSize, (int)cSize);
368
369 DISPLAYLEVEL(3, "Decompression test : \n");
370 { size_t const decodedBufferSize = COMPRESSIBLE_NOISE_LENGTH;
371 unsigned const maxBits = FUZ_highbit((U32)decodedBufferSize);
372 BYTE* const ostart = (BYTE*)decodedBuffer;
373 BYTE* op = ostart;
374 BYTE* const oend = ostart + COMPRESSIBLE_NOISE_LENGTH;
375 const BYTE* ip = (const BYTE*)compressedBuffer;
376 const BYTE* const iend = (const BYTE*)compressedBuffer + cSize;
377
378 DISPLAYLEVEL(3, "random segment sizes : ");
379 while (ip < iend) {
380 unsigned const nbBits = FUZ_rand(&randState) % maxBits;
381 size_t iSize = (FUZ_rand(&randState) & ((1<<nbBits)-1)) + 1;
382 size_t oSize = oend-op;
383 if (iSize > (size_t)(iend-ip)) iSize = iend-ip;
384 CHECK( LZ4F_decompress(dCtx, op, &oSize, ip, &iSize, NULL) );
385 op += oSize;
386 ip += iSize;
387 }
388 { size_t const decodedSize = (size_t)(op - ostart);
389 U64 const crcDest = XXH64(decodedBuffer, decodedSize, 1);
390 if (crcDest != crcOrig) goto _output_error;
391 DISPLAYLEVEL(3, "Regenerated %u bytes \n", (U32)decodedSize);
392 }
393
394 CHECK( LZ4F_freeDecompressionContext(dCtx) );
395 dCtx = NULL;
396 }
397
398 DISPLAYLEVEL(3, "without checksum : ");
399 prefs.frameInfo.contentChecksumFlag = LZ4F_noContentChecksum;
400 CHECK_V(cSize, LZ4F_compressFrame(compressedBuffer, LZ4F_compressFrameBound(testSize, &prefs), CNBuffer, testSize, &prefs) );
401 DISPLAYLEVEL(3, "Compressed %i bytes into a %i bytes frame \n", (int)testSize, (int)cSize);
402
403 DISPLAYLEVEL(3, "Using 1 MB block : ");
404 prefs.frameInfo.blockSizeID = LZ4F_max1MB;
405 prefs.frameInfo.contentChecksumFlag = LZ4F_contentChecksumEnabled;
406 CHECK_V(cSize, LZ4F_compressFrame(compressedBuffer, LZ4F_compressFrameBound(testSize, &prefs), CNBuffer, testSize, &prefs) );
407 DISPLAYLEVEL(3, "Compressed %i bytes into a %i bytes frame \n", (int)testSize, (int)cSize);
408
409 DISPLAYLEVEL(3, "without frame checksum : ");
410 prefs.frameInfo.contentChecksumFlag = LZ4F_noContentChecksum;
411 CHECK_V(cSize, LZ4F_compressFrame(compressedBuffer, LZ4F_compressFrameBound(testSize, &prefs), CNBuffer, testSize, &prefs) );
412 DISPLAYLEVEL(3, "Compressed %i bytes into a %i bytes frame \n", (int)testSize, (int)cSize);
413
414 DISPLAYLEVEL(3, "Using 4 MB block : ");
415 prefs.frameInfo.blockSizeID = LZ4F_max4MB;
416 prefs.frameInfo.contentChecksumFlag = LZ4F_contentChecksumEnabled;
417 { size_t const dstCapacity = LZ4F_compressFrameBound(testSize, &prefs);
418 DISPLAYLEVEL(4, "dstCapacity = %u ; ", (U32)dstCapacity)
419 CHECK_V(cSize, LZ4F_compressFrame(compressedBuffer, dstCapacity, CNBuffer, testSize, &prefs) );
420 DISPLAYLEVEL(3, "Compressed %u bytes into a %u bytes frame \n", (U32)testSize, (U32)cSize);
421 }
422
423 DISPLAYLEVEL(3, "without frame checksum : ");
424 prefs.frameInfo.contentChecksumFlag = LZ4F_noContentChecksum;
425 { size_t const dstCapacity = LZ4F_compressFrameBound(testSize, &prefs);
426 DISPLAYLEVEL(4, "dstCapacity = %u ; ", (U32)dstCapacity)
427 CHECK_V(cSize, LZ4F_compressFrame(compressedBuffer, dstCapacity, CNBuffer, testSize, &prefs) );
428 DISPLAYLEVEL(3, "Compressed %u bytes into a %u bytes frame \n", (U32)testSize, (U32)cSize);
429 }
430
431 DISPLAYLEVEL(3, "LZ4F_compressFrame with block checksum : ");
432 memset(&prefs, 0, sizeof(prefs));
433 prefs.frameInfo.blockChecksumFlag = LZ4F_blockChecksumEnabled;
434 CHECK_V(cSize, LZ4F_compressFrame(compressedBuffer, LZ4F_compressFrameBound(testSize, &prefs), CNBuffer, testSize, &prefs) );
435 DISPLAYLEVEL(3, "Compressed %i bytes into a %i bytes frame \n", (int)testSize, (int)cSize);
436
437 DISPLAYLEVEL(3, "Decompress with block checksum : ");
438 { size_t iSize = cSize;
439 size_t decodedSize = COMPRESSIBLE_NOISE_LENGTH;
440 LZ4F_decompressionContext_t dctx;
441 CHECK( LZ4F_createDecompressionContext(&dctx, LZ4F_VERSION) );
442 CHECK( LZ4F_decompress(dctx, decodedBuffer, &decodedSize, compressedBuffer, &iSize, NULL) );
443 if (decodedSize != testSize) goto _output_error;
444 if (iSize != cSize) goto _output_error;
445 { U64 const crcDest = XXH64(decodedBuffer, decodedSize, 1);
446 U64 const crcSrc = XXH64(CNBuffer, testSize, 1);
447 if (crcDest != crcSrc) goto _output_error;
448 }
449 DISPLAYLEVEL(3, "Regenerated %u bytes \n", (U32)decodedSize);
450
451 CHECK( LZ4F_freeDecompressionContext(dctx) );
452 }
453
454 /* frame content size tests */
455 { size_t cErr;
456 BYTE* const ostart = (BYTE*)compressedBuffer;
457 BYTE* op = ostart;
458 CHECK( LZ4F_createCompressionContext(&cctx, LZ4F_VERSION) );
459
460 DISPLAYLEVEL(3, "compress without frameSize : ");
461 memset(&(prefs.frameInfo), 0, sizeof(prefs.frameInfo));
462 CHECK_V(cErr, LZ4F_compressBegin(cctx, compressedBuffer, testSize, &prefs));
463 op += cErr;
464 CHECK_V(cErr, LZ4F_compressUpdate(cctx, op, LZ4F_compressBound(testSize, &prefs), CNBuffer, testSize, NULL));
465 op += cErr;
466 CHECK( LZ4F_compressEnd(cctx, compressedBuffer, testSize, NULL) );
467 DISPLAYLEVEL(3, "Compressed %i bytes into a %i bytes frame \n", (int)testSize, (int)(op-ostart));
468
469 DISPLAYLEVEL(3, "compress with frameSize : ");
470 prefs.frameInfo.contentSize = testSize;
471 op = ostart;
472 CHECK_V(cErr, LZ4F_compressBegin(cctx, compressedBuffer, testSize, &prefs));
473 op += cErr;
474 CHECK_V(cErr, LZ4F_compressUpdate(cctx, op, LZ4F_compressBound(testSize, &prefs), CNBuffer, testSize, NULL));
475 op += cErr;
476 CHECK( LZ4F_compressEnd(cctx, compressedBuffer, testSize, NULL) );
477 DISPLAYLEVEL(3, "Compressed %i bytes into a %i bytes frame \n", (int)testSize, (int)(op-ostart));
478
479 DISPLAYLEVEL(3, "compress with wrong frameSize : ");
480 prefs.frameInfo.contentSize = testSize+1;
481 op = ostart;
482 CHECK_V(cErr, LZ4F_compressBegin(cctx, compressedBuffer, testSize, &prefs));
483 op += cErr;
484 CHECK_V(cErr, LZ4F_compressUpdate(cctx, op, LZ4F_compressBound(testSize, &prefs), CNBuffer, testSize, NULL));
485 op += cErr;
486 cErr = LZ4F_compressEnd(cctx, op, testSize, NULL);
487 if (!LZ4F_isError(cErr)) goto _output_error;
488 DISPLAYLEVEL(3, "Error correctly detected : %s \n", LZ4F_getErrorName(cErr));
489
490 CHECK( LZ4F_freeCompressionContext(cctx) );
491 cctx = NULL;
492 }
493
494 /* dictID tests */
495 { size_t cErr;
496 U32 const dictID = 0x99;
497 CHECK( LZ4F_createCompressionContext(&cctx, LZ4F_VERSION) );
498
499 DISPLAYLEVEL(3, "insert a dictID : ");
500 memset(&prefs.frameInfo, 0, sizeof(prefs.frameInfo));
501 prefs.frameInfo.dictID = dictID;
502 CHECK_V(cErr, LZ4F_compressBegin(cctx, compressedBuffer, testSize, &prefs));
503 DISPLAYLEVEL(3, "created frame header of size %i bytes \n", (int)cErr);
504
505 DISPLAYLEVEL(3, "read a dictID : ");
506 CHECK( LZ4F_createDecompressionContext(&dCtx, LZ4F_VERSION) );
507 memset(&prefs.frameInfo, 0, sizeof(prefs.frameInfo));
508 CHECK( LZ4F_getFrameInfo(dCtx, &prefs.frameInfo, compressedBuffer, &cErr) );
509 if (prefs.frameInfo.dictID != dictID) goto _output_error;
510 DISPLAYLEVEL(3, "%u \n", (U32)prefs.frameInfo.dictID);
511
512 CHECK( LZ4F_freeDecompressionContext(dCtx) ); dCtx = NULL;
513 CHECK( LZ4F_freeCompressionContext(cctx) ); cctx = NULL;
514 }
515
516 /* Dictionary compression test */
517 { size_t const dictSize = 63 KB;
518 size_t const dstCapacity = LZ4F_compressFrameBound(dictSize, NULL);
519 size_t cSizeNoDict, cSizeWithDict;
520 LZ4F_CDict* const cdict = LZ4F_createCDict(CNBuffer, dictSize);
521 if (cdict == NULL) goto _output_error;
522 CHECK( LZ4F_createCompressionContext(&cctx, LZ4F_VERSION) );
523
524 DISPLAYLEVEL(3, "LZ4F_compressFrame_usingCDict, with NULL dict : ");
525 CHECK_V(cSizeNoDict,
526 LZ4F_compressFrame_usingCDict(cctx, compressedBuffer, dstCapacity,
527 CNBuffer, dictSize,
528 NULL, NULL) );
529 DISPLAYLEVEL(3, "%u bytes \n", (unsigned)cSizeNoDict);
530
531 CHECK( LZ4F_freeCompressionContext(cctx) );
532 CHECK( LZ4F_createCompressionContext(&cctx, LZ4F_VERSION) );
533 DISPLAYLEVEL(3, "LZ4F_compressFrame_usingCDict, with dict : ");
534 CHECK_V(cSizeWithDict,
535 LZ4F_compressFrame_usingCDict(cctx, compressedBuffer, dstCapacity,
536 CNBuffer, dictSize,
537 cdict, NULL) );
538 DISPLAYLEVEL(3, "compressed %u bytes into %u bytes \n",
539 (unsigned)dictSize, (unsigned)cSizeWithDict);
540 if (cSizeWithDict >= cSizeNoDict) goto _output_error; /* must be more efficient */
541 crcOrig = XXH64(CNBuffer, dictSize, 0);
542
543 DISPLAYLEVEL(3, "LZ4F_decompress_usingDict : ");
544 { LZ4F_dctx* dctx;
545 size_t decodedSize = COMPRESSIBLE_NOISE_LENGTH;
546 size_t compressedSize = cSizeWithDict;
547 CHECK( LZ4F_createDecompressionContext(&dctx, LZ4F_VERSION) );
548 CHECK( LZ4F_decompress_usingDict(dctx,
549 decodedBuffer, &decodedSize,
550 compressedBuffer, &compressedSize,
551 CNBuffer, dictSize,
552 NULL) );
553 if (compressedSize != cSizeWithDict) goto _output_error;
554 if (decodedSize != dictSize) goto _output_error;
555 { U64 const crcDest = XXH64(decodedBuffer, decodedSize, 0);
556 if (crcDest != crcOrig) goto _output_error; }
557 DISPLAYLEVEL(3, "Regenerated %u bytes \n", (U32)decodedSize);
558 CHECK( LZ4F_freeDecompressionContext(dctx) );
559 }
560
561 DISPLAYLEVEL(3, "LZ4F_compressFrame_usingCDict, with dict, negative level : ");
562 { size_t cSizeLevelMax;
563 LZ4F_preferences_t cParams;
564 memset(&cParams, 0, sizeof(cParams));
565 cParams.compressionLevel = -3;
566 CHECK_V(cSizeLevelMax,
567 LZ4F_compressFrame_usingCDict(cctx, compressedBuffer, dstCapacity,
568 CNBuffer, dictSize,
569 cdict, &cParams) );
570 DISPLAYLEVEL(3, "%u bytes \n", (unsigned)cSizeLevelMax);
571 }
572
573 DISPLAYLEVEL(3, "LZ4F_compressFrame_usingCDict, with dict, level max : ");
574 { size_t cSizeLevelMax;
575 LZ4F_preferences_t cParams;
576 memset(&cParams, 0, sizeof(cParams));
577 cParams.compressionLevel = LZ4F_compressionLevel_max();
578 CHECK_V(cSizeLevelMax,
579 LZ4F_compressFrame_usingCDict(cctx, compressedBuffer, dstCapacity,
580 CNBuffer, dictSize,
581 cdict, &cParams) );
582 DISPLAYLEVEL(3, "%u bytes \n", (unsigned)cSizeLevelMax);
583 }
584
585 DISPLAYLEVEL(3, "LZ4F_compressFrame_usingCDict, multiple linked blocks : ");
586 { size_t cSizeContiguous;
587 size_t const inSize = dictSize * 3;
588 size_t const outCapacity = LZ4F_compressFrameBound(inSize, NULL);
589 LZ4F_preferences_t cParams;
590 memset(&cParams, 0, sizeof(cParams));
591 cParams.frameInfo.blockMode = LZ4F_blockLinked;
592 cParams.frameInfo.blockSizeID = LZ4F_max64KB;
593 CHECK_V(cSizeContiguous,
594 LZ4F_compressFrame_usingCDict(cctx, compressedBuffer, outCapacity,
595 CNBuffer, inSize,
596 cdict, &cParams) );
597 DISPLAYLEVEL(3, "compressed %u bytes into %u bytes \n",
598 (unsigned)inSize, (unsigned)cSizeContiguous);
599
600 DISPLAYLEVEL(3, "LZ4F_decompress_usingDict on multiple linked blocks : ");
601 { LZ4F_dctx* dctx;
602 size_t decodedSize = COMPRESSIBLE_NOISE_LENGTH;
603 size_t compressedSize = cSizeContiguous;
604 CHECK( LZ4F_createDecompressionContext(&dctx, LZ4F_VERSION) );
605 CHECK( LZ4F_decompress_usingDict(dctx,
606 decodedBuffer, &decodedSize,
607 compressedBuffer, &compressedSize,
608 CNBuffer, dictSize,
609 NULL) );
610 if (compressedSize != cSizeContiguous) goto _output_error;
611 if (decodedSize != inSize) goto _output_error;
612 crcOrig = XXH64(CNBuffer, inSize, 0);
613 { U64 const crcDest = XXH64(decodedBuffer, decodedSize, 0);
614 if (crcDest != crcOrig) goto _output_error; }
615 DISPLAYLEVEL(3, "Regenerated %u bytes \n", (U32)decodedSize);
616 CHECK( LZ4F_freeDecompressionContext(dctx) );
617 }
618 }
619
620
621 DISPLAYLEVEL(3, "LZ4F_compressFrame_usingCDict, multiple independent blocks : ");
622 { size_t cSizeIndep;
623 size_t const inSize = dictSize * 3;
624 size_t const outCapacity = LZ4F_compressFrameBound(inSize, NULL);
625 LZ4F_preferences_t cParams;
626 memset(&cParams, 0, sizeof(cParams));
627 cParams.frameInfo.blockMode = LZ4F_blockIndependent;
628 cParams.frameInfo.blockSizeID = LZ4F_max64KB;
629 CHECK_V(cSizeIndep,
630 LZ4F_compressFrame_usingCDict(cctx, compressedBuffer, outCapacity,
631 CNBuffer, inSize,
632 cdict, &cParams) );
633 DISPLAYLEVEL(3, "compressed %u bytes into %u bytes \n",
634 (unsigned)inSize, (unsigned)cSizeIndep);
635
636 DISPLAYLEVEL(3, "LZ4F_decompress_usingDict on multiple independent blocks : ");
637 { LZ4F_dctx* dctx;
638 size_t decodedSize = COMPRESSIBLE_NOISE_LENGTH;
639 size_t compressedSize = cSizeIndep;
640 CHECK( LZ4F_createDecompressionContext(&dctx, LZ4F_VERSION) );
641 CHECK( LZ4F_decompress_usingDict(dctx,
642 decodedBuffer, &decodedSize,
643 compressedBuffer, &compressedSize,
644 CNBuffer, dictSize,
645 NULL) );
646 if (compressedSize != cSizeIndep) goto _output_error;
647 if (decodedSize != inSize) goto _output_error;
648 crcOrig = XXH64(CNBuffer, inSize, 0);
649 { U64 const crcDest = XXH64(decodedBuffer, decodedSize, 0);
650 if (crcDest != crcOrig) goto _output_error; }
651 DISPLAYLEVEL(3, "Regenerated %u bytes \n", (U32)decodedSize);
652 CHECK( LZ4F_freeDecompressionContext(dctx) );
653 }
654 }
655
656 LZ4F_freeCDict(cdict);
657 CHECK( LZ4F_freeCompressionContext(cctx) ); cctx = NULL;
658 }
659
660
661 DISPLAYLEVEL(3, "Skippable frame test : \n");
662 { size_t decodedBufferSize = COMPRESSIBLE_NOISE_LENGTH;
663 unsigned maxBits = FUZ_highbit((U32)decodedBufferSize);
664 BYTE* op = (BYTE*)decodedBuffer;
665 BYTE* const oend = (BYTE*)decodedBuffer + COMPRESSIBLE_NOISE_LENGTH;
666 BYTE* ip = (BYTE*)compressedBuffer;
667 BYTE* iend = (BYTE*)compressedBuffer + cSize + 8;
668
669 CHECK( LZ4F_createDecompressionContext(&dCtx, LZ4F_VERSION) );
670
671 /* generate skippable frame */
672 FUZ_writeLE32(ip, LZ4F_MAGIC_SKIPPABLE_START);
673 FUZ_writeLE32(ip+4, (U32)cSize);
674
675 DISPLAYLEVEL(3, "random segment sizes : \n");
676 while (ip < iend) {
677 unsigned nbBits = FUZ_rand(&randState) % maxBits;
678 size_t iSize = (FUZ_rand(&randState) & ((1<<nbBits)-1)) + 1;
679 size_t oSize = oend-op;
680 if (iSize > (size_t)(iend-ip)) iSize = iend-ip;
681 CHECK( LZ4F_decompress(dCtx, op, &oSize, ip, &iSize, NULL) );
682 op += oSize;
683 ip += iSize;
684 }
685 DISPLAYLEVEL(3, "Skipped %i bytes \n", (int)decodedBufferSize);
686
687 /* generate zero-size skippable frame */
688 DISPLAYLEVEL(3, "zero-size skippable frame\n");
689 ip = (BYTE*)compressedBuffer;
690 op = (BYTE*)decodedBuffer;
691 FUZ_writeLE32(ip, LZ4F_MAGIC_SKIPPABLE_START+1);
692 FUZ_writeLE32(ip+4, 0);
693 iend = ip+8;
694
695 while (ip < iend) {
696 unsigned const nbBits = FUZ_rand(&randState) % maxBits;
697 size_t iSize = (FUZ_rand(&randState) & ((1<<nbBits)-1)) + 1;
698 size_t oSize = oend-op;
699 if (iSize > (size_t)(iend-ip)) iSize = iend-ip;
700 CHECK( LZ4F_decompress(dCtx, op, &oSize, ip, &iSize, NULL) );
701 op += oSize;
702 ip += iSize;
703 }
704 DISPLAYLEVEL(3, "Skipped %i bytes \n", (int)(ip - (BYTE*)compressedBuffer - 8));
705
706 DISPLAYLEVEL(3, "Skippable frame header complete in first call \n");
707 ip = (BYTE*)compressedBuffer;
708 op = (BYTE*)decodedBuffer;
709 FUZ_writeLE32(ip, LZ4F_MAGIC_SKIPPABLE_START+2);
710 FUZ_writeLE32(ip+4, 10);
711 iend = ip+18;
712 while (ip < iend) {
713 size_t iSize = 10;
714 size_t oSize = 10;
715 if (iSize > (size_t)(iend-ip)) iSize = iend-ip;
716 CHECK( LZ4F_decompress(dCtx, op, &oSize, ip, &iSize, NULL) );
717 op += oSize;
718 ip += iSize;
719 }
720 DISPLAYLEVEL(3, "Skipped %i bytes \n", (int)(ip - (BYTE*)compressedBuffer - 8));
721 }
722
723 DISPLAY("Basic tests completed \n");
724 _end:
725 free(CNBuffer);
726 free(compressedBuffer);
727 free(decodedBuffer);
728 LZ4F_freeDecompressionContext(dCtx); dCtx = NULL;
729 LZ4F_freeCompressionContext(cctx); cctx = NULL;
730 return basicTests_error;
731
732 _output_error:
733 basicTests_error = 1;
734 DISPLAY("Error detected ! \n");
735 goto _end;
736 }
737
738
locateBuffDiff(const void * buff1,const void * buff2,size_t size,unsigned nonContiguous)739 static void locateBuffDiff(const void* buff1, const void* buff2, size_t size, unsigned nonContiguous)
740 {
741 size_t p=0;
742 const BYTE* b1=(const BYTE*)buff1;
743 const BYTE* b2=(const BYTE*)buff2;
744 DISPLAY("locateBuffDiff: looking for error position \n");
745 if (nonContiguous) {
746 DISPLAY("mode %u: non-contiguous output (%zu bytes), cannot search \n", nonContiguous, size);
747 return;
748 }
749 while (p < size && b1[p]==b2[p]) p++;
750 if (p != size) {
751 DISPLAY("Error at pos %i/%i : %02X != %02X \n", (int)p, (int)size, b1[p], b2[p]);
752 }
753 }
754
755
fuzzerTests(U32 seed,unsigned nbTests,unsigned startTest,double compressibility,U32 duration_s)756 int fuzzerTests(U32 seed, unsigned nbTests, unsigned startTest, double compressibility, U32 duration_s)
757 {
758 unsigned testResult = 0;
759 unsigned testNb = 0;
760 size_t const srcDataLength = 9 MB; /* needs to be > 2x4MB to test large blocks */
761 void* srcBuffer = NULL;
762 size_t const compressedBufferSize = LZ4F_compressFrameBound(srcDataLength, NULL);
763 void* compressedBuffer = NULL;
764 void* decodedBuffer = NULL;
765 U32 coreRand = seed;
766 LZ4F_decompressionContext_t dCtx = NULL;
767 LZ4F_compressionContext_t cCtx = NULL;
768 size_t result;
769 clock_t const startClock = clock();
770 clock_t const clockDuration = duration_s * CLOCKS_PER_SEC;
771 # undef CHECK
772 # define CHECK(cond, ...) if (cond) { DISPLAY("Error => "); DISPLAY(__VA_ARGS__); \
773 DISPLAY(" (seed %u, test nb %u) \n", seed, testNb); goto _output_error; }
774
775 /* Create buffers */
776 result = LZ4F_createDecompressionContext(&dCtx, LZ4F_VERSION);
777 CHECK(LZ4F_isError(result), "Allocation failed (error %i)", (int)result);
778 result = LZ4F_createCompressionContext(&cCtx, LZ4F_VERSION);
779 CHECK(LZ4F_isError(result), "Allocation failed (error %i)", (int)result);
780 srcBuffer = malloc(srcDataLength);
781 CHECK(srcBuffer==NULL, "srcBuffer Allocation failed");
782 compressedBuffer = malloc(compressedBufferSize);
783 CHECK(compressedBuffer==NULL, "compressedBuffer Allocation failed");
784 decodedBuffer = calloc(1, srcDataLength); /* calloc avoids decodedBuffer being considered "garbage" by scan-build */
785 CHECK(decodedBuffer==NULL, "decodedBuffer Allocation failed");
786 FUZ_fillCompressibleNoiseBuffer(srcBuffer, srcDataLength, compressibility, &coreRand);
787
788 /* jump to requested testNb */
789 for (testNb =0; (testNb < startTest); testNb++) (void)FUZ_rand(&coreRand); /* sync randomizer */
790
791 /* main fuzzer test loop */
792 for ( ; (testNb < nbTests) || (clockDuration > FUZ_GetClockSpan(startClock)) ; testNb++) {
793 U32 randState = coreRand ^ prime1;
794 unsigned const srcBits = (FUZ_rand(&randState) % (FUZ_highbit((U32)(srcDataLength-1)) - 1)) + 1;
795 size_t const srcSize = (FUZ_rand(&randState) & ((1<<srcBits)-1)) + 1;
796 size_t const srcStartId = FUZ_rand(&randState) % (srcDataLength - srcSize);
797 const BYTE* const srcStart = (const BYTE*)srcBuffer + srcStartId;
798 unsigned const neverFlush = (FUZ_rand(&randState) & 15) == 1;
799 U64 const crcOrig = XXH64(srcStart, srcSize, 1);
800 LZ4F_preferences_t prefs;
801 const LZ4F_preferences_t* prefsPtr = &prefs;
802 size_t cSize;
803
804 (void)FUZ_rand(&coreRand); /* update seed */
805 memset(&prefs, 0, sizeof(prefs));
806 prefs.frameInfo.blockMode = (LZ4F_blockMode_t)(FUZ_rand(&randState) & 1);
807 prefs.frameInfo.blockSizeID = (LZ4F_blockSizeID_t)(4 + (FUZ_rand(&randState) & 3));
808 prefs.frameInfo.blockChecksumFlag = (LZ4F_blockChecksum_t)(FUZ_rand(&randState) & 1);
809 prefs.frameInfo.contentChecksumFlag = (LZ4F_contentChecksum_t)(FUZ_rand(&randState) & 1);
810 prefs.frameInfo.contentSize = ((FUZ_rand(&randState) & 0xF) == 1) ? srcSize : 0;
811 prefs.autoFlush = neverFlush ? 0 : (FUZ_rand(&randState) & 7) == 2;
812 prefs.compressionLevel = -5 + (int)(FUZ_rand(&randState) % 11);
813 if ((FUZ_rand(&randState) & 0xF) == 1) prefsPtr = NULL;
814
815 DISPLAYUPDATE(2, "\r%5u ", testNb);
816
817 if ((FUZ_rand(&randState) & 0xFFF) == 0) {
818 /* create a skippable frame (rare case) */
819 BYTE* op = (BYTE*)compressedBuffer;
820 FUZ_writeLE32(op, LZ4F_MAGIC_SKIPPABLE_START + (FUZ_rand(&randState) & 15));
821 FUZ_writeLE32(op+4, (U32)srcSize);
822 cSize = srcSize+8;
823 } else if ((FUZ_rand(&randState) & 0xF) == 2) { /* single pass compression (simple) */
824 cSize = LZ4F_compressFrame(compressedBuffer, LZ4F_compressFrameBound(srcSize, prefsPtr), srcStart, srcSize, prefsPtr);
825 CHECK(LZ4F_isError(cSize), "LZ4F_compressFrame failed : error %i (%s)", (int)cSize, LZ4F_getErrorName(cSize));
826 } else { /* multi-segments compression */
827 const BYTE* ip = srcStart;
828 const BYTE* const iend = srcStart + srcSize;
829 BYTE* op = (BYTE*)compressedBuffer;
830 BYTE* const oend = op + (neverFlush ? LZ4F_compressFrameBound(srcSize, prefsPtr) : compressedBufferSize); /* when flushes are possible, can't guarantee a max compressed size */
831 unsigned const maxBits = FUZ_highbit((U32)srcSize);
832 LZ4F_compressOptions_t cOptions;
833 memset(&cOptions, 0, sizeof(cOptions));
834 result = LZ4F_compressBegin(cCtx, op, oend-op, prefsPtr);
835 CHECK(LZ4F_isError(result), "Compression header failed (error %i)", (int)result);
836 op += result;
837 while (ip < iend) {
838 unsigned const nbBitsSeg = FUZ_rand(&randState) % maxBits;
839 size_t const sampleMax = (FUZ_rand(&randState) & ((1<<nbBitsSeg)-1)) + 1;
840 size_t const iSize = MIN(sampleMax, (size_t)(iend-ip));
841 size_t const oSize = LZ4F_compressBound(iSize, prefsPtr);
842 cOptions.stableSrc = ((FUZ_rand(&randState) & 3) == 1);
843 DISPLAYLEVEL(6, "Sending %zi bytes to compress (stableSrc:%u) \n",
844 iSize, cOptions.stableSrc);
845
846 result = LZ4F_compressUpdate(cCtx, op, oSize, ip, iSize, &cOptions);
847 CHECK(LZ4F_isError(result), "Compression failed (error %i : %s)", (int)result, LZ4F_getErrorName(result));
848 op += result;
849 ip += iSize;
850
851 { unsigned const forceFlush = neverFlush ? 0 : ((FUZ_rand(&randState) & 3) == 1);
852 if (forceFlush) {
853 result = LZ4F_flush(cCtx, op, oend-op, &cOptions);
854 CHECK(LZ4F_isError(result), "Compression failed (error %i)", (int)result);
855 op += result;
856 } }
857 }
858 CHECK(op>=oend, "LZ4F_compressFrameBound overflow");
859 result = LZ4F_compressEnd(cCtx, op, oend-op, &cOptions);
860 CHECK(LZ4F_isError(result), "Compression completion failed (error %i : %s)", (int)result, LZ4F_getErrorName(result));
861 op += result;
862 cSize = op-(BYTE*)compressedBuffer;
863 DISPLAYLEVEL(5, "\nCompressed %u bytes into %u \n", (U32)srcSize, (U32)cSize);
864 }
865
866 /* multi-segments decompression */
867 { const BYTE* ip = (const BYTE*)compressedBuffer;
868 const BYTE* const iend = ip + cSize;
869 BYTE* op = (BYTE*)decodedBuffer;
870 BYTE* const oend = op + srcDataLength;
871 unsigned const suggestedBits = FUZ_highbit((U32)cSize);
872 unsigned const maxBits = MAX(3, suggestedBits);
873 unsigned const nonContiguousDst = FUZ_rand(&randState) % 3; /* 0 : contiguous; 1 : non-contiguous; 2 : dst overwritten */
874 size_t totalOut = 0;
875 XXH64_state_t xxh64;
876 XXH64_reset(&xxh64, 1);
877 while (ip < iend) {
878 unsigned const nbBitsI = (FUZ_rand(&randState) % (maxBits-1)) + 1;
879 unsigned const nbBitsO = (FUZ_rand(&randState) % (maxBits)) + 1;
880 size_t const iSizeMax = (FUZ_rand(&randState) & ((1<<nbBitsI)-1)) + 1;
881 size_t iSize = MIN(iSizeMax, (size_t)(iend-ip));
882 size_t const oSizeMax = (FUZ_rand(&randState) & ((1<<nbBitsO)-1)) + 2;
883 size_t oSize = MIN(oSizeMax, (size_t)(oend-op));
884 LZ4F_decompressOptions_t dOptions;
885 memset(&dOptions, 0, sizeof(dOptions));
886 dOptions.stableDst = FUZ_rand(&randState) & 1;
887 if (nonContiguousDst==2) dOptions.stableDst = 0; /* overwrite mode */
888 result = LZ4F_decompress(dCtx, op, &oSize, ip, &iSize, &dOptions);
889 if (LZ4F_getErrorCode(result) == LZ4F_ERROR_contentChecksum_invalid)
890 locateBuffDiff(srcStart, decodedBuffer, srcSize, nonContiguousDst);
891 CHECK(LZ4F_isError(result), "Decompression failed (error %i:%s)", (int)result, LZ4F_getErrorName(result));
892 XXH64_update(&xxh64, op, (U32)oSize);
893 totalOut += oSize;
894 op += oSize;
895 ip += iSize;
896 op += nonContiguousDst;
897 if (nonContiguousDst==2) op = (BYTE*)decodedBuffer; /* overwritten destination */
898 }
899 CHECK(result != 0, "Frame decompression failed (error %i)", (int)result);
900 if (totalOut) { /* otherwise, it's a skippable frame */
901 U64 const crcDecoded = XXH64_digest(&xxh64);
902 if (crcDecoded != crcOrig) locateBuffDiff(srcStart, decodedBuffer, srcSize, nonContiguousDst);
903 CHECK(crcDecoded != crcOrig, "Decompression corruption");
904 }
905 }
906 }
907
908 DISPLAYLEVEL(2, "\rAll tests completed \n");
909
910 _end:
911 LZ4F_freeDecompressionContext(dCtx);
912 LZ4F_freeCompressionContext(cCtx);
913 free(srcBuffer);
914 free(compressedBuffer);
915 free(decodedBuffer);
916
917 if (use_pause) {
918 DISPLAY("press enter to finish \n");
919 (void)getchar();
920 }
921 return testResult;
922
923 _output_error:
924 testResult = 1;
925 goto _end;
926 }
927
928
FUZ_usage(const char * programName)929 int FUZ_usage(const char* programName)
930 {
931 DISPLAY( "Usage :\n");
932 DISPLAY( " %s [args]\n", programName);
933 DISPLAY( "\n");
934 DISPLAY( "Arguments :\n");
935 DISPLAY( " -i# : Nb of tests (default:%u) \n", nbTestsDefault);
936 DISPLAY( " -T# : Duration of tests, in seconds (default: use Nb of tests) \n");
937 DISPLAY( " -s# : Select seed (default:prompt user)\n");
938 DISPLAY( " -t# : Select starting test number (default:0)\n");
939 DISPLAY( " -P# : Select compressibility in %% (default:%i%%)\n", FUZ_COMPRESSIBILITY_DEFAULT);
940 DISPLAY( " -v : verbose\n");
941 DISPLAY( " -h : display help and exit\n");
942 return 0;
943 }
944
945
main(int argc,const char ** argv)946 int main(int argc, const char** argv)
947 {
948 U32 seed=0;
949 int seedset=0;
950 int argNb;
951 int nbTests = nbTestsDefault;
952 int testNb = 0;
953 int proba = FUZ_COMPRESSIBILITY_DEFAULT;
954 int result=0;
955 U32 duration=0;
956 const char* const programName = argv[0];
957
958 /* Check command line */
959 for (argNb=1; argNb<argc; argNb++) {
960 const char* argument = argv[argNb];
961
962 if(!argument) continue; /* Protection if argument empty */
963
964 /* Decode command (note : aggregated short commands are allowed) */
965 if (argument[0]=='-') {
966 if (!strcmp(argument, "--no-prompt")) {
967 no_prompt=1;
968 seedset=1;
969 displayLevel=1;
970 continue;
971 }
972 argument++;
973
974 while (*argument!=0) {
975 switch(*argument)
976 {
977 case 'h':
978 return FUZ_usage(programName);
979 case 'v':
980 argument++;
981 displayLevel++;
982 break;
983 case 'q':
984 argument++;
985 displayLevel--;
986 break;
987 case 'p': /* pause at the end */
988 argument++;
989 use_pause = 1;
990 break;
991
992 case 'i':
993 argument++;
994 nbTests=0; duration=0;
995 while ((*argument>='0') && (*argument<='9')) {
996 nbTests *= 10;
997 nbTests += *argument - '0';
998 argument++;
999 }
1000 break;
1001
1002 case 'T':
1003 argument++;
1004 nbTests = 0; duration = 0;
1005 for (;;) {
1006 switch(*argument)
1007 {
1008 case 'm': duration *= 60; argument++; continue;
1009 case 's':
1010 case 'n': argument++; continue;
1011 case '0':
1012 case '1':
1013 case '2':
1014 case '3':
1015 case '4':
1016 case '5':
1017 case '6':
1018 case '7':
1019 case '8':
1020 case '9': duration *= 10; duration += *argument++ - '0'; continue;
1021 }
1022 break;
1023 }
1024 break;
1025
1026 case 's':
1027 argument++;
1028 seed=0;
1029 seedset=1;
1030 while ((*argument>='0') && (*argument<='9')) {
1031 seed *= 10;
1032 seed += *argument - '0';
1033 argument++;
1034 }
1035 break;
1036 case 't':
1037 argument++;
1038 testNb=0;
1039 while ((*argument>='0') && (*argument<='9')) {
1040 testNb *= 10;
1041 testNb += *argument - '0';
1042 argument++;
1043 }
1044 break;
1045 case 'P': /* compressibility % */
1046 argument++;
1047 proba=0;
1048 while ((*argument>='0') && (*argument<='9')) {
1049 proba *= 10;
1050 proba += *argument - '0';
1051 argument++;
1052 }
1053 if (proba<0) proba=0;
1054 if (proba>100) proba=100;
1055 break;
1056 default:
1057 ;
1058 return FUZ_usage(programName);
1059 }
1060 }
1061 }
1062 }
1063
1064 /* Get Seed */
1065 DISPLAY("Starting lz4frame tester (%i-bits, %s)\n", (int)(sizeof(size_t)*8), LZ4_VERSION_STRING);
1066
1067 if (!seedset) {
1068 time_t const t = time(NULL);
1069 U32 const h = XXH32(&t, sizeof(t), 1);
1070 seed = h % 10000;
1071 }
1072 DISPLAY("Seed = %u\n", seed);
1073 if (proba!=FUZ_COMPRESSIBILITY_DEFAULT) DISPLAY("Compressibility : %i%%\n", proba);
1074
1075 if (nbTests<=0) nbTests=1;
1076
1077 if (testNb==0) result = basicTests(seed, ((double)proba) / 100);
1078 if (result) return 1;
1079 return fuzzerTests(seed, nbTests, testNb, ((double)proba) / 100, duration);
1080 }
1081