1 /*
2 frameTest - test tool for lz4frame
3 Copyright (C) Yann Collet 2014-2020
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 : 26451) /* disable: Arithmetic overflow */
31 # pragma warning(disable : 4127) /* disable: C4127: conditional expression is constant */
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" /* included 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 #define LZ4_STATIC_LINKING_ONLY /* LZ4_DISTANCE_MAX */
50 #include "lz4.h" /* LZ4_VERSION_STRING */
51 #define XXH_STATIC_LINKING_ONLY
52 #include "xxhash.h" /* XXH64 */
53
54
55 /* unoptimized version; solves endianness & alignment issues */
FUZ_writeLE32(void * dstVoidPtr,U32 value32)56 static void FUZ_writeLE32 (void* dstVoidPtr, U32 value32)
57 {
58 BYTE* const dstPtr = (BYTE*)dstVoidPtr;
59 dstPtr[0] = (BYTE) value32;
60 dstPtr[1] = (BYTE)(value32 >> 8);
61 dstPtr[2] = (BYTE)(value32 >> 16);
62 dstPtr[3] = (BYTE)(value32 >> 24);
63 }
64
65
66 /*-************************************
67 * Constants
68 **************************************/
69 #define KB *(1U<<10)
70 #define MB *(1U<<20)
71 #define GB *(1U<<30)
72
73 static const U32 nbTestsDefault = 256 KB;
74 #define FUZ_COMPRESSIBILITY_DEFAULT 50
75 static const U32 prime1 = 2654435761U;
76 static const U32 prime2 = 2246822519U;
77
78
79 /*-************************************
80 * Macros
81 **************************************/
82 #define DISPLAY(...) fprintf(stderr, __VA_ARGS__)
83 #define DISPLAYLEVEL(l, ...) do { if (displayLevel>=(l)) DISPLAY(__VA_ARGS__); } while (0)
84 #define DISPLAYUPDATE(l, ...) do { if (displayLevel>=(l)) { \
85 if ((FUZ_GetClockSpan(g_clockTime) > refreshRate) || (displayLevel>=4)) \
86 { g_clockTime = clock(); DISPLAY(__VA_ARGS__); \
87 if (displayLevel>=4) fflush(stdout); } } } while (0)
88 static const clock_t refreshRate = CLOCKS_PER_SEC / 6;
89 static clock_t g_clockTime = 0;
90
91
92 /*-***************************************
93 * Local Parameters
94 *****************************************/
95 static U32 no_prompt = 0;
96 static U32 displayLevel = 2;
97 static U32 use_pause = 0;
98
99
100 /*-*******************************************************
101 * Fuzzer functions
102 *********************************************************/
103 #define MIN(a,b) ( (a) < (b) ? (a) : (b) )
104 #define MAX(a,b) ( (a) > (b) ? (a) : (b) )
105
106 typedef struct {
107 int nbAllocs;
108 } Test_alloc_state;
109 static Test_alloc_state g_testAllocState = { 0 };
110
dummy_malloc(void * state,size_t s)111 static void* dummy_malloc(void* state, size_t s)
112 {
113 Test_alloc_state* const t = (Test_alloc_state*)state;
114 void* const p = malloc(s);
115 if (p==NULL) return NULL;
116 assert(t != NULL);
117 t->nbAllocs += 1;
118 DISPLAYLEVEL(6, "Allocating %u bytes at address %p \n", (unsigned)s, p);
119 DISPLAYLEVEL(5, "nb allocated memory segments : %i \n", t->nbAllocs);
120 return p;
121 }
122
dummy_calloc(void * state,size_t s)123 static void* dummy_calloc(void* state, size_t s)
124 {
125 Test_alloc_state* const t = (Test_alloc_state*)state;
126 void* const p = calloc(1, s);
127 if (p==NULL) return NULL;
128 assert(t != NULL);
129 t->nbAllocs += 1;
130 DISPLAYLEVEL(6, "Allocating and zeroing %u bytes at address %p \n", (unsigned)s, p);
131 DISPLAYLEVEL(5, "nb allocated memory segments : %i \n", t->nbAllocs);
132 return p;
133 }
134
dummy_free(void * state,void * p)135 static void dummy_free(void* state, void* p)
136 {
137 Test_alloc_state* const t = (Test_alloc_state*)state;
138 if (p==NULL) {
139 DISPLAYLEVEL(5, "free() on NULL \n");
140 return;
141 }
142 DISPLAYLEVEL(6, "freeing memory at address %p \n", p);
143 free(p);
144 assert(t != NULL);
145 t->nbAllocs -= 1;
146 DISPLAYLEVEL(5, "nb of allocated memory segments after this free : %i \n", t->nbAllocs);
147 assert(t->nbAllocs >= 0);
148 }
149
150 static const LZ4F_CustomMem lz4f_cmem_test = {
151 dummy_malloc,
152 dummy_calloc,
153 dummy_free,
154 &g_testAllocState
155 };
156
157
FUZ_GetClockSpan(clock_t clockStart)158 static clock_t FUZ_GetClockSpan(clock_t clockStart)
159 {
160 return clock() - clockStart; /* works even if overflow; max span ~ 30 mn */
161 }
162
163 #define FUZ_rotl32(x,r) ((x << r) | (x >> (32 - r)))
FUZ_rand(unsigned int * src)164 unsigned int FUZ_rand(unsigned int* src)
165 {
166 U32 rand32 = *src;
167 rand32 *= prime1;
168 rand32 += prime2;
169 rand32 = FUZ_rotl32(rand32, 13);
170 *src = rand32;
171 return rand32 >> 5;
172 }
173
174 #define RAND_BITS(N) (FUZ_rand(randState) & ((1 << (N))-1))
175 #define FUZ_LITERAL (RAND_BITS(6) + '0')
176 #define FUZ_ABOUT(_R) ((FUZ_rand(randState) % (_R)) + (FUZ_rand(randState) % (_R)) + 1)
FUZ_fillCompressibleNoiseBuffer(void * buffer,size_t bufferSize,double proba,U32 * randState)177 static void FUZ_fillCompressibleNoiseBuffer(void* buffer, size_t bufferSize, double proba, U32* randState)
178 {
179 BYTE* BBuffer = (BYTE*)buffer;
180 size_t pos = 0;
181 U32 P32 = (U32)(32768 * proba);
182
183 /* First Byte */
184 BBuffer[pos++] = FUZ_LITERAL;
185
186 while (pos < bufferSize) {
187 /* Select : Literal (noise) or copy (within 64K) */
188 if (RAND_BITS(15) < P32) {
189 /* Copy (within 64K) */
190 size_t const lengthRand = FUZ_ABOUT(8) + 4;
191 size_t const length = MIN(lengthRand, bufferSize - pos);
192 size_t const end = pos + length;
193 size_t const offsetRand = RAND_BITS(15) + 1;
194 size_t const offset = MIN(offsetRand, pos);
195 size_t match = pos - offset;
196 while (pos < end) BBuffer[pos++] = BBuffer[match++];
197 } else {
198 /* Literal (noise) */
199 size_t const lengthRand = FUZ_ABOUT(4);
200 size_t const length = MIN(lengthRand, bufferSize - pos);
201 size_t const end = pos + length;
202 while (pos < end) BBuffer[pos++] = FUZ_LITERAL;
203 } }
204 }
205
FUZ_highbit(U32 v32)206 static unsigned FUZ_highbit(U32 v32)
207 {
208 unsigned nbBits = 0;
209 if (v32==0) return 0;
210 while (v32) {v32 >>= 1; nbBits ++;}
211 return nbBits;
212 }
213
214
215 /*-*******************************************************
216 * Tests
217 *********************************************************/
218
219 #define CONTROL(c) { \
220 if (!(c)) { \
221 DISPLAY("Error (line %i) => %s not respected \n", __LINE__, #c); \
222 return 1; \
223 } }
224
bug1227(void)225 static int bug1227(void)
226 {
227 LZ4F_dctx* dctx;
228 CONTROL(!LZ4F_isError(LZ4F_createDecompressionContext(&dctx, LZ4F_VERSION)));
229
230 /* first session */
231 { const char s9Buffer[9] = { 0 };
232 char d9Buffer[sizeof(s9Buffer)];
233 size_t const c9SizeBound = LZ4F_compressFrameBound(sizeof(s9Buffer), NULL);
234 void* const c9Buffer = malloc(c9SizeBound);
235 /* First compress a valid frame */
236 LZ4F_preferences_t pref = LZ4F_INIT_PREFERENCES;
237 pref.frameInfo.contentSize = sizeof(s9Buffer);
238 CONTROL(c9Buffer != NULL);
239 { size_t const c9Size = LZ4F_compressFrame(c9Buffer, c9SizeBound, s9Buffer, sizeof(s9Buffer), &pref);
240 CONTROL(!LZ4F_isError(c9Size));
241 assert(c9Size > 15);
242 /* decompress it, but do not complete the process - state not terminated correctly */
243 { size_t dstSize = sizeof(d9Buffer);
244 size_t srcSize = 15;
245 size_t const d9Size = LZ4F_decompress(dctx, d9Buffer, &dstSize, c9Buffer, &srcSize, NULL);
246 CONTROL(!LZ4F_isError(d9Size));
247 CONTROL(srcSize < c9Size); /* not entirely consumed */
248 }
249 }
250 free(c9Buffer);
251 }
252 LZ4F_resetDecompressionContext(dctx); /* unfinished session -> reset should make it clean */
253
254 /* second session : generate a valid 0-size frame with no content size field (default) */
255 { size_t const c0SizeBound = LZ4F_compressFrameBound(0, NULL);
256 void* const c0Buffer = malloc(c0SizeBound);
257 char d0Buffer[1];
258 CONTROL(c0Buffer != NULL);
259 { size_t const c0Size = LZ4F_compressFrame(c0Buffer, c0SizeBound, NULL, 0, NULL);
260 CONTROL(!LZ4F_isError(c0Size));
261 /* now decompress this valid empty frame */
262 { size_t dstSize = sizeof(d0Buffer);
263 size_t srcSize = c0Size;
264 size_t const d0Size = LZ4F_decompress(dctx, d0Buffer, &dstSize, c0Buffer, &srcSize, NULL);
265 CONTROL(!LZ4F_isError(d0Size));
266 CONTROL(dstSize == 0);
267 CONTROL(srcSize == c0Size);
268 } }
269 free(c0Buffer);
270 }
271
272 LZ4F_freeDecompressionContext(dctx);
273 return 0;
274 }
275
276 #define CHECK_V(v,f) v = f; if (LZ4F_isError(v)) { fprintf(stderr, "%s \n", LZ4F_getErrorName(v)); goto _output_error; }
277 #define CHECK(f) { LZ4F_errorCode_t const CHECK_V(err_ , f); }
278
unitTests(U32 seed,double compressibility)279 static int unitTests(U32 seed, double compressibility)
280 {
281 #define COMPRESSIBLE_NOISE_LENGTH (2 MB)
282 void* const CNBuffer = malloc(COMPRESSIBLE_NOISE_LENGTH);
283 size_t const cBuffSize = LZ4F_compressFrameBound(COMPRESSIBLE_NOISE_LENGTH, NULL);
284 void* const compressedBuffer = malloc(cBuffSize);
285 void* const decodedBuffer = malloc(COMPRESSIBLE_NOISE_LENGTH);
286 U32 randVal = seed;
287 U32* const randState = &randVal;
288 size_t cSize, testSize;
289 LZ4F_decompressionContext_t dCtx = NULL;
290 LZ4F_compressionContext_t cctx = NULL;
291 U64 crcOrig;
292 int basicTests_error = 0;
293 LZ4F_preferences_t prefs;
294 memset(&prefs, 0, sizeof(prefs));
295
296 if (!CNBuffer || !compressedBuffer || !decodedBuffer) {
297 DISPLAY("allocation error, not enough memory to start fuzzer tests \n");
298 goto _output_error;
299 }
300 FUZ_fillCompressibleNoiseBuffer(CNBuffer, COMPRESSIBLE_NOISE_LENGTH, compressibility, randState);
301 crcOrig = XXH64(CNBuffer, COMPRESSIBLE_NOISE_LENGTH, 1);
302
303 /* LZ4F_compressBound() : special case : srcSize == 0 */
304 DISPLAYLEVEL(3, "LZ4F_compressBound(0) = ");
305 { size_t const cBound = LZ4F_compressBound(0, NULL);
306 if (cBound < 64 KB) goto _output_error;
307 DISPLAYLEVEL(3, " %u \n", (U32)cBound);
308 }
309
310 /* LZ4F_compressBound() : special case : automatic flushing enabled */
311 DISPLAYLEVEL(3, "LZ4F_compressBound(1 KB, autoFlush=1) = ");
312 { size_t cBound;
313 LZ4F_preferences_t autoFlushPrefs;
314 memset(&autoFlushPrefs, 0, sizeof(autoFlushPrefs));
315 autoFlushPrefs.autoFlush = 1;
316 cBound = LZ4F_compressBound(1 KB, &autoFlushPrefs);
317 if (cBound > 64 KB) goto _output_error;
318 DISPLAYLEVEL(3, " %u \n", (U32)cBound);
319 }
320
321 /* LZ4F_compressBound() : special case : automatic flushing disabled */
322 DISPLAYLEVEL(3, "LZ4F_compressBound(1 KB, autoFlush=0) = ");
323 { size_t const cBound = LZ4F_compressBound(1 KB, &prefs);
324 if (cBound < 64 KB) goto _output_error;
325 DISPLAYLEVEL(3, " %u \n", (U32)cBound);
326 }
327
328 /* Special case : null-content frame */
329 testSize = 0;
330 DISPLAYLEVEL(3, "LZ4F_compressFrame, compress null content : ");
331 CHECK_V(cSize, LZ4F_compressFrame(compressedBuffer, LZ4F_compressFrameBound(testSize, NULL), CNBuffer, testSize, NULL));
332 DISPLAYLEVEL(3, "null content encoded into a %u bytes frame \n", (unsigned)cSize);
333
334 DISPLAYLEVEL(3, "LZ4F_createDecompressionContext \n");
335 CHECK ( LZ4F_createDecompressionContext(&dCtx, LZ4F_VERSION) );
336
337 DISPLAYLEVEL(3, "LZ4F_getFrameInfo on null-content frame (#157) \n");
338 assert(cSize >= LZ4F_MIN_SIZE_TO_KNOW_HEADER_LENGTH);
339 { LZ4F_frameInfo_t frame_info;
340 size_t const fhs = LZ4F_headerSize(compressedBuffer, LZ4F_MIN_SIZE_TO_KNOW_HEADER_LENGTH);
341 size_t avail_in = fhs;
342 CHECK( fhs );
343 CHECK( LZ4F_getFrameInfo(dCtx, &frame_info, compressedBuffer, &avail_in) );
344 if (avail_in != fhs) goto _output_error; /* must consume all, since header size is supposed to be exact */
345 }
346
347 DISPLAYLEVEL(3, "LZ4F_freeDecompressionContext \n");
348 CHECK( LZ4F_freeDecompressionContext(dCtx) );
349 dCtx = NULL;
350
351 /* test one-pass frame compression */
352 testSize = COMPRESSIBLE_NOISE_LENGTH;
353
354 DISPLAYLEVEL(3, "LZ4F_compressFrame, using fast level -3 : ");
355 { LZ4F_preferences_t fastCompressPrefs;
356 memset(&fastCompressPrefs, 0, sizeof(fastCompressPrefs));
357 fastCompressPrefs.compressionLevel = -3;
358 CHECK_V(cSize, LZ4F_compressFrame(compressedBuffer, LZ4F_compressFrameBound(testSize, NULL), CNBuffer, testSize, &fastCompressPrefs));
359 DISPLAYLEVEL(3, "Compressed %u bytes into a %u bytes frame \n", (U32)testSize, (U32)cSize);
360 }
361
362 DISPLAYLEVEL(3, "LZ4F_compressFrame, using default preferences : ");
363 CHECK_V(cSize, LZ4F_compressFrame(compressedBuffer, LZ4F_compressFrameBound(testSize, NULL), CNBuffer, testSize, NULL));
364 DISPLAYLEVEL(3, "Compressed %u bytes into a %u bytes frame \n", (U32)testSize, (U32)cSize);
365
366 DISPLAYLEVEL(3, "Decompression test : \n");
367 { size_t decodedBufferSize = COMPRESSIBLE_NOISE_LENGTH;
368 size_t compressedBufferSize = cSize;
369
370 CHECK( LZ4F_createDecompressionContext(&dCtx, LZ4F_VERSION) );
371
372 DISPLAYLEVEL(3, "Single Pass decompression : ");
373 CHECK( LZ4F_decompress(dCtx, decodedBuffer, &decodedBufferSize, compressedBuffer, &compressedBufferSize, NULL) );
374 { U64 const crcDest = XXH64(decodedBuffer, decodedBufferSize, 1);
375 if (crcDest != crcOrig) goto _output_error; }
376 DISPLAYLEVEL(3, "Regenerated %u bytes \n", (U32)decodedBufferSize);
377
378 DISPLAYLEVEL(3, "Reusing decompression context \n");
379 { size_t const missingBytes = 4;
380 size_t iSize = compressedBufferSize - missingBytes;
381 const BYTE* cBuff = (const BYTE*) compressedBuffer;
382 BYTE* const ostart = (BYTE*)decodedBuffer;
383 BYTE* op = ostart;
384 BYTE* const oend = (BYTE*)decodedBuffer + COMPRESSIBLE_NOISE_LENGTH;
385 size_t decResult, oSize = COMPRESSIBLE_NOISE_LENGTH;
386 DISPLAYLEVEL(3, "Missing last %u bytes : ", (U32)missingBytes);
387 CHECK_V(decResult, LZ4F_decompress(dCtx, op, &oSize, cBuff, &iSize, NULL));
388 if (decResult != missingBytes) {
389 DISPLAY("%u bytes missing != %u bytes requested \n", (U32)missingBytes, (U32)decResult);
390 goto _output_error;
391 }
392 DISPLAYLEVEL(3, "indeed, requests %u bytes \n", (unsigned)decResult);
393 cBuff += iSize;
394 iSize = decResult;
395 op += oSize;
396 oSize = (size_t)(oend-op);
397 decResult = LZ4F_decompress(dCtx, op, &oSize, cBuff, &iSize, NULL);
398 if (decResult != 0) goto _output_error; /* should finish now */
399 op += oSize;
400 if (op>oend) { DISPLAY("decompression write overflow \n"); goto _output_error; }
401 { U64 const crcDest = XXH64(decodedBuffer, (size_t)(op-ostart), 1);
402 if (crcDest != crcOrig) goto _output_error;
403 } }
404
405 { size_t oSize = 0;
406 size_t iSize = 0;
407 LZ4F_frameInfo_t fi;
408 const BYTE* ip = (BYTE*)compressedBuffer;
409
410 DISPLAYLEVEL(3, "Start by feeding 0 bytes, to get next input size : ");
411 CHECK( LZ4F_decompress(dCtx, NULL, &oSize, ip, &iSize, NULL) );
412 //DISPLAYLEVEL(3, " %u \n", (unsigned)errorCode);
413 DISPLAYLEVEL(3, " OK \n");
414
415 DISPLAYLEVEL(3, "LZ4F_getFrameInfo on zero-size input : ");
416 { size_t nullSize = 0;
417 size_t const fiError = LZ4F_getFrameInfo(dCtx, &fi, ip, &nullSize);
418 if (LZ4F_getErrorCode(fiError) != LZ4F_ERROR_frameHeader_incomplete) {
419 DISPLAYLEVEL(3, "incorrect error : %s != ERROR_frameHeader_incomplete \n",
420 LZ4F_getErrorName(fiError));
421 goto _output_error;
422 }
423 DISPLAYLEVEL(3, " correctly failed : %s \n", LZ4F_getErrorName(fiError));
424 }
425
426 DISPLAYLEVEL(3, "LZ4F_getFrameInfo on not enough input : ");
427 { size_t inputSize = 6;
428 size_t const fiError = LZ4F_getFrameInfo(dCtx, &fi, ip, &inputSize);
429 if (LZ4F_getErrorCode(fiError) != LZ4F_ERROR_frameHeader_incomplete) {
430 DISPLAYLEVEL(3, "incorrect error : %s != ERROR_frameHeader_incomplete \n", LZ4F_getErrorName(fiError));
431 goto _output_error;
432 }
433 DISPLAYLEVEL(3, " correctly failed : %s \n", LZ4F_getErrorName(fiError));
434 }
435
436 DISPLAYLEVEL(3, "LZ4F_getFrameInfo on enough input : ");
437 iSize = LZ4F_headerSize(ip, LZ4F_MIN_SIZE_TO_KNOW_HEADER_LENGTH);
438 CHECK( iSize );
439 CHECK( LZ4F_getFrameInfo(dCtx, &fi, ip, &iSize) );
440 DISPLAYLEVEL(3, " correctly decoded \n");
441 }
442
443 DISPLAYLEVEL(3, "Decode a buggy input : ");
444 assert(COMPRESSIBLE_NOISE_LENGTH > 64);
445 assert(cSize > 48);
446 memcpy(decodedBuffer, (char*)compressedBuffer+16, 32); /* save correct data */
447 memcpy((char*)compressedBuffer+16, (const char*)decodedBuffer+32, 32); /* insert noise */
448 { size_t dbSize = COMPRESSIBLE_NOISE_LENGTH;
449 size_t cbSize = cSize;
450 size_t const decompressError = LZ4F_decompress(dCtx, decodedBuffer, &dbSize,
451 compressedBuffer, &cbSize,
452 NULL);
453 if (!LZ4F_isError(decompressError)) goto _output_error;
454 DISPLAYLEVEL(3, "error detected : %s \n", LZ4F_getErrorName(decompressError));
455 }
456 memcpy((char*)compressedBuffer+16, decodedBuffer, 32); /* restore correct data */
457
458 DISPLAYLEVEL(3, "Reset decompression context, since it's left in error state \n");
459 LZ4F_resetDecompressionContext(dCtx); /* always successful */
460
461 DISPLAYLEVEL(3, "Byte after byte : ");
462 { BYTE* const ostart = (BYTE*)decodedBuffer;
463 BYTE* op = ostart;
464 BYTE* const oend = (BYTE*)decodedBuffer + COMPRESSIBLE_NOISE_LENGTH;
465 const BYTE* ip = (const BYTE*) compressedBuffer;
466 const BYTE* const iend = ip + cSize;
467 while (ip < iend) {
468 size_t oSize = (size_t)(oend-op);
469 size_t iSize = 1;
470 CHECK( LZ4F_decompress(dCtx, op, &oSize, ip, &iSize, NULL) );
471 op += oSize;
472 ip += iSize;
473 }
474 { U64 const crcDest = XXH64(decodedBuffer, COMPRESSIBLE_NOISE_LENGTH, 1);
475 if (crcDest != crcOrig) goto _output_error;
476 }
477 DISPLAYLEVEL(3, "Regenerated %u/%u bytes \n", (unsigned)(op-ostart), (unsigned)COMPRESSIBLE_NOISE_LENGTH);
478 }
479 }
480
481 DISPLAYLEVEL(3, "Using 64 KB block : ");
482 prefs.frameInfo.blockSizeID = LZ4F_max64KB;
483 prefs.frameInfo.contentChecksumFlag = LZ4F_contentChecksumEnabled;
484 CHECK_V(cSize, LZ4F_compressFrame(compressedBuffer, LZ4F_compressFrameBound(testSize, &prefs), CNBuffer, testSize, &prefs));
485 DISPLAYLEVEL(3, "Compressed %i bytes into a %i bytes frame \n", (int)testSize, (int)cSize);
486
487 DISPLAYLEVEL(3, "without checksum : ");
488 prefs.frameInfo.contentChecksumFlag = LZ4F_noContentChecksum;
489 CHECK_V(cSize, LZ4F_compressFrame(compressedBuffer, LZ4F_compressFrameBound(testSize, &prefs), CNBuffer, testSize, &prefs));
490 DISPLAYLEVEL(3, "Compressed %i bytes into a %i bytes frame \n", (int)testSize, (int)cSize);
491
492 DISPLAYLEVEL(3, "Using 256 KB block : ");
493 prefs.frameInfo.blockSizeID = LZ4F_max256KB;
494 prefs.frameInfo.contentChecksumFlag = LZ4F_contentChecksumEnabled;
495 CHECK_V(cSize, LZ4F_compressFrame(compressedBuffer, LZ4F_compressFrameBound(testSize, &prefs), CNBuffer, testSize, &prefs));
496 DISPLAYLEVEL(3, "Compressed %i bytes into a %i bytes frame \n", (int)testSize, (int)cSize);
497
498 DISPLAYLEVEL(3, "Decompression test : \n");
499 { size_t const decodedBufferSize = COMPRESSIBLE_NOISE_LENGTH;
500 unsigned const maxBits = FUZ_highbit((U32)decodedBufferSize);
501 BYTE* const ostart = (BYTE*)decodedBuffer;
502 BYTE* op = ostart;
503 BYTE* const oend = ostart + COMPRESSIBLE_NOISE_LENGTH;
504 const BYTE* ip = (const BYTE*)compressedBuffer;
505 const BYTE* const iend = (const BYTE*)compressedBuffer + cSize;
506
507 DISPLAYLEVEL(3, "random segment sizes : ");
508 while (ip < iend) {
509 unsigned const nbBits = FUZ_rand(randState) % maxBits;
510 size_t iSize = RAND_BITS(nbBits) + 1;
511 size_t oSize = (size_t)(oend-op);
512 if (iSize > (size_t)(iend-ip)) iSize = (size_t)(iend-ip);
513 CHECK( LZ4F_decompress(dCtx, op, &oSize, ip, &iSize, NULL) );
514 op += oSize;
515 ip += iSize;
516 }
517 { size_t const decodedSize = (size_t)(op - ostart);
518 U64 const crcDest = XXH64(decodedBuffer, decodedSize, 1);
519 if (crcDest != crcOrig) goto _output_error;
520 DISPLAYLEVEL(3, "Regenerated %u bytes \n", (U32)decodedSize);
521 }
522
523 CHECK( LZ4F_freeDecompressionContext(dCtx) );
524 dCtx = NULL;
525 }
526
527 DISPLAYLEVEL(3, "without checksum : ");
528 prefs.frameInfo.contentChecksumFlag = LZ4F_noContentChecksum;
529 CHECK_V(cSize, LZ4F_compressFrame(compressedBuffer, LZ4F_compressFrameBound(testSize, &prefs), CNBuffer, testSize, &prefs) );
530 DISPLAYLEVEL(3, "Compressed %i bytes into a %i bytes frame \n", (int)testSize, (int)cSize);
531
532 DISPLAYLEVEL(3, "Using 1 MB block : ");
533 prefs.frameInfo.blockSizeID = LZ4F_max1MB;
534 prefs.frameInfo.contentChecksumFlag = LZ4F_contentChecksumEnabled;
535 CHECK_V(cSize, LZ4F_compressFrame(compressedBuffer, LZ4F_compressFrameBound(testSize, &prefs), CNBuffer, testSize, &prefs) );
536 DISPLAYLEVEL(3, "Compressed %i bytes into a %i bytes frame \n", (int)testSize, (int)cSize);
537
538 DISPLAYLEVEL(3, "without frame checksum : ");
539 prefs.frameInfo.contentChecksumFlag = LZ4F_noContentChecksum;
540 CHECK_V(cSize, LZ4F_compressFrame(compressedBuffer, LZ4F_compressFrameBound(testSize, &prefs), CNBuffer, testSize, &prefs) );
541 DISPLAYLEVEL(3, "Compressed %i bytes into a %i bytes frame \n", (int)testSize, (int)cSize);
542
543 DISPLAYLEVEL(3, "Using 4 MB block : ");
544 prefs.frameInfo.blockSizeID = LZ4F_max4MB;
545 prefs.frameInfo.contentChecksumFlag = LZ4F_contentChecksumEnabled;
546 { size_t const dstCapacity = LZ4F_compressFrameBound(testSize, &prefs);
547 DISPLAYLEVEL(4, "dstCapacity = %u ; ", (U32)dstCapacity);
548 CHECK_V(cSize, LZ4F_compressFrame(compressedBuffer, dstCapacity, CNBuffer, testSize, &prefs) );
549 DISPLAYLEVEL(3, "Compressed %u bytes into a %u bytes frame \n", (U32)testSize, (U32)cSize);
550 }
551
552 DISPLAYLEVEL(3, "without frame checksum : ");
553 prefs.frameInfo.contentChecksumFlag = LZ4F_noContentChecksum;
554 { size_t const dstCapacity = LZ4F_compressFrameBound(testSize, &prefs);
555 DISPLAYLEVEL(4, "dstCapacity = %u ; ", (U32)dstCapacity);
556 CHECK_V(cSize, LZ4F_compressFrame(compressedBuffer, dstCapacity, CNBuffer, testSize, &prefs) );
557 DISPLAYLEVEL(3, "Compressed %u bytes into a %u bytes frame \n", (U32)testSize, (U32)cSize);
558 }
559
560 DISPLAYLEVEL(3, "LZ4F_compressFrame with block checksum : ");
561 memset(&prefs, 0, sizeof(prefs));
562 prefs.frameInfo.blockChecksumFlag = LZ4F_blockChecksumEnabled;
563 CHECK_V(cSize, LZ4F_compressFrame(compressedBuffer, LZ4F_compressFrameBound(testSize, &prefs), CNBuffer, testSize, &prefs) );
564 DISPLAYLEVEL(3, "Compressed %i bytes into a %i bytes frame \n", (int)testSize, (int)cSize);
565
566 DISPLAYLEVEL(3, "Decompress with block checksum : ");
567 { size_t iSize = cSize;
568 size_t decodedSize = COMPRESSIBLE_NOISE_LENGTH;
569 LZ4F_decompressionContext_t dctx;
570 CHECK( LZ4F_createDecompressionContext(&dctx, LZ4F_VERSION) );
571 CHECK( LZ4F_decompress(dctx, decodedBuffer, &decodedSize, compressedBuffer, &iSize, NULL) );
572 if (decodedSize != testSize) goto _output_error;
573 if (iSize != cSize) goto _output_error;
574 { U64 const crcDest = XXH64(decodedBuffer, decodedSize, 1);
575 U64 const crcSrc = XXH64(CNBuffer, testSize, 1);
576 if (crcDest != crcSrc) goto _output_error;
577 }
578 DISPLAYLEVEL(3, "Regenerated %u bytes \n", (U32)decodedSize);
579
580 CHECK( LZ4F_freeDecompressionContext(dctx) );
581 }
582
583 /* frame content size tests */
584 { size_t cErr;
585 BYTE* const ostart = (BYTE*)compressedBuffer;
586 BYTE* op = ostart;
587 CHECK( LZ4F_createCompressionContext(&cctx, LZ4F_VERSION) );
588
589 DISPLAYLEVEL(3, "compress without frameSize : ");
590 memset(&(prefs.frameInfo), 0, sizeof(prefs.frameInfo));
591 CHECK_V(cErr, LZ4F_compressBegin(cctx, compressedBuffer, testSize, &prefs));
592 op += cErr;
593 CHECK_V(cErr, LZ4F_compressUpdate(cctx, op, LZ4F_compressBound(testSize, &prefs), CNBuffer, testSize, NULL));
594 op += cErr;
595 CHECK( LZ4F_compressEnd(cctx, compressedBuffer, testSize, NULL) );
596 DISPLAYLEVEL(3, "Compressed %i bytes into a %i bytes frame \n", (int)testSize, (int)(op-ostart));
597
598 DISPLAYLEVEL(3, "compress with frameSize : ");
599 prefs.frameInfo.contentSize = testSize;
600 op = ostart;
601 CHECK_V(cErr, LZ4F_compressBegin(cctx, compressedBuffer, testSize, &prefs));
602 op += cErr;
603 CHECK_V(cErr, LZ4F_compressUpdate(cctx, op, LZ4F_compressBound(testSize, &prefs), CNBuffer, testSize, NULL));
604 op += cErr;
605 CHECK( LZ4F_compressEnd(cctx, compressedBuffer, testSize, NULL) );
606 DISPLAYLEVEL(3, "Compressed %i bytes into a %i bytes frame \n", (int)testSize, (int)(op-ostart));
607
608 DISPLAYLEVEL(3, "compress with wrong frameSize : ");
609 prefs.frameInfo.contentSize = testSize+1;
610 op = ostart;
611 CHECK_V(cErr, LZ4F_compressBegin(cctx, compressedBuffer, testSize, &prefs));
612 op += cErr;
613 CHECK_V(cErr, LZ4F_compressUpdate(cctx, op, LZ4F_compressBound(testSize, &prefs), CNBuffer, testSize, NULL));
614 op += cErr;
615 cErr = LZ4F_compressEnd(cctx, op, testSize, NULL);
616 if (!LZ4F_isError(cErr)) goto _output_error;
617 DISPLAYLEVEL(3, "Error correctly detected : %s \n", LZ4F_getErrorName(cErr));
618
619 CHECK( LZ4F_freeCompressionContext(cctx) );
620 cctx = NULL;
621 }
622
623 /* dictID tests */
624 { size_t cErr;
625 U32 const dictID = 0x99;
626 /* test advanced variant with custom allocator functions */
627 cctx = LZ4F_createCompressionContext_advanced(lz4f_cmem_test, LZ4F_VERSION);
628 if (cctx==NULL) goto _output_error;
629
630 DISPLAYLEVEL(3, "insert a dictID : ");
631 memset(&prefs.frameInfo, 0, sizeof(prefs.frameInfo));
632 prefs.frameInfo.dictID = dictID;
633 CHECK_V(cErr, LZ4F_compressBegin(cctx, compressedBuffer, testSize, &prefs));
634 DISPLAYLEVEL(3, "created frame header of size %i bytes \n", (int)cErr);
635
636 DISPLAYLEVEL(3, "read a dictID : ");
637 CHECK( LZ4F_createDecompressionContext(&dCtx, LZ4F_VERSION) );
638 memset(&prefs.frameInfo, 0, sizeof(prefs.frameInfo));
639 CHECK( LZ4F_getFrameInfo(dCtx, &prefs.frameInfo, compressedBuffer, &cErr) );
640 if (prefs.frameInfo.dictID != dictID) goto _output_error;
641 DISPLAYLEVEL(3, "%u \n", (U32)prefs.frameInfo.dictID);
642
643 CHECK( LZ4F_freeDecompressionContext(dCtx) ); dCtx = NULL;
644 CHECK( LZ4F_freeCompressionContext(cctx) ); cctx = NULL;
645 }
646
647 /* Raw Dictionary compression test */
648 { size_t const dictSize = 7 KB; /* small enough for LZ4_MEMORY_USAGE == 10 */
649 size_t const srcSize = 66 KB; /* must be > 64 KB to avoid short-size optimizations */
650 size_t const dstCapacity = LZ4F_compressFrameBound(srcSize, NULL);
651 size_t cSizeNoDict, cSizeWithDict;
652 const void* dict = CNBuffer;
653 const void* src = (const char*)CNBuffer + dictSize;
654 char* cPtr = (char*)compressedBuffer;
655 CHECK( LZ4F_createCompressionContext(&cctx, LZ4F_VERSION) );
656
657 /* compress without dictionary, just to establish a comparison point */
658 CHECK_V(cSizeNoDict,
659 LZ4F_compressFrame(compressedBuffer, dstCapacity,
660 src, srcSize,
661 NULL) );
662 /* note: NULL preferences ==> 64 KB linked blocks */
663
664 /* now compress with dictionary */
665 DISPLAYLEVEL(3, "LZ4F_compressBegin_usingDict: ");
666 cSizeWithDict = 0;
667 { size_t hSize = LZ4F_compressBegin_usingDict(cctx, cPtr, dstCapacity, dict, dictSize, NULL);
668 //size_t hSize = LZ4F_compressBegin(cctx, cPtr, dstCapacity, NULL);
669 CHECK(hSize);
670 cSizeWithDict += hSize;
671 cPtr += hSize;
672 }
673 { size_t bSize = LZ4F_compressUpdate(cctx, cPtr, dstCapacity, src, srcSize, NULL);
674 CHECK(bSize);
675 cSizeWithDict += bSize;
676 cPtr += bSize;
677 }
678 { size_t endSize = LZ4F_compressEnd(cctx, cPtr, dstCapacity, NULL);
679 CHECK(endSize);
680 cSizeWithDict += endSize;
681 }
682 DISPLAYLEVEL(3, "compress %u bytes into %u bytes with dict (< %u bytes without) \n",
683 (unsigned)srcSize, (unsigned)cSizeWithDict, (unsigned)cSizeNoDict);
684 if (cSizeWithDict >= cSizeNoDict) {
685 DISPLAYLEVEL(3, "cSizeWithDict (%u) should have been more compact than cSizeNoDict(%u) \n", (unsigned)cSizeWithDict, (unsigned)cSizeNoDict);
686 goto _output_error; /* must be more efficient */
687 }
688 crcOrig = XXH64(src, srcSize, 0);
689
690 DISPLAYLEVEL(3, "LZ4F_decompress_usingDict: ");
691 { LZ4F_dctx* dctx;
692 size_t decodedSize = srcSize;
693 size_t compressedSize = cSizeWithDict;
694 CHECK( LZ4F_createDecompressionContext(&dctx, LZ4F_VERSION) );
695 CHECK( LZ4F_decompress_usingDict(dctx,
696 decodedBuffer, &decodedSize,
697 compressedBuffer, &compressedSize,
698 CNBuffer, dictSize,
699 NULL) );
700 if (compressedSize != cSizeWithDict) goto _output_error;
701 if (decodedSize != srcSize) goto _output_error;
702 { U64 const crcDest = XXH64(decodedBuffer, decodedSize, 0);
703 if (crcDest != crcOrig) goto _output_error; }
704 DISPLAYLEVEL(3, "Regenerated %u bytes \n", (U32)decodedSize);
705 CHECK( LZ4F_freeDecompressionContext(dctx) );
706 }
707
708 /* clean */
709 CHECK( LZ4F_freeCompressionContext(cctx) );
710 }
711
712 /* Digested Dictionary (cdict) compression test */
713 { size_t const dictSize = 7 KB; /* small enough for LZ4_MEMORY_USAGE == 10 */
714 size_t const srcSize = 65 KB; /* must be > 64 KB to avoid short-size optimizations */
715 size_t const dstCapacity = LZ4F_compressFrameBound(srcSize, NULL);
716 size_t cSizeNoDict, cSizeWithDict;
717 LZ4F_CDict* const cdict = LZ4F_createCDict(CNBuffer, dictSize);
718 if (cdict == NULL) goto _output_error;
719 CHECK( LZ4F_createCompressionContext(&cctx, LZ4F_VERSION) );
720
721 DISPLAYLEVEL(3, "Testing LZ4F_createCDict_advanced : ");
722 { LZ4F_CDict* const cda = LZ4F_createCDict_advanced(lz4f_cmem_test, CNBuffer, dictSize);
723 if (cda == NULL) goto _output_error;
724 LZ4F_freeCDict(cda);
725 }
726 DISPLAYLEVEL(3, "OK \n");
727
728 DISPLAYLEVEL(3, "LZ4F_compressFrame_usingCDict, with NULL dict : ");
729 CHECK_V(cSizeNoDict,
730 LZ4F_compressFrame_usingCDict(cctx, compressedBuffer, dstCapacity,
731 CNBuffer, srcSize,
732 NULL, NULL) );
733 DISPLAYLEVEL(3, "%u bytes \n", (unsigned)cSizeNoDict);
734
735 DISPLAYLEVEL(3, "LZ4F_compressFrame_usingCDict, with dict : ");
736 CHECK( LZ4F_freeCompressionContext(cctx) );
737 CHECK( LZ4F_createCompressionContext(&cctx, LZ4F_VERSION) );
738 CHECK_V(cSizeWithDict,
739 LZ4F_compressFrame_usingCDict(cctx, compressedBuffer, dstCapacity,
740 CNBuffer, srcSize,
741 cdict, NULL) );
742 DISPLAYLEVEL(3, "compressed %u bytes into %u bytes \n",
743 (unsigned)srcSize, (unsigned)cSizeWithDict);
744 if (cSizeWithDict > cSizeNoDict) {
745 DISPLAYLEVEL(3, "cSizeWithDict (%u) should have been more compact than cSizeNoDict(%u) \n", (unsigned)cSizeWithDict, (unsigned)cSizeNoDict);
746 goto _output_error; /* must be more efficient */
747 }
748 crcOrig = XXH64(CNBuffer, srcSize, 0);
749
750 DISPLAYLEVEL(3, "LZ4F_decompress_usingDict : ");
751 { LZ4F_dctx* dctx;
752 size_t decodedSize = srcSize;
753 size_t compressedSize = cSizeWithDict;
754 CHECK( LZ4F_createDecompressionContext(&dctx, LZ4F_VERSION) );
755 CHECK( LZ4F_decompress_usingDict(dctx,
756 decodedBuffer, &decodedSize,
757 compressedBuffer, &compressedSize,
758 CNBuffer, dictSize,
759 NULL) );
760 if (compressedSize != cSizeWithDict) goto _output_error;
761 if (decodedSize != srcSize) goto _output_error;
762 { U64 const crcDest = XXH64(decodedBuffer, decodedSize, 0);
763 if (crcDest != crcOrig) goto _output_error; }
764 DISPLAYLEVEL(3, "Regenerated %u bytes \n", (U32)decodedSize);
765 CHECK( LZ4F_freeDecompressionContext(dctx) );
766 }
767
768 DISPLAYLEVEL(3, "LZ4F_compressFrame_usingCDict, with dict, negative level : ");
769 { size_t cSizeLevelMax;
770 LZ4F_preferences_t cParams;
771 memset(&cParams, 0, sizeof(cParams));
772 cParams.compressionLevel = -3;
773 CHECK_V(cSizeLevelMax,
774 LZ4F_compressFrame_usingCDict(cctx, compressedBuffer, dstCapacity,
775 CNBuffer, dictSize,
776 cdict, &cParams) );
777 DISPLAYLEVEL(3, "%u bytes \n", (unsigned)cSizeLevelMax);
778 }
779
780 DISPLAYLEVEL(3, "LZ4F_compressFrame_usingCDict, with dict, level max : ");
781 { size_t cSizeLevelMax;
782 LZ4F_preferences_t cParams;
783 memset(&cParams, 0, sizeof(cParams));
784 cParams.compressionLevel = LZ4F_compressionLevel_max();
785 CHECK_V(cSizeLevelMax,
786 LZ4F_compressFrame_usingCDict(cctx, compressedBuffer, dstCapacity,
787 CNBuffer, dictSize,
788 cdict, &cParams) );
789 DISPLAYLEVEL(3, "%u bytes \n", (unsigned)cSizeLevelMax);
790 }
791
792 DISPLAYLEVEL(3, "LZ4F_compressFrame_usingCDict, multiple linked blocks : ");
793 { size_t cSizeContiguous;
794 size_t const inSize = dictSize * 3;
795 size_t const outCapacity = LZ4F_compressFrameBound(inSize, NULL);
796 LZ4F_preferences_t cParams;
797 memset(&cParams, 0, sizeof(cParams));
798 cParams.frameInfo.blockMode = LZ4F_blockLinked;
799 cParams.frameInfo.blockSizeID = LZ4F_max64KB;
800 CHECK_V(cSizeContiguous,
801 LZ4F_compressFrame_usingCDict(cctx, compressedBuffer, outCapacity,
802 CNBuffer, inSize,
803 cdict, &cParams) );
804 DISPLAYLEVEL(3, "compressed %u bytes into %u bytes \n",
805 (unsigned)inSize, (unsigned)cSizeContiguous);
806
807 DISPLAYLEVEL(3, "LZ4F_decompress_usingDict on multiple linked blocks : ");
808 { LZ4F_dctx* dctx;
809 size_t decodedSize = COMPRESSIBLE_NOISE_LENGTH;
810 size_t compressedSize = cSizeContiguous;
811 CHECK( LZ4F_createDecompressionContext(&dctx, LZ4F_VERSION) );
812 CHECK( LZ4F_decompress_usingDict(dctx,
813 decodedBuffer, &decodedSize,
814 compressedBuffer, &compressedSize,
815 CNBuffer, dictSize,
816 NULL) );
817 if (compressedSize != cSizeContiguous) goto _output_error;
818 if (decodedSize != inSize) goto _output_error;
819 crcOrig = XXH64(CNBuffer, inSize, 0);
820 { U64 const crcDest = XXH64(decodedBuffer, decodedSize, 0);
821 if (crcDest != crcOrig) goto _output_error; }
822 DISPLAYLEVEL(3, "Regenerated %u bytes \n", (U32)decodedSize);
823 CHECK( LZ4F_freeDecompressionContext(dctx) );
824 }
825 }
826
827 DISPLAYLEVEL(3, "LZ4F_compressFrame_usingCDict, multiple independent blocks : ");
828 { size_t cSizeIndep;
829 size_t const inSize = dictSize * 3;
830 size_t const outCapacity = LZ4F_compressFrameBound(inSize, NULL);
831 LZ4F_preferences_t cParams;
832 memset(&cParams, 0, sizeof(cParams));
833 cParams.frameInfo.blockMode = LZ4F_blockIndependent;
834 cParams.frameInfo.blockSizeID = LZ4F_max64KB;
835 CHECK_V(cSizeIndep,
836 LZ4F_compressFrame_usingCDict(cctx, compressedBuffer, outCapacity,
837 CNBuffer, inSize,
838 cdict, &cParams) );
839 DISPLAYLEVEL(3, "compressed %u bytes into %u bytes \n",
840 (unsigned)inSize, (unsigned)cSizeIndep);
841
842 DISPLAYLEVEL(3, "LZ4F_decompress_usingDict on multiple independent blocks : ");
843 { LZ4F_dctx* dctx;
844 size_t decodedSize = COMPRESSIBLE_NOISE_LENGTH;
845 size_t compressedSize = cSizeIndep;
846 CHECK( LZ4F_createDecompressionContext(&dctx, LZ4F_VERSION) );
847 CHECK( LZ4F_decompress_usingDict(dctx,
848 decodedBuffer, &decodedSize,
849 compressedBuffer, &compressedSize,
850 CNBuffer, dictSize,
851 NULL) );
852 if (compressedSize != cSizeIndep) goto _output_error;
853 if (decodedSize != inSize) goto _output_error;
854 crcOrig = XXH64(CNBuffer, inSize, 0);
855 { U64 const crcDest = XXH64(decodedBuffer, decodedSize, 0);
856 if (crcDest != crcOrig) goto _output_error; }
857 DISPLAYLEVEL(3, "Regenerated %u bytes \n", (U32)decodedSize);
858 CHECK( LZ4F_freeDecompressionContext(dctx) );
859 }
860 }
861
862 LZ4F_freeCDict(cdict);
863 CHECK( LZ4F_freeCompressionContext(cctx) ); cctx = NULL;
864 }
865
866 DISPLAYLEVEL(3, "getBlockSize test: \n");
867 { size_t result;
868 unsigned blockSizeID;
869 for (blockSizeID = 4; blockSizeID < 8; ++blockSizeID) {
870 result = LZ4F_getBlockSize((LZ4F_blockSizeID_t)blockSizeID);
871 CHECK(result);
872 DISPLAYLEVEL(3, "Returned block size of %u bytes for blockID %u \n",
873 (unsigned)result, blockSizeID);
874 }
875
876 /* Test an invalid input that's too large */
877 result = LZ4F_getBlockSize((LZ4F_blockSizeID_t)8);
878 if(!LZ4F_isError(result) ||
879 LZ4F_getErrorCode(result) != LZ4F_ERROR_maxBlockSize_invalid)
880 goto _output_error;
881
882 /* Test an invalid input that's too small */
883 result = LZ4F_getBlockSize((LZ4F_blockSizeID_t)3);
884 if(!LZ4F_isError(result) ||
885 LZ4F_getErrorCode(result) != LZ4F_ERROR_maxBlockSize_invalid)
886 goto _output_error;
887 }
888
889 DISPLAYLEVEL(3, "check bug1227: reused dctx after error => ");
890 if (bug1227()) goto _output_error;
891 DISPLAYLEVEL(3, "OK \n");
892
893 DISPLAYLEVEL(3, "Skippable frame test : \n");
894 { size_t decodedBufferSize = COMPRESSIBLE_NOISE_LENGTH;
895 unsigned maxBits = FUZ_highbit((U32)decodedBufferSize);
896 BYTE* op = (BYTE*)decodedBuffer;
897 BYTE* const oend = (BYTE*)decodedBuffer + COMPRESSIBLE_NOISE_LENGTH;
898 BYTE* ip = (BYTE*)compressedBuffer;
899 BYTE* iend = (BYTE*)compressedBuffer + cSize + 8;
900
901 CHECK( LZ4F_createDecompressionContext(&dCtx, LZ4F_VERSION) );
902
903 /* generate skippable frame */
904 FUZ_writeLE32(ip, LZ4F_MAGIC_SKIPPABLE_START);
905 FUZ_writeLE32(ip+4, (U32)cSize);
906
907 DISPLAYLEVEL(3, "random segment sizes : \n");
908 while (ip < iend) {
909 unsigned nbBits = FUZ_rand(randState) % maxBits;
910 size_t iSize = RAND_BITS(nbBits) + 1;
911 size_t oSize = (size_t)(oend-op);
912 if (iSize > (size_t)(iend-ip)) iSize = (size_t)(iend-ip);
913 CHECK( LZ4F_decompress(dCtx, op, &oSize, ip, &iSize, NULL) );
914 op += oSize;
915 ip += iSize;
916 }
917 DISPLAYLEVEL(3, "Skipped %i bytes \n", (int)decodedBufferSize);
918
919 /* generate zero-size skippable frame */
920 DISPLAYLEVEL(3, "zero-size skippable frame\n");
921 ip = (BYTE*)compressedBuffer;
922 op = (BYTE*)decodedBuffer;
923 FUZ_writeLE32(ip, LZ4F_MAGIC_SKIPPABLE_START+1);
924 FUZ_writeLE32(ip+4, 0);
925 iend = ip+8;
926
927 while (ip < iend) {
928 unsigned const nbBits = FUZ_rand(randState) % maxBits;
929 size_t iSize = RAND_BITS(nbBits) + 1;
930 size_t oSize = (size_t)(oend-op);
931 if (iSize > (size_t)(iend-ip)) iSize = (size_t)(iend-ip);
932 CHECK( LZ4F_decompress(dCtx, op, &oSize, ip, &iSize, NULL) );
933 op += oSize;
934 ip += iSize;
935 }
936 DISPLAYLEVEL(3, "Skipped %i bytes \n", (int)(ip - (BYTE*)compressedBuffer - 8));
937
938 DISPLAYLEVEL(3, "Skippable frame header complete in first call \n");
939 ip = (BYTE*)compressedBuffer;
940 op = (BYTE*)decodedBuffer;
941 FUZ_writeLE32(ip, LZ4F_MAGIC_SKIPPABLE_START+2);
942 FUZ_writeLE32(ip+4, 10);
943 iend = ip+18;
944 while (ip < iend) {
945 size_t iSize = 10;
946 size_t oSize = 10;
947 if (iSize > (size_t)(iend-ip)) iSize = (size_t)(iend-ip);
948 CHECK( LZ4F_decompress(dCtx, op, &oSize, ip, &iSize, NULL) );
949 op += oSize;
950 ip += iSize;
951 }
952 DISPLAYLEVEL(3, "Skipped %i bytes \n", (int)(ip - (BYTE*)compressedBuffer - 8));
953 }
954
955 DISPLAY("Basic tests completed \n");
956 _end:
957 free(CNBuffer);
958 free(compressedBuffer);
959 free(decodedBuffer);
960 LZ4F_freeDecompressionContext(dCtx); dCtx = NULL;
961 LZ4F_freeCompressionContext(cctx); cctx = NULL;
962 return basicTests_error;
963
964 _output_error:
965 basicTests_error = 1;
966 DISPLAY("Error detected ! \n");
967 goto _end;
968 }
969
970
971 typedef enum { o_contiguous, o_noncontiguous, o_overwrite } o_scenario_e;
972
locateBuffDiff(const void * buff1,const void * buff2,size_t size,o_scenario_e o_scenario)973 static void locateBuffDiff(const void* buff1, const void* buff2, size_t size, o_scenario_e o_scenario)
974 {
975 if (displayLevel >= 2) {
976 size_t p=0;
977 const BYTE* b1=(const BYTE*)buff1;
978 const BYTE* b2=(const BYTE*)buff2;
979 DISPLAY("locateBuffDiff: looking for error position \n");
980 if (o_scenario != o_contiguous) {
981 DISPLAY("mode %i: non-contiguous output (%u bytes), cannot search \n",
982 (int)o_scenario, (unsigned)size);
983 return;
984 }
985 while (p < size && b1[p]==b2[p]) p++;
986 if (p != size) {
987 DISPLAY("Error at pos %i/%i : %02X != %02X \n", (int)p, (int)size, b1[p], b2[p]);
988 }
989 }
990 }
991
992 #define EXIT_MSG(...) { DISPLAY("Error => "); DISPLAY(__VA_ARGS__); \
993 DISPLAY(" (seed %u, test nb %u) \n", seed, testNb); exit(1); }
994 #undef CHECK
995 #define CHECK(cond, ...) { if (cond) { EXIT_MSG(__VA_ARGS__); } }
996
test_lz4f_decompression_wBuffers(const void * cSrc,size_t cSize,void * dst,size_t dstCapacity,o_scenario_e o_scenario,const void * srcRef,size_t decompressedSize,U64 crcOrig,U32 * const randState,LZ4F_dctx * const dCtx,U32 seed,U32 testNb,int findErrorPos)997 size_t test_lz4f_decompression_wBuffers(
998 const void* cSrc, size_t cSize,
999 void* dst, size_t dstCapacity, o_scenario_e o_scenario,
1000 const void* srcRef, size_t decompressedSize,
1001 U64 crcOrig,
1002 U32* const randState,
1003 LZ4F_dctx* const dCtx,
1004 U32 seed, U32 testNb,
1005 int findErrorPos)
1006 {
1007 const BYTE* ip = (const BYTE*)cSrc;
1008 const BYTE* const iend = ip + cSize;
1009
1010 BYTE* op = (BYTE*)dst;
1011 BYTE* const oend = op + dstCapacity;
1012
1013 unsigned const suggestedBits = FUZ_highbit((U32)cSize);
1014 unsigned const maxBits = MAX(3, suggestedBits);
1015 size_t totalOut = 0;
1016 size_t moreToFlush = 0;
1017 XXH64_state_t xxh64;
1018 XXH64_reset(&xxh64, 1);
1019 assert(ip < iend);
1020 while (ip < iend) {
1021 unsigned const nbBitsI = (FUZ_rand(randState) % (maxBits-1)) + 1;
1022 unsigned const nbBitsO = (FUZ_rand(randState) % (maxBits)) + 1;
1023 size_t const iSizeCand = RAND_BITS(nbBitsI) + 1;
1024 size_t const iSizeMax = MIN(iSizeCand, (size_t)(iend-ip));
1025 size_t iSize = iSizeMax;
1026 size_t const oSizeCand = RAND_BITS(nbBitsO) + 2;
1027 size_t const oSizeMax = MIN(oSizeCand, (size_t)(oend-op));
1028 int const sentinelTest = (op + oSizeMax < oend);
1029 size_t oSize = oSizeMax;
1030 BYTE const mark = (BYTE)(RAND_BITS(8));
1031 LZ4F_decompressOptions_t dOptions;
1032 memset(&dOptions, 0, sizeof(dOptions));
1033 dOptions.stableDst = RAND_BITS(1);
1034 if (o_scenario == o_overwrite) dOptions.stableDst = 0; /* overwrite mode */
1035 dOptions.skipChecksums = RAND_BITS(1);
1036 if (sentinelTest) op[oSizeMax] = mark;
1037
1038 DISPLAYLEVEL(7, "dstCapacity=%u, presentedInput=%u \n", (unsigned)oSize, (unsigned)iSize);
1039
1040 /* read data from byte-exact buffer to catch out-of-bound reads */
1041 { void* const iBuffer = malloc(iSizeMax);
1042 /*test NULL supported if size==0 */
1043 void* const tmpop = RAND_BITS(oSize == 0) ? NULL : op;
1044 const void* const tmpip = RAND_BITS(iSize == 0) ? NULL : iBuffer;
1045 assert(iBuffer != NULL);
1046 memcpy(iBuffer, ip, iSizeMax);
1047 moreToFlush = LZ4F_decompress(dCtx, tmpop, &oSize, tmpip, &iSize, &dOptions);
1048 free(iBuffer);
1049 }
1050 DISPLAYLEVEL(7, "oSize=%u, readSize=%u \n", (unsigned)oSize, (unsigned)iSize);
1051
1052 if (sentinelTest) {
1053 CHECK(op[oSizeMax] != mark, "op[oSizeMax] = %02X != %02X : "
1054 "Decompression overwrites beyond assigned dst size",
1055 op[oSizeMax], mark);
1056 }
1057 if (LZ4F_getErrorCode(moreToFlush) == LZ4F_ERROR_contentChecksum_invalid) {
1058 if (findErrorPos) DISPLAYLEVEL(2, "checksum error detected \n");
1059 if (findErrorPos) locateBuffDiff(srcRef, dst, decompressedSize, o_scenario);
1060 }
1061 if (LZ4F_isError(moreToFlush)) return moreToFlush;
1062
1063 XXH64_update(&xxh64, op, oSize);
1064 totalOut += oSize;
1065 op += oSize;
1066 ip += iSize;
1067 if (o_scenario == o_noncontiguous) {
1068 if (op == oend) return LZ4F_ERROR_GENERIC; /* can theoretically happen with bogus data */
1069 op++; /* create a gap between consecutive output */
1070 }
1071 if (o_scenario==o_overwrite) op = (BYTE*)dst; /* overwrite destination */
1072 if ( (op == oend) /* no more room for output; can happen with bogus input */
1073 && (iSize == 0)) /* no input consumed */
1074 break;
1075 }
1076 if (moreToFlush != 0) return LZ4F_ERROR_decompressionFailed;
1077 if (totalOut) { /* otherwise, it's a skippable frame */
1078 U64 const crcDecoded = XXH64_digest(&xxh64);
1079 if (crcDecoded != crcOrig) {
1080 if (findErrorPos) locateBuffDiff(srcRef, dst, decompressedSize, o_scenario);
1081 return LZ4F_ERROR_contentChecksum_invalid;
1082 } }
1083 return 0;
1084 }
1085
1086
test_lz4f_decompression(const void * cSrc,size_t cSize,const void * srcRef,size_t decompressedSize,U64 crcOrig,U32 * const randState,LZ4F_dctx * const dCtx,U32 seed,U32 testNb,int findErrorPos)1087 size_t test_lz4f_decompression(const void* cSrc, size_t cSize,
1088 const void* srcRef, size_t decompressedSize,
1089 U64 crcOrig,
1090 U32* const randState,
1091 LZ4F_dctx* const dCtx,
1092 U32 seed, U32 testNb,
1093 int findErrorPos)
1094 {
1095 o_scenario_e const o_scenario = (o_scenario_e)(FUZ_rand(randState) % 3); /* 0 : contiguous; 1 : non-contiguous; 2 : dst overwritten */
1096 /* tighten dst buffer conditions */
1097 size_t const dstCapacity = (o_scenario == o_noncontiguous) ?
1098 (decompressedSize * 2) + 128 :
1099 decompressedSize;
1100 size_t result;
1101 void* const dstBuffer = malloc(dstCapacity);
1102 assert(dstBuffer != NULL);
1103
1104 result = test_lz4f_decompression_wBuffers(cSrc, cSize,
1105 dstBuffer, dstCapacity, o_scenario,
1106 srcRef, decompressedSize,
1107 crcOrig,
1108 randState,
1109 dCtx,
1110 seed, testNb, findErrorPos);
1111
1112 free(dstBuffer);
1113 return result;
1114 }
1115
1116
fuzzerTests(U32 seed,unsigned nbTests,unsigned startTest,double compressibility,U32 duration_s)1117 int fuzzerTests(U32 seed, unsigned nbTests, unsigned startTest, double compressibility, U32 duration_s)
1118 {
1119 unsigned testNb = 0;
1120 size_t const CNBufferLength = 9 MB; /* needs to be > 2x4MB to test large blocks */
1121 void* CNBuffer = NULL;
1122 size_t const compressedBufferSize = LZ4F_compressFrameBound(CNBufferLength, NULL) + 4 MB; /* needs some margin */
1123 void* compressedBuffer = NULL;
1124 void* decodedBuffer = NULL;
1125 U32 coreRand = seed;
1126 LZ4F_decompressionContext_t dCtx = NULL;
1127 LZ4F_compressionContext_t cCtx = NULL;
1128 clock_t const startClock = clock();
1129 clock_t const clockDuration = duration_s * CLOCKS_PER_SEC;
1130
1131 /* Create states & buffers */
1132 { size_t const creationStatus = LZ4F_createDecompressionContext(&dCtx, LZ4F_VERSION);
1133 CHECK(LZ4F_isError(creationStatus), "Allocation failed (error %i)", (int)creationStatus); }
1134 { size_t const creationStatus = LZ4F_createCompressionContext(&cCtx, LZ4F_VERSION);
1135 CHECK(LZ4F_isError(creationStatus), "Allocation failed (error %i)", (int)creationStatus); }
1136 CNBuffer = malloc(CNBufferLength);
1137 CHECK(CNBuffer==NULL, "CNBuffer Allocation failed");
1138 compressedBuffer = malloc(compressedBufferSize);
1139 CHECK(compressedBuffer==NULL, "compressedBuffer Allocation failed");
1140 decodedBuffer = calloc(1, CNBufferLength); /* calloc avoids decodedBuffer being considered "garbage" by scan-build */
1141 CHECK(decodedBuffer==NULL, "decodedBuffer Allocation failed");
1142 FUZ_fillCompressibleNoiseBuffer(CNBuffer, CNBufferLength, compressibility, &coreRand);
1143
1144 /* jump to requested testNb */
1145 for (testNb =0; (testNb < startTest); testNb++) (void)FUZ_rand(&coreRand); /* sync randomizer */
1146
1147 /* main fuzzer test loop */
1148 for ( ; (testNb < nbTests) || (clockDuration > FUZ_GetClockSpan(startClock)) ; testNb++) {
1149 U32 randState = coreRand ^ prime1;
1150 unsigned const srcBits = (FUZ_rand(&randState) % (FUZ_highbit((U32)(CNBufferLength-1)) - 1)) + 1;
1151 size_t const srcSize = (FUZ_rand(&randState) & ((1<<srcBits)-1));
1152 size_t const srcStartId = FUZ_rand(&randState) % (CNBufferLength - srcSize);
1153 const BYTE* const srcStart = (const BYTE*)CNBuffer + srcStartId;
1154 unsigned const neverFlush = (FUZ_rand(&randState) & 15) == 1;
1155 U64 const crcOrig = XXH64(srcStart, srcSize, 1);
1156 LZ4F_preferences_t prefs;
1157 const LZ4F_preferences_t* prefsPtr = &prefs;
1158 size_t cSize;
1159
1160 (void)FUZ_rand(&coreRand); /* update seed */
1161 memset(&prefs, 0, sizeof(prefs));
1162 prefs.frameInfo.blockMode = (LZ4F_blockMode_t)(FUZ_rand(&randState) & 1);
1163 prefs.frameInfo.blockSizeID = (LZ4F_blockSizeID_t)(4 + (FUZ_rand(&randState) & 3));
1164 prefs.frameInfo.blockChecksumFlag = (LZ4F_blockChecksum_t)(FUZ_rand(&randState) & 1);
1165 prefs.frameInfo.contentChecksumFlag = (LZ4F_contentChecksum_t)(FUZ_rand(&randState) & 1);
1166 prefs.frameInfo.contentSize = ((FUZ_rand(&randState) & 0xF) == 1) ? srcSize : 0;
1167 prefs.autoFlush = neverFlush ? 0 : (FUZ_rand(&randState) & 7) == 2;
1168 prefs.compressionLevel = -5 + (int)(FUZ_rand(&randState) % 11);
1169 if ((FUZ_rand(&randState) & 0xF) == 1) prefsPtr = NULL;
1170
1171 DISPLAYUPDATE(2, "\r%5u ", testNb);
1172
1173 if ((FUZ_rand(&randState) & 0xFFF) == 0) {
1174 /* create a skippable frame (rare case) */
1175 BYTE* op = (BYTE*)compressedBuffer;
1176 FUZ_writeLE32(op, LZ4F_MAGIC_SKIPPABLE_START + (FUZ_rand(&randState) & 15));
1177 FUZ_writeLE32(op+4, (U32)srcSize);
1178 cSize = srcSize+8;
1179
1180 } else if ((FUZ_rand(&randState) & 0xF) == 2) { /* single pass compression (simple) */
1181 cSize = LZ4F_compressFrame(compressedBuffer, LZ4F_compressFrameBound(srcSize, prefsPtr), srcStart, srcSize, prefsPtr);
1182 CHECK(LZ4F_isError(cSize), "LZ4F_compressFrame failed : error %i (%s)", (int)cSize, LZ4F_getErrorName(cSize));
1183
1184 } else { /* multi-segments compression */
1185 const BYTE* ip = srcStart;
1186 const BYTE* const iend = srcStart + srcSize;
1187 BYTE* op = (BYTE*)compressedBuffer;
1188 BYTE* const oend = op + (neverFlush ? LZ4F_compressFrameBound(srcSize, prefsPtr) : compressedBufferSize); /* when flushes are possible, can't guarantee a max compressed size */
1189 unsigned const maxBits = FUZ_highbit((U32)srcSize);
1190 LZ4F_compressOptions_t cOptions;
1191 memset(&cOptions, 0, sizeof(cOptions));
1192 { size_t const fhSize = LZ4F_compressBegin(cCtx, op, (size_t)(oend-op), prefsPtr);
1193 CHECK(LZ4F_isError(fhSize), "Compression header failed (error %i)",
1194 (int)fhSize);
1195 op += fhSize;
1196 }
1197 while (ip < iend) {
1198 unsigned const nbBitsSeg = FUZ_rand(&randState) % maxBits;
1199 size_t const sampleMax = (FUZ_rand(&randState) & ((1<<nbBitsSeg)-1)) + 1;
1200 size_t iSize = MIN(sampleMax, (size_t)(iend-ip));
1201 size_t const oSize = LZ4F_compressBound(iSize, prefsPtr);
1202 cOptions.stableSrc = ((FUZ_rand(&randState) & 3) == 1);
1203 DISPLAYLEVEL(6, "Sending %u bytes to compress (stableSrc:%u) \n",
1204 (unsigned)iSize, cOptions.stableSrc);
1205
1206 #if 1
1207 /* insert uncompressed segment */
1208 if ( (iSize>0)
1209 && !neverFlush /* do not mess with compressBound when neverFlush is set */
1210 && prefsPtr != NULL /* prefs are set */
1211 && prefs.frameInfo.blockMode == LZ4F_blockIndependent /* uncompressedUpdate is only valid with blockMode==independent */
1212 && (FUZ_rand(&randState) & 15) == 1 ) {
1213 size_t const uSize = FUZ_rand(&randState) % iSize;
1214 size_t const flushedSize = LZ4F_uncompressedUpdate(cCtx, op, (size_t)(oend-op), ip, uSize, &cOptions);
1215 CHECK(LZ4F_isError(flushedSize), "Insert uncompressed data failed (error %i : %s)",
1216 (int)flushedSize, LZ4F_getErrorName(flushedSize));
1217 op += flushedSize;
1218 ip += uSize;
1219 iSize -= uSize;
1220 }
1221 #endif
1222
1223 { size_t const flushedSize = LZ4F_compressUpdate(cCtx, op, oSize, ip, iSize, &cOptions);
1224 CHECK(LZ4F_isError(flushedSize), "Compression failed (error %i : %s)",
1225 (int)flushedSize, LZ4F_getErrorName(flushedSize));
1226 op += flushedSize;
1227 ip += iSize;
1228 }
1229
1230 { unsigned const forceFlush = neverFlush ? 0 : ((FUZ_rand(&randState) & 3) == 1);
1231 if (forceFlush) {
1232 size_t const flushSize = LZ4F_flush(cCtx, op, (size_t)(oend-op), &cOptions);
1233 DISPLAYLEVEL(6,"flushing %u bytes \n", (unsigned)flushSize);
1234 CHECK(LZ4F_isError(flushSize), "Compression failed (error %i)", (int)flushSize);
1235 op += flushSize;
1236 if ((FUZ_rand(&randState) % 1024) == 3) {
1237 /* add an empty block (requires uncompressed flag) */
1238 op[0] = op[1] = op[2] = 0;
1239 op[3] = 0x80; /* 0x80000000U in little-endian format */
1240 op += 4;
1241 if ((prefsPtr!= NULL) && prefsPtr->frameInfo.blockChecksumFlag) {
1242 /* add block checksum (even for empty blocks) */
1243 FUZ_writeLE32(op, XXH32(op, 0, 0));
1244 op += 4;
1245 } } } }
1246 } /* while (ip<iend) */
1247 CHECK(op>=oend, "LZ4F_compressFrameBound overflow");
1248 { size_t const dstEndSafeSize = LZ4F_compressBound(0, prefsPtr);
1249 int const tooSmallDstEnd = ((FUZ_rand(&randState) & 31) == 3);
1250 size_t const dstEndTooSmallSize = (FUZ_rand(&randState) % dstEndSafeSize) + 1;
1251 size_t const dstEndSize = tooSmallDstEnd ? dstEndTooSmallSize : dstEndSafeSize;
1252 BYTE const canaryByte = (BYTE)(FUZ_rand(&randState) & 255);
1253 size_t flushedSize;
1254 DISPLAYLEVEL(7,"canaryByte at pos %u / %u \n",
1255 (unsigned)((size_t)(op - (BYTE*)compressedBuffer) + dstEndSize),
1256 (unsigned)compressedBufferSize);
1257 assert(op + dstEndSize < (BYTE*)compressedBuffer + compressedBufferSize);
1258 op[dstEndSize] = canaryByte;
1259 flushedSize = LZ4F_compressEnd(cCtx, op, dstEndSize, &cOptions);
1260 CHECK(op[dstEndSize] != canaryByte, "LZ4F_compressEnd writes beyond dstCapacity !");
1261 if (LZ4F_isError(flushedSize)) {
1262 if (tooSmallDstEnd) /* failure is allowed */ continue;
1263 CHECK(!tooSmallDstEnd, "Compression completion failed (error %i : %s)",
1264 (int)flushedSize, LZ4F_getErrorName(flushedSize));
1265 }
1266 op += flushedSize;
1267 }
1268 cSize = (size_t)(op - (BYTE*)compressedBuffer);
1269 DISPLAYLEVEL(5, "\nCompressed %u bytes into %u \n", (U32)srcSize, (U32)cSize);
1270 }
1271
1272
1273 /* multi-segments decompression */
1274 DISPLAYLEVEL(6, "normal decompression \n");
1275 { size_t result = test_lz4f_decompression(compressedBuffer, cSize, srcStart, srcSize, crcOrig, &randState, dCtx, seed, testNb, 1 /*findError*/ );
1276 CHECK (LZ4F_isError(result), "multi-segment decompression failed (error %i => %s)",
1277 (int)result, LZ4F_getErrorName(result));
1278 }
1279
1280 /* insert noise into src - ensure decoder survives with no sanitizer error */
1281 { U32 const maxNbBits = FUZ_highbit((U32)cSize);
1282 size_t pos = 0;
1283 for (;;) {
1284 /* keep some original src */
1285 { U32 const nbBits = FUZ_rand(&randState) % maxNbBits;
1286 size_t const mask = (1<<nbBits) - 1;
1287 size_t const skipLength = FUZ_rand(&randState) & mask;
1288 pos += skipLength;
1289 }
1290 if (pos >= cSize) break;
1291 /* add noise */
1292 { U32 const nbBitsCodes = FUZ_rand(&randState) % maxNbBits;
1293 U32 const nbBits = nbBitsCodes ? nbBitsCodes-1 : 0;
1294 size_t const mask = (1<<nbBits) - 1;
1295 size_t const rNoiseLength = (FUZ_rand(&randState) & mask) + 1;
1296 size_t const noiseLength = MIN(rNoiseLength, cSize-pos);
1297 size_t const noiseStart = FUZ_rand(&randState) % (CNBufferLength - noiseLength);
1298 memcpy((BYTE*)compressedBuffer + pos, (const char*)CNBuffer + noiseStart, noiseLength);
1299 pos += noiseLength;
1300 } } }
1301
1302 /* test decompression on noisy src */
1303 DISPLAYLEVEL(6, "noisy decompression \n");
1304 test_lz4f_decompression(compressedBuffer, cSize, srcStart, srcSize, crcOrig, &randState, dCtx, seed, testNb, 0 /*don't search error Pos*/ );
1305 /* note : we don't analyze result here : it probably failed, which is expected.
1306 * The sole purpose is to catch potential out-of-bound reads and writes. */
1307 LZ4F_resetDecompressionContext(dCtx); /* state must be reset to clean after an error */
1308
1309 } /* for ( ; (testNb < nbTests) ; ) */
1310
1311 DISPLAYLEVEL(2, "\rAll tests completed \n");
1312
1313 LZ4F_freeDecompressionContext(dCtx);
1314 LZ4F_freeCompressionContext(cCtx);
1315 free(CNBuffer);
1316 free(compressedBuffer);
1317 free(decodedBuffer);
1318
1319 if (use_pause) {
1320 DISPLAY("press enter to finish \n");
1321 (void)getchar();
1322 }
1323 return 0;
1324 }
1325
1326
FUZ_usage(const char * programName)1327 int FUZ_usage(const char* programName)
1328 {
1329 DISPLAY( "Usage :\n");
1330 DISPLAY( " %s [args]\n", programName);
1331 DISPLAY( "\n");
1332 DISPLAY( "Arguments :\n");
1333 DISPLAY( " -i# : Nb of tests (default:%u) \n", nbTestsDefault);
1334 DISPLAY( " -T# : Duration of tests, in seconds (default: use Nb of tests) \n");
1335 DISPLAY( " -s# : Select seed (default:prompt user)\n");
1336 DISPLAY( " -t# : Select starting test number (default:0)\n");
1337 DISPLAY( " -P# : Select compressibility in %% (default:%i%%)\n", FUZ_COMPRESSIBILITY_DEFAULT);
1338 DISPLAY( " -v : verbose\n");
1339 DISPLAY( " -h : display help and exit\n");
1340 return 0;
1341 }
1342
1343
main(int argc,const char ** argv)1344 int main(int argc, const char** argv)
1345 {
1346 U32 seed=0;
1347 int seedset=0;
1348 int argNb;
1349 unsigned nbTests = nbTestsDefault;
1350 unsigned testNb = 0;
1351 int proba = FUZ_COMPRESSIBILITY_DEFAULT;
1352 U32 duration=0;
1353 const char* const programName = argv[0];
1354
1355 /* Check command line */
1356 for (argNb=1; argNb<argc; argNb++) {
1357 const char* argument = argv[argNb];
1358
1359 if(!argument) continue; /* Protection if argument empty */
1360
1361 /* Decode command (note : aggregated short commands are allowed) */
1362 if (argument[0]=='-') {
1363 if (!strcmp(argument, "--no-prompt")) {
1364 no_prompt=1;
1365 seedset=1;
1366 displayLevel=1;
1367 continue;
1368 }
1369 argument++;
1370
1371 while (*argument!=0) {
1372 switch(*argument)
1373 {
1374 case 'h':
1375 return FUZ_usage(programName);
1376 case 'v':
1377 argument++;
1378 displayLevel++;
1379 break;
1380 case 'q':
1381 argument++;
1382 displayLevel--;
1383 break;
1384 case 'p': /* pause at the end */
1385 argument++;
1386 use_pause = 1;
1387 break;
1388
1389 case 'i':
1390 argument++;
1391 nbTests=0; duration=0;
1392 while ((*argument>='0') && (*argument<='9')) {
1393 nbTests *= 10;
1394 nbTests += (unsigned)(*argument - '0');
1395 argument++;
1396 }
1397 break;
1398
1399 case 'T':
1400 argument++;
1401 nbTests = 0; duration = 0;
1402 for (;;) {
1403 switch(*argument)
1404 {
1405 case 'm': duration *= 60; argument++; continue;
1406 case 's':
1407 case 'n': argument++; continue;
1408 case '0':
1409 case '1':
1410 case '2':
1411 case '3':
1412 case '4':
1413 case '5':
1414 case '6':
1415 case '7':
1416 case '8':
1417 case '9': duration *= 10; duration += (U32)(*argument++ - '0'); continue;
1418 }
1419 break;
1420 }
1421 break;
1422
1423 case 's':
1424 argument++;
1425 seed=0;
1426 seedset=1;
1427 while ((*argument>='0') && (*argument<='9')) {
1428 seed *= 10;
1429 seed += (U32)(*argument - '0');
1430 argument++;
1431 }
1432 break;
1433 case 't':
1434 argument++;
1435 testNb=0;
1436 while ((*argument>='0') && (*argument<='9')) {
1437 testNb *= 10;
1438 testNb += (unsigned)(*argument - '0');
1439 argument++;
1440 }
1441 break;
1442 case 'P': /* compressibility % */
1443 argument++;
1444 proba=0;
1445 while ((*argument>='0') && (*argument<='9')) {
1446 proba *= 10;
1447 proba += *argument - '0';
1448 argument++;
1449 }
1450 if (proba<0) proba=0;
1451 if (proba>100) proba=100;
1452 break;
1453 default:
1454 ;
1455 return FUZ_usage(programName);
1456 }
1457 }
1458 } /* if (argument[0]=='-') */
1459 } /* for (argNb=1; argNb<argc; argNb++) */
1460
1461 DISPLAY("Starting lz4frame tester (%i-bits, %s) \n", (int)(sizeof(size_t)*8), LZ4_VERSION_STRING);
1462
1463 /* Select a random seed if none given */
1464 if (!seedset) {
1465 time_t const t = time(NULL);
1466 U32 const h = XXH32(&t, sizeof(t), 1);
1467 seed = h % 10000;
1468 }
1469 DISPLAY("Seed = %u \n", seed);
1470 if (proba != FUZ_COMPRESSIBILITY_DEFAULT)
1471 DISPLAY("Compressibility : %i%% \n", proba);
1472
1473 { double const compressibility = (double)proba / 100;
1474 /* start by unit tests if not requesting a specific run nb */
1475 if (testNb==0) {
1476 if (unitTests(seed, compressibility))
1477 return 1;
1478 }
1479
1480 nbTests += (nbTests==0); /* avoid zero */
1481 return fuzzerTests(seed, nbTests, testNb, compressibility, duration);
1482 }
1483 }
1484