1 /*
2 fuzzer.c - Fuzzer test tool for LZ4
3 Copyright (C) Yann Collet 2012-2015
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 source repository : http://code.google.com/p/lz4
23 - LZ4 source mirror : https://github.com/Cyan4973/lz4
24 - LZ4 public forum : https://groups.google.com/forum/#!forum/lz4c
25 */
26
27 /**************************************
28 * Remove Visual warning messages
29 **************************************/
30 #ifdef _MSC_VER /* Visual Studio */
31 # define _CRT_SECURE_NO_WARNINGS /* fgets */
32 # pragma warning(disable : 4127) /* disable: C4127: conditional expression is constant */
33 # pragma warning(disable : 4146) /* disable: C4146: minus unsigned expression */
34 # pragma warning(disable : 4310) /* disable: C4310: constant char value > 127 */
35 #endif
36
37
38 /**************************************
39 * Includes
40 **************************************/
41 #include <stdlib.h>
42 #include <stdio.h> /* fgets, sscanf */
43 #include <sys/timeb.h> /* timeb */
44 #include <string.h> /* strcmp */
45 #include "lz4.h"
46 #include "lz4hc.h"
47 #include "xxhash.h"
48
49
50 /**************************************
51 * Basic Types
52 **************************************/
53 #if defined (__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) /* C99 */
54 # include <stdint.h>
55 typedef uint8_t BYTE;
56 typedef uint16_t U16;
57 typedef uint32_t U32;
58 typedef int32_t S32;
59 typedef uint64_t U64;
60 #else
61 typedef unsigned char BYTE;
62 typedef unsigned short U16;
63 typedef unsigned int U32;
64 typedef signed int S32;
65 typedef unsigned long long U64;
66 #endif
67
68
69 /**************************************
70 * Constants
71 **************************************/
72 #ifndef LZ4_VERSION
73 # define LZ4_VERSION ""
74 #endif
75
76 #define NB_ATTEMPTS (1<<16)
77 #define COMPRESSIBLE_NOISE_LENGTH (1 << 21)
78 #define FUZ_MAX_BLOCK_SIZE (1 << 17)
79 #define FUZ_MAX_DICT_SIZE (1 << 15)
80 #define FUZ_COMPRESSIBILITY_DEFAULT 60
81 #define PRIME1 2654435761U
82 #define PRIME2 2246822519U
83 #define PRIME3 3266489917U
84
85 #define KB *(1U<<10)
86 #define MB *(1U<<20)
87 #define GB *(1U<<30)
88
89
90 /*****************************************
91 * Macros
92 *****************************************/
93 #define DISPLAY(...) fprintf(stderr, __VA_ARGS__)
94 #define DISPLAYLEVEL(l, ...) if (g_displayLevel>=l) { DISPLAY(__VA_ARGS__); }
95 static int g_displayLevel = 2;
96 static const U32 g_refreshRate = 250;
97 static U32 g_time = 0;
98
99
100 /*********************************************************
101 Fuzzer functions
102 *********************************************************/
FUZ_GetMilliStart(void)103 static U32 FUZ_GetMilliStart(void)
104 {
105 struct timeb tb;
106 U32 nCount;
107 ftime( &tb );
108 nCount = (U32) (((tb.time & 0xFFFFF) * 1000) + tb.millitm);
109 return nCount;
110 }
111
FUZ_GetMilliSpan(U32 nTimeStart)112 static U32 FUZ_GetMilliSpan(U32 nTimeStart)
113 {
114 U32 nCurrent = FUZ_GetMilliStart();
115 U32 nSpan = nCurrent - nTimeStart;
116 if (nTimeStart > nCurrent)
117 nSpan += 0x100000 * 1000;
118 return nSpan;
119 }
120
FUZ_rotl32(U32 u32,U32 nbBits)121 static U32 FUZ_rotl32(U32 u32, U32 nbBits)
122 {
123 return ((u32 << nbBits) | (u32 >> (32 - nbBits)));
124 }
125
FUZ_rand(U32 * src)126 static U32 FUZ_rand(U32* src)
127 {
128 U32 rand32 = *src;
129 rand32 *= PRIME1;
130 rand32 += PRIME2;
131 rand32 = FUZ_rotl32(rand32, 13);
132 *src = rand32;
133 return rand32 >> 3;
134 }
135
136
137 #define FUZ_RAND15BITS ((FUZ_rand(seed) >> 3) & 32767)
138 #define FUZ_RANDLENGTH ( ((FUZ_rand(seed) >> 7) & 3) ? (FUZ_rand(seed) % 15) : (FUZ_rand(seed) % 510) + 15)
FUZ_fillCompressibleNoiseBuffer(void * buffer,size_t bufferSize,double proba,U32 * seed)139 static void FUZ_fillCompressibleNoiseBuffer(void* buffer, size_t bufferSize, double proba, U32* seed)
140 {
141 BYTE* BBuffer = (BYTE*)buffer;
142 size_t pos = 0;
143 U32 P32 = (U32)(32768 * proba);
144
145 // First Byte
146 BBuffer[pos++] = (BYTE)(FUZ_rand(seed));
147
148 while (pos < bufferSize)
149 {
150 // Select : Literal (noise) or copy (within 64K)
151 if (FUZ_RAND15BITS < P32)
152 {
153 // Copy (within 64K)
154 size_t match, d;
155 size_t length = FUZ_RANDLENGTH + 4;
156 size_t offset = FUZ_RAND15BITS + 1;
157 if (offset > pos) offset = pos;
158 d = pos + length;
159 if (d > bufferSize) d = bufferSize;
160 match = pos - offset;
161 while (pos < d) BBuffer[pos++] = BBuffer[match++];
162 }
163 else
164 {
165 // Literal (noise)
166 size_t d;
167 size_t length = FUZ_RANDLENGTH;
168 d = pos + length;
169 if (d > bufferSize) d = bufferSize;
170 while (pos < d) BBuffer[pos++] = (BYTE)(FUZ_rand(seed) >> 5);
171 }
172 }
173 }
174
175
176 #define MAX_NB_BUFF_I134 150
177 #define BLOCKSIZE_I134 (32 MB)
FUZ_AddressOverflow(void)178 static int FUZ_AddressOverflow(void)
179 {
180 char* buffers[MAX_NB_BUFF_I134+1] = {0};
181 int i, nbBuff=0;
182 int highAddress = 0;
183
184 printf("Overflow tests : ");
185
186 // Only possible in 32-bits
187 if (sizeof(void*)==8)
188 {
189 printf("64 bits mode : no overflow \n");
190 fflush(stdout);
191 return 0;
192 }
193
194 buffers[0] = (char*)malloc(BLOCKSIZE_I134);
195 buffers[1] = (char*)malloc(BLOCKSIZE_I134);
196 if ((!buffers[0]) || (!buffers[1]))
197 {
198 printf("not enough memory for tests \n");
199 return 0;
200 }
201 for (nbBuff=2; nbBuff < MAX_NB_BUFF_I134; nbBuff++)
202 {
203 printf("%3i \b\b\b\b", nbBuff);
204 buffers[nbBuff] = (char*)malloc(BLOCKSIZE_I134);
205 //printf("%08X ", (U32)(size_t)(buffers[nbBuff]));
206 fflush(stdout);
207
208 if (((size_t)buffers[nbBuff] > (size_t)0x80000000) && (!highAddress))
209 {
210 printf("high address detected : ");
211 fflush(stdout);
212 highAddress=1;
213 }
214 if (buffers[nbBuff]==NULL) goto _endOfTests;
215
216 {
217 size_t sizeToGenerateOverflow = (size_t)(- ((size_t)buffers[nbBuff-1]) + 512);
218 int nbOf255 = (int)((sizeToGenerateOverflow / 255) + 1);
219 char* input = buffers[nbBuff-1];
220 char* output = buffers[nbBuff];
221 int r;
222 input[0] = (char)0xF0; // Literal length overflow
223 input[1] = (char)0xFF;
224 input[2] = (char)0xFF;
225 input[3] = (char)0xFF;
226 for(i = 4; i <= nbOf255+4; i++) input[i] = (char)0xff;
227 r = LZ4_decompress_safe(input, output, nbOf255+64, BLOCKSIZE_I134);
228 if (r>0) goto _overflowError;
229 input[0] = (char)0x1F; // Match length overflow
230 input[1] = (char)0x01;
231 input[2] = (char)0x01;
232 input[3] = (char)0x00;
233 r = LZ4_decompress_safe(input, output, nbOf255+64, BLOCKSIZE_I134);
234 if (r>0) goto _overflowError;
235
236 output = buffers[nbBuff-2]; // Reverse in/out pointer order
237 input[0] = (char)0xF0; // Literal length overflow
238 input[1] = (char)0xFF;
239 input[2] = (char)0xFF;
240 input[3] = (char)0xFF;
241 r = LZ4_decompress_safe(input, output, nbOf255+64, BLOCKSIZE_I134);
242 if (r>0) goto _overflowError;
243 input[0] = (char)0x1F; // Match length overflow
244 input[1] = (char)0x01;
245 input[2] = (char)0x01;
246 input[3] = (char)0x00;
247 r = LZ4_decompress_safe(input, output, nbOf255+64, BLOCKSIZE_I134);
248 if (r>0) goto _overflowError;
249 }
250 }
251
252 nbBuff++;
253 _endOfTests:
254 for (i=0 ; i<nbBuff; i++) free(buffers[i]);
255 if (!highAddress) printf("high address not possible \n");
256 else printf("all overflows correctly detected \n");
257 return 0;
258
259 _overflowError:
260 printf("Address space overflow error !! \n");
261 exit(1);
262 }
263
264
FUZ_displayUpdate(unsigned testNb)265 static void FUZ_displayUpdate(unsigned testNb)
266 {
267 if ((FUZ_GetMilliSpan(g_time) > g_refreshRate) || (g_displayLevel>=3))
268 {
269 g_time = FUZ_GetMilliStart();
270 DISPLAY("\r%5u ", testNb);
271 if (g_displayLevel>=3) fflush(stdout);
272 }
273 }
274
275
FUZ_test(U32 seed,const U32 nbCycles,const U32 startCycle,const double compressibility)276 static int FUZ_test(U32 seed, const U32 nbCycles, const U32 startCycle, const double compressibility)
277 {
278 unsigned long long bytes = 0;
279 unsigned long long cbytes = 0;
280 unsigned long long hcbytes = 0;
281 unsigned long long ccbytes = 0;
282 void* CNBuffer;
283 char* compressedBuffer;
284 char* decodedBuffer;
285 # define FUZ_max LZ4_COMPRESSBOUND(LEN)
286 int ret;
287 unsigned cycleNb;
288 # define FUZ_CHECKTEST(cond, ...) if (cond) { printf("Test %u : ", testNb); printf(__VA_ARGS__); \
289 printf(" (seed %u, cycle %u) \n", seed, cycleNb); goto _output_error; }
290 # define FUZ_DISPLAYTEST { testNb++; g_displayLevel<3 ? 0 : printf("%2u\b\b", testNb); if (g_displayLevel==4) fflush(stdout); }
291 void* stateLZ4 = malloc(LZ4_sizeofState());
292 void* stateLZ4HC = malloc(LZ4_sizeofStateHC());
293 void* LZ4continue;
294 LZ4_stream_t LZ4dict;
295 LZ4_streamHC_t LZ4dictHC;
296 U32 crcOrig, crcCheck;
297 U32 coreRandState = seed;
298 U32 randState = coreRandState ^ PRIME3;
299
300
301 // init
302 memset(&LZ4dict, 0, sizeof(LZ4dict));
303
304 // Create compressible test buffer
305 CNBuffer = malloc(COMPRESSIBLE_NOISE_LENGTH);
306 FUZ_fillCompressibleNoiseBuffer(CNBuffer, COMPRESSIBLE_NOISE_LENGTH, compressibility, &randState);
307 compressedBuffer = (char*)malloc(LZ4_compressBound(FUZ_MAX_BLOCK_SIZE));
308 decodedBuffer = (char*)malloc(FUZ_MAX_DICT_SIZE + FUZ_MAX_BLOCK_SIZE);
309
310 // move to startCycle
311 for (cycleNb = 0; cycleNb < startCycle; cycleNb++)
312 {
313 (void)FUZ_rand(&coreRandState);
314
315 if (0) // some problems related to dictionary re-use; in this case, enable this loop
316 {
317 int dictSize, blockSize, blockStart;
318 char* dict;
319 char* block;
320 FUZ_displayUpdate(cycleNb);
321 randState = coreRandState ^ PRIME3;
322 blockSize = FUZ_rand(&randState) % FUZ_MAX_BLOCK_SIZE;
323 blockStart = FUZ_rand(&randState) % (COMPRESSIBLE_NOISE_LENGTH - blockSize);
324 dictSize = FUZ_rand(&randState) % FUZ_MAX_DICT_SIZE;
325 if (dictSize > blockStart) dictSize = blockStart;
326 block = ((char*)CNBuffer) + blockStart;
327 dict = block - dictSize;
328 LZ4_loadDict(&LZ4dict, dict, dictSize);
329 LZ4_compress_continue(&LZ4dict, block, compressedBuffer, blockSize);
330 LZ4_loadDict(&LZ4dict, dict, dictSize);
331 LZ4_compress_continue(&LZ4dict, block, compressedBuffer, blockSize);
332 LZ4_loadDict(&LZ4dict, dict, dictSize);
333 LZ4_compress_continue(&LZ4dict, block, compressedBuffer, blockSize);
334 }
335 }
336
337 // Test loop
338 for (cycleNb = startCycle; cycleNb < nbCycles; cycleNb++)
339 {
340 U32 testNb = 0;
341 char* dict;
342 char* block;
343 int dictSize, blockSize, blockStart, compressedSize, HCcompressedSize;
344 int blockContinueCompressedSize;
345
346 FUZ_displayUpdate(cycleNb);
347 (void)FUZ_rand(&coreRandState);
348 randState = coreRandState ^ PRIME3;
349
350 // Select block to test
351 blockSize = FUZ_rand(&randState) % FUZ_MAX_BLOCK_SIZE;
352 blockStart = FUZ_rand(&randState) % (COMPRESSIBLE_NOISE_LENGTH - blockSize);
353 dictSize = FUZ_rand(&randState) % FUZ_MAX_DICT_SIZE;
354 if (dictSize > blockStart) dictSize = blockStart;
355 block = ((char*)CNBuffer) + blockStart;
356 dict = block - dictSize;
357
358 /* Compression tests */
359
360 // Test compression HC
361 FUZ_DISPLAYTEST;
362 ret = LZ4_compressHC(block, compressedBuffer, blockSize);
363 FUZ_CHECKTEST(ret==0, "LZ4_compressHC() failed");
364 HCcompressedSize = ret;
365
366 // Test compression HC using external state
367 FUZ_DISPLAYTEST;
368 ret = LZ4_compressHC_withStateHC(stateLZ4HC, block, compressedBuffer, blockSize);
369 FUZ_CHECKTEST(ret==0, "LZ4_compressHC_withStateHC() failed");
370
371 // Test compression using external state
372 FUZ_DISPLAYTEST;
373 ret = LZ4_compress_withState(stateLZ4, block, compressedBuffer, blockSize);
374 FUZ_CHECKTEST(ret==0, "LZ4_compress_withState() failed");
375
376 // Test compression
377 FUZ_DISPLAYTEST;
378 ret = LZ4_compress(block, compressedBuffer, blockSize);
379 FUZ_CHECKTEST(ret==0, "LZ4_compress() failed");
380 compressedSize = ret;
381
382 /* Decompression tests */
383
384 crcOrig = XXH32(block, blockSize, 0);
385
386 // Test decoding with output size being exactly what's necessary => must work
387 FUZ_DISPLAYTEST;
388 ret = LZ4_decompress_fast(compressedBuffer, decodedBuffer, blockSize);
389 FUZ_CHECKTEST(ret<0, "LZ4_decompress_fast failed despite correct space");
390 FUZ_CHECKTEST(ret!=compressedSize, "LZ4_decompress_fast failed : did not fully read compressed data");
391 crcCheck = XXH32(decodedBuffer, blockSize, 0);
392 FUZ_CHECKTEST(crcCheck!=crcOrig, "LZ4_decompress_fast corrupted decoded data");
393
394 // Test decoding with one byte missing => must fail
395 FUZ_DISPLAYTEST;
396 decodedBuffer[blockSize-1] = 0;
397 ret = LZ4_decompress_fast(compressedBuffer, decodedBuffer, blockSize-1);
398 FUZ_CHECKTEST(ret>=0, "LZ4_decompress_fast should have failed, due to Output Size being too small");
399 FUZ_CHECKTEST(decodedBuffer[blockSize-1], "LZ4_decompress_fast overrun specified output buffer");
400
401 // Test decoding with one byte too much => must fail
402 FUZ_DISPLAYTEST;
403 ret = LZ4_decompress_fast(compressedBuffer, decodedBuffer, blockSize+1);
404 FUZ_CHECKTEST(ret>=0, "LZ4_decompress_fast should have failed, due to Output Size being too large");
405
406 // Test decoding with output size exactly what's necessary => must work
407 FUZ_DISPLAYTEST;
408 decodedBuffer[blockSize] = 0;
409 ret = LZ4_decompress_safe(compressedBuffer, decodedBuffer, compressedSize, blockSize);
410 FUZ_CHECKTEST(ret<0, "LZ4_decompress_safe failed despite sufficient space");
411 FUZ_CHECKTEST(ret!=blockSize, "LZ4_decompress_safe did not regenerate original data");
412 FUZ_CHECKTEST(decodedBuffer[blockSize], "LZ4_decompress_safe overrun specified output buffer size");
413 crcCheck = XXH32(decodedBuffer, blockSize, 0);
414 FUZ_CHECKTEST(crcCheck!=crcOrig, "LZ4_decompress_safe corrupted decoded data");
415
416 // Test decoding with more than enough output size => must work
417 FUZ_DISPLAYTEST;
418 decodedBuffer[blockSize] = 0;
419 decodedBuffer[blockSize+1] = 0;
420 ret = LZ4_decompress_safe(compressedBuffer, decodedBuffer, compressedSize, blockSize+1);
421 FUZ_CHECKTEST(ret<0, "LZ4_decompress_safe failed despite amply sufficient space");
422 FUZ_CHECKTEST(ret!=blockSize, "LZ4_decompress_safe did not regenerate original data");
423 //FUZ_CHECKTEST(decodedBuffer[blockSize], "LZ4_decompress_safe wrote more than (unknown) target size"); // well, is that an issue ?
424 FUZ_CHECKTEST(decodedBuffer[blockSize+1], "LZ4_decompress_safe overrun specified output buffer size");
425 crcCheck = XXH32(decodedBuffer, blockSize, 0);
426 FUZ_CHECKTEST(crcCheck!=crcOrig, "LZ4_decompress_safe corrupted decoded data");
427
428 // Test decoding with output size being one byte too short => must fail
429 FUZ_DISPLAYTEST;
430 decodedBuffer[blockSize-1] = 0;
431 ret = LZ4_decompress_safe(compressedBuffer, decodedBuffer, compressedSize, blockSize-1);
432 FUZ_CHECKTEST(ret>=0, "LZ4_decompress_safe should have failed, due to Output Size being one byte too short");
433 FUZ_CHECKTEST(decodedBuffer[blockSize-1], "LZ4_decompress_safe overrun specified output buffer size");
434
435 // Test decoding with output size being 10 bytes too short => must fail
436 FUZ_DISPLAYTEST;
437 if (blockSize>10)
438 {
439 decodedBuffer[blockSize-10] = 0;
440 ret = LZ4_decompress_safe(compressedBuffer, decodedBuffer, compressedSize, blockSize-10);
441 FUZ_CHECKTEST(ret>=0, "LZ4_decompress_safe should have failed, due to Output Size being 10 bytes too short");
442 FUZ_CHECKTEST(decodedBuffer[blockSize-10], "LZ4_decompress_safe overrun specified output buffer size");
443 }
444
445 // Test decoding with input size being one byte too short => must fail
446 FUZ_DISPLAYTEST;
447 ret = LZ4_decompress_safe(compressedBuffer, decodedBuffer, compressedSize-1, blockSize);
448 FUZ_CHECKTEST(ret>=0, "LZ4_decompress_safe should have failed, due to input size being one byte too short (blockSize=%i, ret=%i, compressedSize=%i)", blockSize, ret, compressedSize);
449
450 // Test decoding with input size being one byte too large => must fail
451 FUZ_DISPLAYTEST;
452 decodedBuffer[blockSize] = 0;
453 ret = LZ4_decompress_safe(compressedBuffer, decodedBuffer, compressedSize+1, blockSize);
454 FUZ_CHECKTEST(ret>=0, "LZ4_decompress_safe should have failed, due to input size being too large");
455 FUZ_CHECKTEST(decodedBuffer[blockSize], "LZ4_decompress_safe overrun specified output buffer size");
456
457 // Test partial decoding with target output size being max/2 => must work
458 FUZ_DISPLAYTEST;
459 ret = LZ4_decompress_safe_partial(compressedBuffer, decodedBuffer, compressedSize, blockSize/2, blockSize);
460 FUZ_CHECKTEST(ret<0, "LZ4_decompress_safe_partial failed despite sufficient space");
461
462 // Test partial decoding with target output size being just below max => must work
463 FUZ_DISPLAYTEST;
464 ret = LZ4_decompress_safe_partial(compressedBuffer, decodedBuffer, compressedSize, blockSize-3, blockSize);
465 FUZ_CHECKTEST(ret<0, "LZ4_decompress_safe_partial failed despite sufficient space");
466
467 /* Test Compression with limited output size */
468
469 /* Test compression with output size being exactly what's necessary (should work) */
470 FUZ_DISPLAYTEST;
471 ret = LZ4_compress_limitedOutput(block, compressedBuffer, blockSize, compressedSize);
472 FUZ_CHECKTEST(ret==0, "LZ4_compress_limitedOutput() failed despite sufficient space");
473
474 /* Test compression with output size being exactly what's necessary and external state (should work) */
475 FUZ_DISPLAYTEST;
476 ret = LZ4_compress_limitedOutput_withState(stateLZ4, block, compressedBuffer, blockSize, compressedSize);
477 FUZ_CHECKTEST(ret==0, "LZ4_compress_limitedOutput_withState() failed despite sufficient space");
478
479 /* Test HC compression with output size being exactly what's necessary (should work) */
480 FUZ_DISPLAYTEST;
481 ret = LZ4_compressHC_limitedOutput(block, compressedBuffer, blockSize, HCcompressedSize);
482 FUZ_CHECKTEST(ret==0, "LZ4_compressHC_limitedOutput() failed despite sufficient space");
483
484 /* Test HC compression with output size being exactly what's necessary (should work) */
485 FUZ_DISPLAYTEST;
486 ret = LZ4_compressHC_limitedOutput_withStateHC(stateLZ4HC, block, compressedBuffer, blockSize, HCcompressedSize);
487 FUZ_CHECKTEST(ret==0, "LZ4_compressHC_limitedOutput_withStateHC() failed despite sufficient space");
488
489 /* Test compression with missing bytes into output buffer => must fail */
490 FUZ_DISPLAYTEST;
491 {
492 int missingBytes = (FUZ_rand(&randState) % 0x3F) + 1;
493 if (missingBytes >= compressedSize) missingBytes = compressedSize-1;
494 missingBytes += !missingBytes; /* avoid special case missingBytes==0 */
495 compressedBuffer[compressedSize-missingBytes] = 0;
496 ret = LZ4_compress_limitedOutput(block, compressedBuffer, blockSize, compressedSize-missingBytes);
497 FUZ_CHECKTEST(ret, "LZ4_compress_limitedOutput should have failed (output buffer too small by %i byte)", missingBytes);
498 FUZ_CHECKTEST(compressedBuffer[compressedSize-missingBytes], "LZ4_compress_limitedOutput overran output buffer ! (%i missingBytes)", missingBytes)
499 }
500
501 /* Test HC compression with missing bytes into output buffer => must fail */
502 FUZ_DISPLAYTEST;
503 {
504 int missingBytes = (FUZ_rand(&randState) % 0x3F) + 1;
505 if (missingBytes >= HCcompressedSize) missingBytes = HCcompressedSize-1;
506 missingBytes += !missingBytes; /* avoid special case missingBytes==0 */
507 compressedBuffer[HCcompressedSize-missingBytes] = 0;
508 ret = LZ4_compressHC_limitedOutput(block, compressedBuffer, blockSize, HCcompressedSize-missingBytes);
509 FUZ_CHECKTEST(ret, "LZ4_compressHC_limitedOutput should have failed (output buffer too small by %i byte)", missingBytes);
510 FUZ_CHECKTEST(compressedBuffer[HCcompressedSize-missingBytes], "LZ4_compressHC_limitedOutput overran output buffer ! (%i missingBytes)", missingBytes)
511 }
512
513
514 /********************/
515 /* Dictionary tests */
516 /********************/
517
518 /* Compress using dictionary */
519 FUZ_DISPLAYTEST;
520 LZ4continue = LZ4_create (dict);
521 LZ4_compress_continue ((LZ4_stream_t*)LZ4continue, dict, compressedBuffer, dictSize); // Just to fill hash tables
522 blockContinueCompressedSize = LZ4_compress_continue ((LZ4_stream_t*)LZ4continue, block, compressedBuffer, blockSize);
523 FUZ_CHECKTEST(blockContinueCompressedSize==0, "LZ4_compress_continue failed");
524 free (LZ4continue);
525
526 /* Decompress with dictionary as prefix */
527 FUZ_DISPLAYTEST;
528 memcpy(decodedBuffer, dict, dictSize);
529 ret = LZ4_decompress_fast_withPrefix64k(compressedBuffer, decodedBuffer+dictSize, blockSize);
530 FUZ_CHECKTEST(ret!=blockContinueCompressedSize, "LZ4_decompress_fast_withPrefix64k did not read all compressed block input");
531 crcCheck = XXH32(decodedBuffer+dictSize, blockSize, 0);
532 if (crcCheck!=crcOrig)
533 {
534 int i=0;
535 while (block[i]==decodedBuffer[i]) i++;
536 printf("Wrong Byte at position %i/%i\n", i, blockSize);
537
538 }
539 FUZ_CHECKTEST(crcCheck!=crcOrig, "LZ4_decompress_fast_withPrefix64k corrupted decoded data (dict %i)", dictSize);
540
541 FUZ_DISPLAYTEST;
542 ret = LZ4_decompress_safe_withPrefix64k(compressedBuffer, decodedBuffer+dictSize, blockContinueCompressedSize, blockSize);
543 FUZ_CHECKTEST(ret!=blockSize, "LZ4_decompress_safe_withPrefix64k did not regenerate original data");
544 crcCheck = XXH32(decodedBuffer+dictSize, blockSize, 0);
545 FUZ_CHECKTEST(crcCheck!=crcOrig, "LZ4_decompress_safe_withPrefix64k corrupted decoded data");
546
547 // Compress using External dictionary
548 FUZ_DISPLAYTEST;
549 dict -= (FUZ_rand(&randState) & 0xF) + 1; // Separation, so it is an ExtDict
550 if (dict < (char*)CNBuffer) dict = (char*)CNBuffer;
551 LZ4_loadDict(&LZ4dict, dict, dictSize);
552 blockContinueCompressedSize = LZ4_compress_continue(&LZ4dict, block, compressedBuffer, blockSize);
553 FUZ_CHECKTEST(blockContinueCompressedSize==0, "LZ4_compress_continue failed");
554
555 FUZ_DISPLAYTEST;
556 LZ4_loadDict(&LZ4dict, dict, dictSize);
557 ret = LZ4_compress_limitedOutput_continue(&LZ4dict, block, compressedBuffer, blockSize, blockContinueCompressedSize-1);
558 FUZ_CHECKTEST(ret>0, "LZ4_compress_limitedOutput_continue using ExtDict should fail : one missing byte for output buffer");
559
560 FUZ_DISPLAYTEST;
561 LZ4_loadDict(&LZ4dict, dict, dictSize);
562 ret = LZ4_compress_limitedOutput_continue(&LZ4dict, block, compressedBuffer, blockSize, blockContinueCompressedSize);
563 FUZ_CHECKTEST(ret!=blockContinueCompressedSize, "LZ4_compress_limitedOutput_compressed size is different (%i != %i)", ret, blockContinueCompressedSize);
564 FUZ_CHECKTEST(ret<=0, "LZ4_compress_limitedOutput_continue should work : enough size available within output buffer");
565
566 // Decompress with dictionary as external
567 FUZ_DISPLAYTEST;
568 decodedBuffer[blockSize] = 0;
569 ret = LZ4_decompress_fast_usingDict(compressedBuffer, decodedBuffer, blockSize, dict, dictSize);
570 FUZ_CHECKTEST(ret!=blockContinueCompressedSize, "LZ4_decompress_fast_usingDict did not read all compressed block input");
571 FUZ_CHECKTEST(decodedBuffer[blockSize], "LZ4_decompress_fast_usingDict overrun specified output buffer size")
572 crcCheck = XXH32(decodedBuffer, blockSize, 0);
573 if (crcCheck!=crcOrig)
574 {
575 int i=0;
576 while (block[i]==decodedBuffer[i]) i++;
577 printf("Wrong Byte at position %i/%i\n", i, blockSize);
578 }
579 FUZ_CHECKTEST(crcCheck!=crcOrig, "LZ4_decompress_fast_usingDict corrupted decoded data (dict %i)", dictSize);
580
581 FUZ_DISPLAYTEST;
582 decodedBuffer[blockSize] = 0;
583 ret = LZ4_decompress_safe_usingDict(compressedBuffer, decodedBuffer, blockContinueCompressedSize, blockSize, dict, dictSize);
584 FUZ_CHECKTEST(ret!=blockSize, "LZ4_decompress_safe_usingDict did not regenerate original data");
585 FUZ_CHECKTEST(decodedBuffer[blockSize], "LZ4_decompress_safe_usingDict overrun specified output buffer size")
586 crcCheck = XXH32(decodedBuffer, blockSize, 0);
587 FUZ_CHECKTEST(crcCheck!=crcOrig, "LZ4_decompress_safe_usingDict corrupted decoded data");
588
589 FUZ_DISPLAYTEST;
590 decodedBuffer[blockSize-1] = 0;
591 ret = LZ4_decompress_fast_usingDict(compressedBuffer, decodedBuffer, blockSize-1, dict, dictSize);
592 FUZ_CHECKTEST(ret>=0, "LZ4_decompress_fast_withDict should have failed : wrong original size (-1 byte)");
593 FUZ_CHECKTEST(decodedBuffer[blockSize-1], "LZ4_decompress_fast_usingDict overrun specified output buffer size");
594
595 FUZ_DISPLAYTEST;
596 decodedBuffer[blockSize-1] = 0;
597 ret = LZ4_decompress_safe_usingDict(compressedBuffer, decodedBuffer, blockContinueCompressedSize, blockSize-1, dict, dictSize);
598 FUZ_CHECKTEST(ret>=0, "LZ4_decompress_safe_usingDict should have failed : not enough output size (-1 byte)");
599 FUZ_CHECKTEST(decodedBuffer[blockSize-1], "LZ4_decompress_safe_usingDict overrun specified output buffer size");
600
601 FUZ_DISPLAYTEST;
602 {
603 U32 missingBytes = (FUZ_rand(&randState) & 0xF) + 2;
604 if ((U32)blockSize > missingBytes)
605 {
606 decodedBuffer[blockSize-missingBytes] = 0;
607 ret = LZ4_decompress_safe_usingDict(compressedBuffer, decodedBuffer, blockContinueCompressedSize, blockSize-missingBytes, dict, dictSize);
608 FUZ_CHECKTEST(ret>=0, "LZ4_decompress_safe_usingDict should have failed : output buffer too small (-%u byte)", missingBytes);
609 FUZ_CHECKTEST(decodedBuffer[blockSize-missingBytes], "LZ4_decompress_safe_usingDict overrun specified output buffer size (-%u byte) (blockSize=%i)", missingBytes, blockSize);
610 }
611 }
612
613 // Compress HC using External dictionary
614 FUZ_DISPLAYTEST;
615 dict -= (FUZ_rand(&randState) & 7); // even bigger separation
616 if (dict < (char*)CNBuffer) dict = (char*)CNBuffer;
617 LZ4_resetStreamHC (&LZ4dictHC, FUZ_rand(&randState) & 0x7);
618 LZ4_loadDictHC(&LZ4dictHC, dict, dictSize);
619 blockContinueCompressedSize = LZ4_compressHC_continue(&LZ4dictHC, block, compressedBuffer, blockSize);
620 FUZ_CHECKTEST(blockContinueCompressedSize==0, "LZ4_compressHC_continue failed");
621
622 FUZ_DISPLAYTEST;
623 LZ4_loadDictHC(&LZ4dictHC, dict, dictSize);
624 ret = LZ4_compressHC_limitedOutput_continue(&LZ4dictHC, block, compressedBuffer, blockSize, blockContinueCompressedSize-1);
625 FUZ_CHECKTEST(ret>0, "LZ4_compressHC_limitedOutput_continue using ExtDict should fail : one missing byte for output buffer");
626
627 FUZ_DISPLAYTEST;
628 LZ4_loadDictHC(&LZ4dictHC, dict, dictSize);
629 ret = LZ4_compressHC_limitedOutput_continue(&LZ4dictHC, block, compressedBuffer, blockSize, blockContinueCompressedSize);
630 FUZ_CHECKTEST(ret!=blockContinueCompressedSize, "LZ4_compress_limitedOutput_compressed size is different (%i != %i)", ret, blockContinueCompressedSize);
631 FUZ_CHECKTEST(ret<=0, "LZ4_compress_limitedOutput_continue should work : enough size available within output buffer");
632
633 FUZ_DISPLAYTEST;
634 decodedBuffer[blockSize] = 0;
635 ret = LZ4_decompress_safe_usingDict(compressedBuffer, decodedBuffer, blockContinueCompressedSize, blockSize, dict, dictSize);
636 FUZ_CHECKTEST(ret!=blockSize, "LZ4_decompress_safe_usingDict did not regenerate original data");
637 FUZ_CHECKTEST(decodedBuffer[blockSize], "LZ4_decompress_safe_usingDict overrun specified output buffer size")
638 crcCheck = XXH32(decodedBuffer, blockSize, 0);
639 if (crcCheck!=crcOrig)
640 {
641 int i=0;
642 while (block[i]==decodedBuffer[i]) i++;
643 printf("Wrong Byte at position %i/%i\n", i, blockSize);
644 }
645 FUZ_CHECKTEST(crcCheck!=crcOrig, "LZ4_decompress_safe_usingDict corrupted decoded data");
646
647
648 // ***** End of tests *** //
649 // Fill stats
650 bytes += blockSize;
651 cbytes += compressedSize;
652 hcbytes += HCcompressedSize;
653 ccbytes += blockContinueCompressedSize;
654 }
655
656 printf("\r%7u /%7u - ", cycleNb, nbCycles);
657 printf("all tests completed successfully \n");
658 printf("compression ratio: %0.3f%%\n", (double)cbytes/bytes*100);
659 printf("HC compression ratio: %0.3f%%\n", (double)hcbytes/bytes*100);
660 printf("ratio with dict: %0.3f%%\n", (double)ccbytes/bytes*100);
661
662 // unalloc
663 {
664 int result = 0;
665 _exit:
666 free(CNBuffer);
667 free(compressedBuffer);
668 free(decodedBuffer);
669 free(stateLZ4);
670 free(stateLZ4HC);
671 return result;
672
673 _output_error:
674 result = 1;
675 goto _exit;
676 }
677 }
678
679
680 #define testInputSize (192 KB)
681 #define testCompressedSize (128 KB)
682 #define ringBufferSize (8 KB)
683
FUZ_unitTests(void)684 static void FUZ_unitTests(void)
685 {
686 const unsigned testNb = 0;
687 const unsigned seed = 0;
688 const unsigned cycleNb= 0;
689 char testInput[testInputSize];
690 char testCompressed[testCompressedSize];
691 char testVerify[testInputSize];
692 char ringBuffer[ringBufferSize];
693 U32 randState = 1;
694
695 // Init
696 FUZ_fillCompressibleNoiseBuffer(testInput, testInputSize, 0.50, &randState);
697
698 // 32-bits address space overflow test
699 FUZ_AddressOverflow();
700
701 // LZ4 streaming tests
702 {
703 LZ4_stream_t* statePtr;
704 LZ4_stream_t streamingState;
705 U64 crcOrig;
706 U64 crcNew;
707 int result;
708
709 // Allocation test
710 statePtr = LZ4_createStream();
711 FUZ_CHECKTEST(statePtr==NULL, "LZ4_createStream() allocation failed");
712 LZ4_freeStream(statePtr);
713
714 // simple compression test
715 crcOrig = XXH64(testInput, testCompressedSize, 0);
716 LZ4_resetStream(&streamingState);
717 result = LZ4_compress_limitedOutput_continue(&streamingState, testInput, testCompressed, testCompressedSize, testCompressedSize-1);
718 FUZ_CHECKTEST(result==0, "LZ4_compress_limitedOutput_continue() compression failed");
719
720 result = LZ4_decompress_safe(testCompressed, testVerify, result, testCompressedSize);
721 FUZ_CHECKTEST(result!=(int)testCompressedSize, "LZ4_decompress_safe() decompression failed");
722 crcNew = XXH64(testVerify, testCompressedSize, 0);
723 FUZ_CHECKTEST(crcOrig!=crcNew, "LZ4_decompress_safe() decompression corruption");
724
725 // ring buffer test
726 {
727 XXH64_state_t xxhOrig;
728 XXH64_state_t xxhNew;
729 LZ4_streamDecode_t decodeState;
730 const U32 maxMessageSizeLog = 10;
731 const U32 maxMessageSizeMask = (1<<maxMessageSizeLog) - 1;
732 U32 messageSize = (FUZ_rand(&randState) & maxMessageSizeMask) + 1;
733 U32 iNext = 0;
734 U32 rNext = 0;
735 U32 dNext = 0;
736 const U32 dBufferSize = ringBufferSize + maxMessageSizeMask;
737
738 XXH64_reset(&xxhOrig, 0);
739 XXH64_reset(&xxhNew, 0);
740 LZ4_resetStream(&streamingState);
741 LZ4_setStreamDecode(&decodeState, NULL, 0);
742
743 while (iNext + messageSize < testCompressedSize)
744 {
745 XXH64_update(&xxhOrig, testInput + iNext, messageSize);
746 crcOrig = XXH64_digest(&xxhOrig);
747
748 memcpy (ringBuffer + rNext, testInput + iNext, messageSize);
749 result = LZ4_compress_limitedOutput_continue(&streamingState, ringBuffer + rNext, testCompressed, messageSize, testCompressedSize-ringBufferSize);
750 FUZ_CHECKTEST(result==0, "LZ4_compress_limitedOutput_continue() compression failed");
751
752 result = LZ4_decompress_safe_continue(&decodeState, testCompressed, testVerify + dNext, result, messageSize);
753 FUZ_CHECKTEST(result!=(int)messageSize, "ringBuffer : LZ4_decompress_safe() test failed");
754
755 XXH64_update(&xxhNew, testVerify + dNext, messageSize);
756 crcNew = crcOrig = XXH64_digest(&xxhNew);
757 FUZ_CHECKTEST(crcOrig!=crcNew, "LZ4_decompress_safe() decompression corruption");
758
759 // prepare next message
760 iNext += messageSize;
761 rNext += messageSize;
762 dNext += messageSize;
763 messageSize = (FUZ_rand(&randState) & maxMessageSizeMask) + 1;
764 if (rNext + messageSize > ringBufferSize) rNext = 0;
765 if (dNext + messageSize > dBufferSize) dNext = 0;
766 }
767 }
768 }
769
770 // LZ4 HC streaming tests
771 {
772 LZ4_streamHC_t* sp;
773 LZ4_streamHC_t sHC;
774 //XXH64_state_t xxh;
775 U64 crcOrig;
776 U64 crcNew;
777 int result;
778
779 // Allocation test
780 sp = LZ4_createStreamHC();
781 FUZ_CHECKTEST(sp==NULL, "LZ4_createStreamHC() allocation failed");
782 LZ4_freeStreamHC(sp);
783
784 // simple compression test
785 crcOrig = XXH64(testInput, testCompressedSize, 0);
786 LZ4_resetStreamHC(&sHC, 0);
787 result = LZ4_compressHC_limitedOutput_continue(&sHC, testInput, testCompressed, testCompressedSize, testCompressedSize-1);
788 FUZ_CHECKTEST(result==0, "LZ4_compressHC_limitedOutput_continue() compression failed");
789
790 result = LZ4_decompress_safe(testCompressed, testVerify, result, testCompressedSize);
791 FUZ_CHECKTEST(result!=(int)testCompressedSize, "LZ4_decompress_safe() decompression failed");
792 crcNew = XXH64(testVerify, testCompressedSize, 0);
793 FUZ_CHECKTEST(crcOrig!=crcNew, "LZ4_decompress_safe() decompression corruption");
794
795 // simple dictionary compression test
796 crcOrig = XXH64(testInput + 64 KB, testCompressedSize, 0);
797 LZ4_resetStreamHC(&sHC, 0);
798 LZ4_loadDictHC(&sHC, testInput, 64 KB);
799 result = LZ4_compressHC_limitedOutput_continue(&sHC, testInput + 64 KB, testCompressed, testCompressedSize, testCompressedSize-1);
800 FUZ_CHECKTEST(result==0, "LZ4_compressHC_limitedOutput_continue() dictionary compression failed : result = %i", result);
801
802 result = LZ4_decompress_safe_usingDict(testCompressed, testVerify, result, testCompressedSize, testInput, 64 KB);
803 FUZ_CHECKTEST(result!=(int)testCompressedSize, "LZ4_decompress_safe() simple dictionary decompression test failed");
804 crcNew = XXH64(testVerify, testCompressedSize, 0);
805 FUZ_CHECKTEST(crcOrig!=crcNew, "LZ4_decompress_safe() simple dictionary decompression test : corruption");
806
807 // multiple HC compression test with dictionary
808 {
809 int result1, result2;
810 int segSize = testCompressedSize / 2;
811 crcOrig = XXH64(testInput + segSize, testCompressedSize, 0);
812 LZ4_resetStreamHC(&sHC, 0);
813 LZ4_loadDictHC(&sHC, testInput, segSize);
814 result1 = LZ4_compressHC_limitedOutput_continue(&sHC, testInput + segSize, testCompressed, segSize, segSize -1);
815 FUZ_CHECKTEST(result1==0, "LZ4_compressHC_limitedOutput_continue() dictionary compression failed : result = %i", result1);
816 result2 = LZ4_compressHC_limitedOutput_continue(&sHC, testInput + 2*segSize, testCompressed+result1, segSize, segSize-1);
817 FUZ_CHECKTEST(result2==0, "LZ4_compressHC_limitedOutput_continue() dictionary compression failed : result = %i", result2);
818
819 result = LZ4_decompress_safe_usingDict(testCompressed, testVerify, result1, segSize, testInput, segSize);
820 FUZ_CHECKTEST(result!=segSize, "LZ4_decompress_safe() dictionary decompression part 1 failed");
821 result = LZ4_decompress_safe_usingDict(testCompressed+result1, testVerify+segSize, result2, segSize, testInput, 2*segSize);
822 FUZ_CHECKTEST(result!=segSize, "LZ4_decompress_safe() dictionary decompression part 2 failed");
823 crcNew = XXH64(testVerify, testCompressedSize, 0);
824 FUZ_CHECKTEST(crcOrig!=crcNew, "LZ4_decompress_safe() dictionary decompression corruption");
825 }
826
827 // remote dictionary HC compression test
828 crcOrig = XXH64(testInput + 64 KB, testCompressedSize, 0);
829 LZ4_resetStreamHC(&sHC, 0);
830 LZ4_loadDictHC(&sHC, testInput, 32 KB);
831 result = LZ4_compressHC_limitedOutput_continue(&sHC, testInput + 64 KB, testCompressed, testCompressedSize, testCompressedSize-1);
832 FUZ_CHECKTEST(result==0, "LZ4_compressHC_limitedOutput_continue() remote dictionary failed : result = %i", result);
833
834 result = LZ4_decompress_safe_usingDict(testCompressed, testVerify, result, testCompressedSize, testInput, 32 KB);
835 FUZ_CHECKTEST(result!=(int)testCompressedSize, "LZ4_decompress_safe_usingDict() decompression failed following remote dictionary HC compression test");
836 crcNew = XXH64(testVerify, testCompressedSize, 0);
837 FUZ_CHECKTEST(crcOrig!=crcNew, "LZ4_decompress_safe_usingDict() decompression corruption");
838
839 // multiple HC compression with ext. dictionary
840 {
841 XXH64_state_t crcOrigState;
842 XXH64_state_t crcNewState;
843 const char* dict = testInput + 3;
844 int dictSize = (FUZ_rand(&randState) & 8191);
845 char* dst = testVerify;
846
847 size_t segStart = dictSize + 7;
848 int segSize = (FUZ_rand(&randState) & 8191);
849 int segNb = 1;
850
851 LZ4_resetStreamHC(&sHC, 0);
852 LZ4_loadDictHC(&sHC, dict, dictSize);
853
854 XXH64_reset(&crcOrigState, 0);
855 XXH64_reset(&crcNewState, 0);
856
857 while (segStart + segSize < testInputSize)
858 {
859 XXH64_update(&crcOrigState, testInput + segStart, segSize);
860 crcOrig = XXH64_digest(&crcOrigState);
861 result = LZ4_compressHC_limitedOutput_continue(&sHC, testInput + segStart, testCompressed, segSize, LZ4_compressBound(segSize));
862 FUZ_CHECKTEST(result==0, "LZ4_compressHC_limitedOutput_continue() dictionary compression failed : result = %i", result);
863
864 result = LZ4_decompress_safe_usingDict(testCompressed, dst, result, segSize, dict, dictSize);
865 FUZ_CHECKTEST(result!=segSize, "LZ4_decompress_safe_usingDict() dictionary decompression part %i failed", segNb);
866 XXH64_update(&crcNewState, dst, segSize);
867 crcNew = XXH64_digest(&crcNewState);
868 if (crcOrig!=crcNew)
869 {
870 size_t c=0;
871 while (dst[c] == testInput[segStart+c]) c++;
872 DISPLAY("Bad decompression at %u / %u \n", (U32)c, (U32)segSize);
873 }
874 FUZ_CHECKTEST(crcOrig!=crcNew, "LZ4_decompress_safe_usingDict() part %i corruption", segNb);
875
876 dict = dst;
877 //dict = testInput + segStart;
878 dictSize = segSize;
879
880 dst += segSize + 1;
881 segNb ++;
882
883 segStart += segSize + (FUZ_rand(&randState) & 0xF) + 1;
884 segSize = (FUZ_rand(&randState) & 8191);
885 }
886 }
887
888 // ring buffer test
889 {
890 XXH64_state_t xxhOrig;
891 XXH64_state_t xxhNew;
892 LZ4_streamDecode_t decodeState;
893 const U32 maxMessageSizeLog = 10;
894 const U32 maxMessageSizeMask = (1<<maxMessageSizeLog) - 1;
895 U32 messageSize = (FUZ_rand(&randState) & maxMessageSizeMask) + 1;
896 U32 iNext = 0;
897 U32 rNext = 0;
898 U32 dNext = 0;
899 const U32 dBufferSize = ringBufferSize + maxMessageSizeMask;
900
901 XXH64_reset(&xxhOrig, 0);
902 XXH64_reset(&xxhNew, 0);
903 LZ4_resetStreamHC(&sHC, 0);
904 LZ4_setStreamDecode(&decodeState, NULL, 0);
905
906 while (iNext + messageSize < testCompressedSize)
907 {
908 XXH64_update(&xxhOrig, testInput + iNext, messageSize);
909 crcOrig = XXH64_digest(&xxhOrig);
910
911 memcpy (ringBuffer + rNext, testInput + iNext, messageSize);
912 result = LZ4_compressHC_limitedOutput_continue(&sHC, ringBuffer + rNext, testCompressed, messageSize, testCompressedSize-ringBufferSize);
913 FUZ_CHECKTEST(result==0, "LZ4_compressHC_limitedOutput_continue() compression failed");
914
915 result = LZ4_decompress_safe_continue(&decodeState, testCompressed, testVerify + dNext, result, messageSize);
916 FUZ_CHECKTEST(result!=(int)messageSize, "ringBuffer : LZ4_decompress_safe() test failed");
917
918 XXH64_update(&xxhNew, testVerify + dNext, messageSize);
919 crcNew = crcOrig = XXH64_digest(&xxhNew);
920 FUZ_CHECKTEST(crcOrig!=crcNew, "LZ4_decompress_safe() decompression corruption");
921
922 // prepare next message
923 iNext += messageSize;
924 rNext += messageSize;
925 dNext += messageSize;
926 messageSize = (FUZ_rand(&randState) & maxMessageSizeMask) + 1;
927 if (rNext + messageSize > ringBufferSize) rNext = 0;
928 if (dNext + messageSize > dBufferSize) dNext = 0;
929 }
930 }
931
932 // small decoder-side ring buffer test
933 {
934 XXH64_state_t xxhOrig;
935 XXH64_state_t xxhNew;
936 LZ4_streamDecode_t decodeState;
937 const U32 maxMessageSizeLog = 10;
938 const U32 maxMessageSizeMask = (1<<maxMessageSizeLog) - 1;
939 U32 messageSize = (FUZ_rand(&randState) & maxMessageSizeMask) + 1;
940 U32 totalMessageSize = 0;
941 U32 iNext = 0;
942 U32 dNext = 0;
943 const U32 dBufferSize = 64 KB + maxMessageSizeMask;
944
945 XXH64_reset(&xxhOrig, 0);
946 XXH64_reset(&xxhNew, 0);
947 LZ4_resetStreamHC(&sHC, 0);
948 LZ4_setStreamDecode(&decodeState, NULL, 0);
949
950 while (totalMessageSize < 9 MB)
951 {
952 XXH64_update(&xxhOrig, testInput + iNext, messageSize);
953 crcOrig = XXH64_digest(&xxhOrig);
954
955 result = LZ4_compressHC_limitedOutput_continue(&sHC, testInput + iNext, testCompressed, messageSize, testCompressedSize-ringBufferSize);
956 FUZ_CHECKTEST(result==0, "LZ4_compressHC_limitedOutput_continue() compression failed");
957
958 result = LZ4_decompress_safe_continue(&decodeState, testCompressed, testVerify + dNext, result, messageSize);
959 FUZ_CHECKTEST(result!=(int)messageSize, "ringBuffer : LZ4_decompress_safe() test failed");
960
961 XXH64_update(&xxhNew, testVerify + dNext, messageSize);
962 crcNew = crcOrig = XXH64_digest(&xxhNew);
963 FUZ_CHECKTEST(crcOrig!=crcNew, "LZ4_decompress_safe() decompression corruption");
964
965 // prepare next message
966 dNext += messageSize;
967 totalMessageSize += messageSize;
968 messageSize = (FUZ_rand(&randState) & maxMessageSizeMask) + 1;
969 iNext = (FUZ_rand(&randState) & 65535);
970 if (dNext + messageSize > dBufferSize) dNext = 0;
971 }
972 }
973
974 // long stream test ; Warning : very long test !
975 if (1)
976 {
977 XXH64_state_t crcOrigState;
978 XXH64_state_t crcNewState;
979 const U64 totalTestSize = 6ULL << 30;
980 U64 totalTestDone = 0;
981 size_t oldStart = 0;
982 size_t oldSize = 0;
983 U32 segNb = 1;
984
985 DISPLAY("Long HC streaming test (%u MB)\n", (U32)(totalTestSize >> 20));
986 LZ4_resetStreamHC(&sHC, 0);
987
988 XXH64_reset(&crcOrigState, 0);
989 XXH64_reset(&crcNewState, 0);
990
991 while (totalTestDone < totalTestSize)
992 {
993 size_t testSize = (FUZ_rand(&randState) & 65535) + 1;
994 size_t testStart = FUZ_rand(&randState) & 65535;
995
996 FUZ_displayUpdate((U32)(totalTestDone >> 20));
997
998 if (testStart == oldStart + oldSize) // Corner case not covered by this test (LZ4_decompress_safe_usingDict() limitation)
999 testStart++;
1000
1001 XXH64_update(&crcOrigState, testInput + testStart, testSize);
1002 crcOrig = XXH64_digest(&crcOrigState);
1003
1004 result = LZ4_compressHC_limitedOutput_continue(&sHC, testInput + testStart, testCompressed, (int)testSize, LZ4_compressBound((int)testSize));
1005 FUZ_CHECKTEST(result==0, "LZ4_compressHC_limitedOutput_continue() dictionary compression failed : result = %i", result);
1006
1007 result = LZ4_decompress_safe_usingDict(testCompressed, testVerify, result, (int)testSize, testInput + oldStart, (int)oldSize);
1008 FUZ_CHECKTEST(result!=(int)testSize, "LZ4_decompress_safe_usingDict() dictionary decompression part %u failed", segNb);
1009
1010 XXH64_update(&crcNewState, testVerify, testSize);
1011 crcNew = XXH64_digest(&crcNewState);
1012 if (crcOrig!=crcNew)
1013 {
1014 size_t c=0;
1015 while (testVerify[c] == testInput[testStart+c]) c++;
1016 DISPLAY("Bad decompression at %u / %u \n", (U32)c, (U32)testSize);
1017 }
1018 FUZ_CHECKTEST(crcOrig!=crcNew, "LZ4_decompress_safe_usingDict() part %u corruption", segNb);
1019
1020 oldStart = testStart;
1021 oldSize = testSize;
1022 totalTestDone += testSize;
1023
1024 segNb ++;
1025 }
1026
1027 DISPLAY("\r");
1028 }
1029 }
1030
1031 printf("All unit tests completed successfully \n");
1032 return;
1033 _output_error:
1034 exit(1);
1035 }
1036
1037
FUZ_usage(char * programName)1038 static int FUZ_usage(char* programName)
1039 {
1040 DISPLAY( "Usage :\n");
1041 DISPLAY( " %s [args]\n", programName);
1042 DISPLAY( "\n");
1043 DISPLAY( "Arguments :\n");
1044 DISPLAY( " -i# : Nb of tests (default:%i) \n", NB_ATTEMPTS);
1045 DISPLAY( " -s# : Select seed (default:prompt user)\n");
1046 DISPLAY( " -t# : Select starting test number (default:0)\n");
1047 DISPLAY( " -P# : Select compressibility in %% (default:%i%%)\n", FUZ_COMPRESSIBILITY_DEFAULT);
1048 DISPLAY( " -v : verbose\n");
1049 DISPLAY( " -p : pause at the end\n");
1050 DISPLAY( " -h : display help and exit\n");
1051 return 0;
1052 }
1053
1054
main(int argc,char ** argv)1055 int main(int argc, char** argv)
1056 {
1057 U32 seed=0;
1058 int seedset=0;
1059 int argNb;
1060 int nbTests = NB_ATTEMPTS;
1061 int testNb = 0;
1062 int proba = FUZ_COMPRESSIBILITY_DEFAULT;
1063 int pause = 0;
1064 char* programName = argv[0];
1065
1066 // Check command line
1067 for(argNb=1; argNb<argc; argNb++)
1068 {
1069 char* argument = argv[argNb];
1070
1071 if(!argument) continue; // Protection if argument empty
1072
1073 // Decode command (note : aggregated commands are allowed)
1074 if (argument[0]=='-')
1075 {
1076 if (!strcmp(argument, "--no-prompt")) { pause=0; seedset=1; g_displayLevel=1; continue; }
1077 argument++;
1078
1079 while (*argument!=0)
1080 {
1081 switch(*argument)
1082 {
1083 case 'h': /* display help */
1084 return FUZ_usage(programName);
1085
1086 case 'v': /* verbose mode */
1087 argument++;
1088 g_displayLevel=4;
1089 break;
1090
1091 case 'p': /* pause at the end */
1092 argument++;
1093 pause=1;
1094 break;
1095
1096 case 'i':
1097 argument++;
1098 nbTests=0;
1099 while ((*argument>='0') && (*argument<='9'))
1100 {
1101 nbTests *= 10;
1102 nbTests += *argument - '0';
1103 argument++;
1104 }
1105 break;
1106
1107 case 's':
1108 argument++;
1109 seed=0; seedset=1;
1110 while ((*argument>='0') && (*argument<='9'))
1111 {
1112 seed *= 10;
1113 seed += *argument - '0';
1114 argument++;
1115 }
1116 break;
1117
1118 case 't': /* select starting test nb */
1119 argument++;
1120 testNb=0;
1121 while ((*argument>='0') && (*argument<='9'))
1122 {
1123 testNb *= 10;
1124 testNb += *argument - '0';
1125 argument++;
1126 }
1127 break;
1128
1129 case 'P': /* change probability */
1130 argument++;
1131 proba=0;
1132 while ((*argument>='0') && (*argument<='9'))
1133 {
1134 proba *= 10;
1135 proba += *argument - '0';
1136 argument++;
1137 }
1138 if (proba<0) proba=0;
1139 if (proba>100) proba=100;
1140 break;
1141 default: ;
1142 }
1143 }
1144 }
1145 }
1146
1147 // Get Seed
1148 printf("Starting LZ4 fuzzer (%i-bits, %s)\n", (int)(sizeof(size_t)*8), LZ4_VERSION);
1149
1150 if (!seedset) seed = FUZ_GetMilliStart() % 10000;
1151 printf("Seed = %u\n", seed);
1152 if (proba!=FUZ_COMPRESSIBILITY_DEFAULT) printf("Compressibility : %i%%\n", proba);
1153
1154 if ((seedset==0) && (testNb==0)) FUZ_unitTests();
1155
1156 if (nbTests<=0) nbTests=1;
1157
1158 {
1159 int result = FUZ_test(seed, nbTests, testNb, ((double)proba) / 100);
1160 if (pause)
1161 {
1162 DISPLAY("press enter ... \n");
1163 getchar();
1164 }
1165 return result;
1166 }
1167 }
1168