1 /* 2 frameTest - test tool for lz4frame 3 Copyright (C) Yann Collet 2014-2016 4 5 GPL v2 License 6 7 This program is free software; you can redistribute it and/or modify 8 it under the terms of the GNU General Public License as published by 9 the Free Software Foundation; either version 2 of the License, or 10 (at your option) any later version. 11 12 This program is distributed in the hope that it will be useful, 13 but WITHOUT ANY WARRANTY; without even the implied warranty of 14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 GNU General Public License for more details. 16 17 You should have received a copy of the GNU General Public License along 18 with this program; if not, write to the Free Software Foundation, Inc., 19 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 20 21 You can contact the author at : 22 - LZ4 homepage : http://www.lz4.org 23 - LZ4 source repository : https://github.com/lz4/lz4 24 */ 25 26 /*-************************************ 27 * Compiler specific 28 **************************************/ 29 #ifdef _MSC_VER /* Visual Studio */ 30 # pragma warning(disable : 4127) /* disable: C4127: conditional expression is constant */ 31 # pragma warning(disable : 4146) /* disable: C4146: minus unsigned expression */ 32 #endif 33 34 35 /*-************************************ 36 * Includes 37 **************************************/ 38 #include "util.h" /* U32 */ 39 #include <stdlib.h> /* malloc, free */ 40 #include <stdio.h> /* fprintf */ 41 #include <string.h> /* strcmp */ 42 #include <time.h> /* clock_t, clock(), CLOCKS_PER_SEC */ 43 #include "lz4frame_static.h" 44 #include "lz4.h" /* LZ4_VERSION_STRING */ 45 #define XXH_STATIC_LINKING_ONLY 46 #include "xxhash.h" /* XXH64 */ 47 48 49 /* unoptimized version; solves endianess & alignment issues */ 50 static void FUZ_writeLE32 (void* dstVoidPtr, U32 value32) 51 { 52 BYTE* dstPtr = (BYTE*)dstVoidPtr; 53 dstPtr[0] = (BYTE)value32; 54 dstPtr[1] = (BYTE)(value32 >> 8); 55 dstPtr[2] = (BYTE)(value32 >> 16); 56 dstPtr[3] = (BYTE)(value32 >> 24); 57 } 58 59 60 /*-************************************ 61 * Constants 62 **************************************/ 63 #define LZ4F_MAGIC_SKIPPABLE_START 0x184D2A50U 64 65 #define KB *(1U<<10) 66 #define MB *(1U<<20) 67 #define GB *(1U<<30) 68 69 static const U32 nbTestsDefault = 256 KB; 70 #define COMPRESSIBLE_NOISE_LENGTH (2 MB) 71 #define FUZ_COMPRESSIBILITY_DEFAULT 50 72 static const U32 prime1 = 2654435761U; 73 static const U32 prime2 = 2246822519U; 74 75 76 77 /*-************************************ 78 * Macros 79 **************************************/ 80 #define DISPLAY(...) fprintf(stderr, __VA_ARGS__) 81 #define DISPLAYLEVEL(l, ...) if (displayLevel>=l) { DISPLAY(__VA_ARGS__); } 82 #define DISPLAYUPDATE(l, ...) if (displayLevel>=l) { \ 83 if ((FUZ_GetClockSpan(g_clockTime) > refreshRate) || (displayLevel>=4)) \ 84 { g_clockTime = clock(); DISPLAY(__VA_ARGS__); \ 85 if (displayLevel>=4) fflush(stdout); } } 86 static const clock_t refreshRate = CLOCKS_PER_SEC / 6; 87 static clock_t g_clockTime = 0; 88 89 90 /*-*************************************** 91 * Local Parameters 92 *****************************************/ 93 static U32 no_prompt = 0; 94 static U32 displayLevel = 2; 95 static U32 use_pause = 0; 96 97 98 /*-******************************************************* 99 * Fuzzer functions 100 *********************************************************/ 101 #define MIN(a,b) ( (a) < (b) ? (a) : (b) ) 102 #define MAX(a,b) ( (a) > (b) ? (a) : (b) ) 103 104 static clock_t FUZ_GetClockSpan(clock_t clockStart) 105 { 106 return clock() - clockStart; /* works even if overflow; max span ~ 30 mn */ 107 } 108 109 110 #define FUZ_rotl32(x,r) ((x << r) | (x >> (32 - r))) 111 unsigned int FUZ_rand(unsigned int* src) 112 { 113 U32 rand32 = *src; 114 rand32 *= prime1; 115 rand32 += prime2; 116 rand32 = FUZ_rotl32(rand32, 13); 117 *src = rand32; 118 return rand32 >> 5; 119 } 120 121 122 #define FUZ_RAND15BITS (FUZ_rand(seed) & 0x7FFF) 123 #define FUZ_RANDLENGTH ( (FUZ_rand(seed) & 3) ? (FUZ_rand(seed) % 15) : (FUZ_rand(seed) % 510) + 15) 124 static void FUZ_fillCompressibleNoiseBuffer(void* buffer, size_t bufferSize, double proba, U32* seed) 125 { 126 BYTE* BBuffer = (BYTE*)buffer; 127 size_t pos = 0; 128 U32 P32 = (U32)(32768 * proba); 129 130 /* First Byte */ 131 BBuffer[pos++] = (BYTE)(FUZ_rand(seed)); 132 133 while (pos < bufferSize) { 134 /* Select : Literal (noise) or copy (within 64K) */ 135 if (FUZ_RAND15BITS < P32) { 136 /* Copy (within 64K) */ 137 size_t const lengthRand = FUZ_RANDLENGTH + 4; 138 size_t const length = MIN(lengthRand, bufferSize - pos); 139 size_t const end = pos + length; 140 size_t const offsetRand = FUZ_RAND15BITS + 1; 141 size_t const offset = MIN(offsetRand, pos); 142 size_t match = pos - offset; 143 while (pos < end) BBuffer[pos++] = BBuffer[match++]; 144 } else { 145 /* Literal (noise) */ 146 size_t const lengthRand = FUZ_RANDLENGTH + 4; 147 size_t const length = MIN(lengthRand, bufferSize - pos); 148 size_t const end = pos + length; 149 while (pos < end) BBuffer[pos++] = (BYTE)(FUZ_rand(seed) >> 5); 150 } 151 } 152 } 153 154 155 static unsigned FUZ_highbit(U32 v32) 156 { 157 unsigned nbBits = 0; 158 if (v32==0) return 0; 159 while (v32) v32 >>= 1, nbBits ++; 160 return nbBits; 161 } 162 163 164 /*-******************************************************* 165 * Tests 166 *********************************************************/ 167 int basicTests(U32 seed, double compressibility) 168 { 169 int testResult = 0; 170 void* const CNBuffer = malloc(COMPRESSIBLE_NOISE_LENGTH); 171 size_t const cBuffSize = LZ4F_compressFrameBound(COMPRESSIBLE_NOISE_LENGTH, NULL); 172 void* const compressedBuffer = malloc(cBuffSize); 173 void* const decodedBuffer = malloc(COMPRESSIBLE_NOISE_LENGTH); 174 U32 randState = seed; 175 size_t cSize, testSize; 176 LZ4F_decompressionContext_t dCtx = NULL; 177 LZ4F_compressionContext_t cctx = NULL; 178 U64 crcOrig; 179 180 LZ4F_preferences_t prefs; 181 memset(&prefs, 0, sizeof(prefs)); 182 if (!CNBuffer || !compressedBuffer || !decodedBuffer) { 183 DISPLAY("allocation error, not enough memory to start fuzzer tests \n"); 184 goto _output_error; 185 } 186 FUZ_fillCompressibleNoiseBuffer(CNBuffer, COMPRESSIBLE_NOISE_LENGTH, compressibility, &randState); 187 crcOrig = XXH64(CNBuffer, COMPRESSIBLE_NOISE_LENGTH, 1); 188 189 /* LZ4F_compressBound() : special case : srcSize == 0 */ 190 DISPLAYLEVEL(3, "LZ4F_compressBound(0) = "); 191 { size_t const cBound = LZ4F_compressBound(0, NULL); 192 if (cBound < 64 KB) goto _output_error; 193 DISPLAYLEVEL(3, " %u \n", (U32)cBound); 194 } 195 196 /* Special case : null-content frame */ 197 testSize = 0; 198 DISPLAYLEVEL(3, "LZ4F_compressFrame, compress null content : \n"); 199 cSize = LZ4F_compressFrame(compressedBuffer, LZ4F_compressFrameBound(testSize, NULL), CNBuffer, testSize, NULL); 200 if (LZ4F_isError(cSize)) goto _output_error; 201 DISPLAYLEVEL(3, "Compressed null content into a %i bytes frame \n", (int)cSize); 202 203 DISPLAYLEVEL(3, "LZ4F_createDecompressionContext \n"); 204 { LZ4F_errorCode_t const errorCode = LZ4F_createDecompressionContext(&dCtx, LZ4F_VERSION); 205 if (LZ4F_isError(errorCode)) goto _output_error; } 206 207 DISPLAYLEVEL(3, "LZ4F_getFrameInfo on null-content frame (#157) \n"); 208 { size_t avail_in = cSize; 209 LZ4F_frameInfo_t frame_info; 210 LZ4F_errorCode_t const errorCode = LZ4F_getFrameInfo(dCtx, &frame_info, compressedBuffer, &avail_in); 211 if (LZ4F_isError(errorCode)) goto _output_error; 212 } 213 214 DISPLAYLEVEL(3, "LZ4F_freeDecompressionContext \n"); 215 { LZ4F_errorCode_t const errorCode = LZ4F_freeDecompressionContext(dCtx); 216 if (LZ4F_isError(errorCode)) goto _output_error; } 217 dCtx = NULL; 218 219 /* test one-pass frame compression */ 220 testSize = COMPRESSIBLE_NOISE_LENGTH; 221 DISPLAYLEVEL(3, "LZ4F_compressFrame, using default preferences : \n"); 222 cSize = LZ4F_compressFrame(compressedBuffer, LZ4F_compressFrameBound(testSize, NULL), CNBuffer, testSize, NULL); 223 if (LZ4F_isError(cSize)) goto _output_error; 224 DISPLAYLEVEL(3, "Compressed %u bytes into a %u bytes frame \n", (U32)testSize, (U32)cSize); 225 226 DISPLAYLEVEL(3, "Decompression test : \n"); 227 { size_t decodedBufferSize = COMPRESSIBLE_NOISE_LENGTH; 228 size_t compressedBufferSize = cSize; 229 BYTE* ip = (BYTE*)compressedBuffer; 230 BYTE* const iend = (BYTE*)compressedBuffer + cSize; 231 232 LZ4F_errorCode_t errorCode = LZ4F_createDecompressionContext(&dCtx, LZ4F_VERSION); 233 if (LZ4F_isError(errorCode)) goto _output_error; 234 235 DISPLAYLEVEL(3, "Single Pass decompression : \n"); 236 { size_t const decompressError = LZ4F_decompress(dCtx, decodedBuffer, &decodedBufferSize, compressedBuffer, &compressedBufferSize, NULL); 237 if (LZ4F_isError(decompressError)) goto _output_error; } 238 { U64 const crcDest = XXH64(decodedBuffer, COMPRESSIBLE_NOISE_LENGTH, 1); 239 if (crcDest != crcOrig) goto _output_error; } 240 DISPLAYLEVEL(3, "Regenerated %u bytes \n", (U32)decodedBufferSize); 241 242 DISPLAYLEVEL(3, "Reusing decompression context \n"); 243 { size_t const missingBytes = 4; 244 size_t iSize = compressedBufferSize - missingBytes; 245 const BYTE* cBuff = (const BYTE*) compressedBuffer; 246 BYTE* const ostart = (BYTE*)decodedBuffer; 247 BYTE* op = ostart; 248 BYTE* const oend = (BYTE*)decodedBuffer + COMPRESSIBLE_NOISE_LENGTH; 249 size_t decResult, oSize = COMPRESSIBLE_NOISE_LENGTH; 250 DISPLAYLEVEL(3, "Missing last %u bytes : ", (U32)missingBytes); 251 decResult = LZ4F_decompress(dCtx, op, &oSize, cBuff, &iSize, NULL); 252 if (LZ4F_isError(decResult)) goto _output_error; 253 if (decResult != missingBytes) { 254 DISPLAY("%u bytes missing != %u bytes requested \n", (U32)missingBytes, (U32)decResult); 255 goto _output_error; 256 } 257 DISPLAYLEVEL(3, "indeed, requests %u bytes \n", (unsigned)decResult); 258 cBuff += iSize; 259 iSize = decResult; 260 op += oSize; 261 oSize = (size_t)(oend-op); 262 decResult = LZ4F_decompress(dCtx, op, &oSize, cBuff, &iSize, NULL); 263 if (decResult != 0) goto _output_error; /* should finish now */ 264 op += oSize; 265 if (op>oend) { DISPLAY("decompression write overflow \n"); goto _output_error; } 266 { U64 const crcDest = XXH64(decodedBuffer, op-ostart, 1); 267 if (crcDest != crcOrig) goto _output_error; 268 } } 269 270 { size_t oSize = 0; 271 size_t iSize = 0; 272 LZ4F_frameInfo_t fi; 273 274 DISPLAYLEVEL(3, "Start by feeding 0 bytes, to get next input size : "); 275 errorCode = LZ4F_decompress(dCtx, NULL, &oSize, ip, &iSize, NULL); 276 if (LZ4F_isError(errorCode)) goto _output_error; 277 DISPLAYLEVEL(3, " %u \n", (unsigned)errorCode); 278 279 DISPLAYLEVEL(3, "get FrameInfo on null input : "); 280 errorCode = LZ4F_getFrameInfo(dCtx, &fi, ip, &iSize); 281 if (errorCode != (size_t)-LZ4F_ERROR_frameHeader_incomplete) goto _output_error; 282 DISPLAYLEVEL(3, " correctly failed : %s \n", LZ4F_getErrorName(errorCode)); 283 284 DISPLAYLEVEL(3, "get FrameInfo on not enough input : "); 285 iSize = 6; 286 errorCode = LZ4F_getFrameInfo(dCtx, &fi, ip, &iSize); 287 if (errorCode != (size_t)-LZ4F_ERROR_frameHeader_incomplete) goto _output_error; 288 DISPLAYLEVEL(3, " correctly failed : %s \n", LZ4F_getErrorName(errorCode)); 289 ip += iSize; 290 291 DISPLAYLEVEL(3, "get FrameInfo on enough input : "); 292 iSize = 15 - iSize; 293 errorCode = LZ4F_getFrameInfo(dCtx, &fi, ip, &iSize); 294 if (LZ4F_isError(errorCode)) goto _output_error; 295 DISPLAYLEVEL(3, " correctly decoded \n"); 296 ip += iSize; 297 } 298 299 DISPLAYLEVEL(3, "Byte after byte : \n"); 300 { BYTE* const ostart = (BYTE*)decodedBuffer; 301 BYTE* op = ostart; 302 BYTE* const oend = (BYTE*)decodedBuffer + COMPRESSIBLE_NOISE_LENGTH; 303 while (ip < iend) { 304 size_t oSize = oend-op; 305 size_t iSize = 1; 306 errorCode = LZ4F_decompress(dCtx, op, &oSize, ip, &iSize, NULL); 307 if (LZ4F_isError(errorCode)) goto _output_error; 308 op += oSize; 309 ip += iSize; 310 } 311 { U64 const crcDest = XXH64(decodedBuffer, COMPRESSIBLE_NOISE_LENGTH, 1); 312 if (crcDest != crcOrig) goto _output_error; } 313 DISPLAYLEVEL(3, "Regenerated %u/%u bytes \n", (unsigned)(op-ostart), COMPRESSIBLE_NOISE_LENGTH); 314 } 315 316 errorCode = LZ4F_freeDecompressionContext(dCtx); 317 if (LZ4F_isError(errorCode)) goto _output_error; 318 dCtx = NULL; 319 } 320 321 DISPLAYLEVEL(3, "Using 64 KB block : \n"); 322 prefs.frameInfo.blockSizeID = LZ4F_max64KB; 323 prefs.frameInfo.contentChecksumFlag = LZ4F_contentChecksumEnabled; 324 cSize = LZ4F_compressFrame(compressedBuffer, LZ4F_compressFrameBound(testSize, &prefs), CNBuffer, testSize, &prefs); 325 if (LZ4F_isError(cSize)) goto _output_error; 326 DISPLAYLEVEL(3, "Compressed %i bytes into a %i bytes frame \n", (int)testSize, (int)cSize); 327 328 DISPLAYLEVEL(3, "without checksum : \n"); 329 prefs.frameInfo.contentChecksumFlag = LZ4F_noContentChecksum; 330 cSize = LZ4F_compressFrame(compressedBuffer, LZ4F_compressFrameBound(testSize, &prefs), CNBuffer, testSize, &prefs); 331 if (LZ4F_isError(cSize)) goto _output_error; 332 DISPLAYLEVEL(3, "Compressed %i bytes into a %i bytes frame \n", (int)testSize, (int)cSize); 333 334 DISPLAYLEVEL(3, "Using 256 KB block : \n"); 335 prefs.frameInfo.blockSizeID = LZ4F_max256KB; 336 prefs.frameInfo.contentChecksumFlag = LZ4F_contentChecksumEnabled; 337 cSize = LZ4F_compressFrame(compressedBuffer, LZ4F_compressFrameBound(testSize, &prefs), CNBuffer, testSize, &prefs); 338 if (LZ4F_isError(cSize)) goto _output_error; 339 DISPLAYLEVEL(3, "Compressed %i bytes into a %i bytes frame \n", (int)testSize, (int)cSize); 340 341 DISPLAYLEVEL(3, "Decompression test : \n"); 342 { size_t const decodedBufferSize = COMPRESSIBLE_NOISE_LENGTH; 343 unsigned const maxBits = FUZ_highbit((U32)decodedBufferSize); 344 BYTE* const ostart = (BYTE*)decodedBuffer; 345 BYTE* op = ostart; 346 BYTE* const oend = ostart + COMPRESSIBLE_NOISE_LENGTH; 347 const BYTE* ip = (const BYTE*)compressedBuffer; 348 const BYTE* const iend = (const BYTE*)compressedBuffer + cSize; 349 350 { LZ4F_errorCode_t const createError = LZ4F_createDecompressionContext(&dCtx, LZ4F_VERSION); 351 if (LZ4F_isError(createError)) goto _output_error; } 352 353 DISPLAYLEVEL(3, "random segment sizes : \n"); 354 while (ip < iend) { 355 unsigned const nbBits = FUZ_rand(&randState) % maxBits; 356 size_t iSize = (FUZ_rand(&randState) & ((1<<nbBits)-1)) + 1; 357 size_t oSize = oend-op; 358 if (iSize > (size_t)(iend-ip)) iSize = iend-ip; 359 { size_t const decompressError = LZ4F_decompress(dCtx, op, &oSize, ip, &iSize, NULL); 360 if (LZ4F_isError(decompressError)) goto _output_error; } 361 op += oSize; 362 ip += iSize; 363 } 364 { size_t const decodedSize = (size_t)(op - ostart); 365 U64 const crcDest = XXH64(decodedBuffer, decodedSize, 1); 366 if (crcDest != crcOrig) goto _output_error; 367 DISPLAYLEVEL(3, "Regenerated %u bytes \n", (U32)decodedSize); 368 } 369 370 { LZ4F_errorCode_t const freeError = LZ4F_freeDecompressionContext(dCtx); 371 if (LZ4F_isError(freeError)) goto _output_error; } 372 dCtx = NULL; 373 } 374 375 DISPLAYLEVEL(3, "without checksum : \n"); 376 prefs.frameInfo.contentChecksumFlag = LZ4F_noContentChecksum; 377 cSize = LZ4F_compressFrame(compressedBuffer, LZ4F_compressFrameBound(testSize, &prefs), CNBuffer, testSize, &prefs); 378 if (LZ4F_isError(cSize)) goto _output_error; 379 DISPLAYLEVEL(3, "Compressed %i bytes into a %i bytes frame \n", (int)testSize, (int)cSize); 380 381 DISPLAYLEVEL(3, "Using 1 MB block : \n"); 382 prefs.frameInfo.blockSizeID = LZ4F_max1MB; 383 prefs.frameInfo.contentChecksumFlag = LZ4F_contentChecksumEnabled; 384 cSize = LZ4F_compressFrame(compressedBuffer, LZ4F_compressFrameBound(testSize, &prefs), CNBuffer, testSize, &prefs); 385 if (LZ4F_isError(cSize)) goto _output_error; 386 DISPLAYLEVEL(3, "Compressed %i bytes into a %i bytes frame \n", (int)testSize, (int)cSize); 387 388 DISPLAYLEVEL(3, "without checksum : \n"); 389 prefs.frameInfo.contentChecksumFlag = LZ4F_noContentChecksum; 390 cSize = LZ4F_compressFrame(compressedBuffer, LZ4F_compressFrameBound(testSize, &prefs), CNBuffer, testSize, &prefs); 391 if (LZ4F_isError(cSize)) goto _output_error; 392 DISPLAYLEVEL(3, "Compressed %i bytes into a %i bytes frame \n", (int)testSize, (int)cSize); 393 394 DISPLAYLEVEL(3, "Using 4 MB block : \n"); 395 prefs.frameInfo.blockSizeID = LZ4F_max4MB; 396 prefs.frameInfo.contentChecksumFlag = LZ4F_contentChecksumEnabled; 397 { size_t const dstCapacity = LZ4F_compressFrameBound(testSize, &prefs); 398 DISPLAYLEVEL(4, "dstCapacity = %u \n", (U32)dstCapacity) 399 cSize = LZ4F_compressFrame(compressedBuffer, dstCapacity, CNBuffer, testSize, &prefs); 400 if (LZ4F_isError(cSize)) goto _output_error; 401 DISPLAYLEVEL(3, "Compressed %u bytes into a %u bytes frame \n", (U32)testSize, (U32)cSize); 402 } 403 404 DISPLAYLEVEL(3, "without checksum : \n"); 405 prefs.frameInfo.contentChecksumFlag = LZ4F_noContentChecksum; 406 { size_t const dstCapacity = LZ4F_compressFrameBound(testSize, &prefs); 407 DISPLAYLEVEL(4, "dstCapacity = %u \n", (U32)dstCapacity) 408 cSize = LZ4F_compressFrame(compressedBuffer, dstCapacity, CNBuffer, testSize, &prefs); 409 if (LZ4F_isError(cSize)) goto _output_error; 410 DISPLAYLEVEL(3, "Compressed %u bytes into a %u bytes frame \n", (U32)testSize, (U32)cSize); 411 } 412 413 { size_t errorCode; 414 BYTE* const ostart = (BYTE*)compressedBuffer; 415 BYTE* op = ostart; 416 errorCode = LZ4F_createCompressionContext(&cctx, LZ4F_VERSION); 417 if (LZ4F_isError(errorCode)) goto _output_error; 418 419 DISPLAYLEVEL(3, "compress without frameSize : \n"); 420 memset(&(prefs.frameInfo), 0, sizeof(prefs.frameInfo)); 421 errorCode = LZ4F_compressBegin(cctx, compressedBuffer, testSize, &prefs); 422 if (LZ4F_isError(errorCode)) goto _output_error; 423 op += errorCode; 424 errorCode = LZ4F_compressUpdate(cctx, op, LZ4F_compressBound(testSize, &prefs), CNBuffer, testSize, NULL); 425 if (LZ4F_isError(errorCode)) goto _output_error; 426 op += errorCode; 427 errorCode = LZ4F_compressEnd(cctx, compressedBuffer, testSize, NULL); 428 if (LZ4F_isError(errorCode)) goto _output_error; 429 DISPLAYLEVEL(3, "Compressed %i bytes into a %i bytes frame \n", (int)testSize, (int)(op-ostart)); 430 431 DISPLAYLEVEL(3, "compress with frameSize : \n"); 432 prefs.frameInfo.contentSize = testSize; 433 op = ostart; 434 errorCode = LZ4F_compressBegin(cctx, compressedBuffer, testSize, &prefs); 435 if (LZ4F_isError(errorCode)) goto _output_error; 436 op += errorCode; 437 errorCode = LZ4F_compressUpdate(cctx, op, LZ4F_compressBound(testSize, &prefs), CNBuffer, testSize, NULL); 438 if (LZ4F_isError(errorCode)) goto _output_error; 439 op += errorCode; 440 errorCode = LZ4F_compressEnd(cctx, compressedBuffer, testSize, NULL); 441 if (LZ4F_isError(errorCode)) goto _output_error; 442 DISPLAYLEVEL(3, "Compressed %i bytes into a %i bytes frame \n", (int)testSize, (int)(op-ostart)); 443 444 DISPLAYLEVEL(3, "compress with wrong frameSize : \n"); 445 prefs.frameInfo.contentSize = testSize+1; 446 op = ostart; 447 errorCode = LZ4F_compressBegin(cctx, compressedBuffer, testSize, &prefs); 448 if (LZ4F_isError(errorCode)) goto _output_error; 449 op += errorCode; 450 errorCode = LZ4F_compressUpdate(cctx, op, LZ4F_compressBound(testSize, &prefs), CNBuffer, testSize, NULL); 451 if (LZ4F_isError(errorCode)) goto _output_error; 452 op += errorCode; 453 errorCode = LZ4F_compressEnd(cctx, op, testSize, NULL); 454 if (LZ4F_isError(errorCode)) { DISPLAYLEVEL(3, "Error correctly detected : %s \n", LZ4F_getErrorName(errorCode)); } 455 else 456 goto _output_error; 457 458 errorCode = LZ4F_freeCompressionContext(cctx); 459 if (LZ4F_isError(errorCode)) goto _output_error; 460 cctx = NULL; 461 } 462 463 DISPLAYLEVEL(3, "Skippable frame test : \n"); 464 { size_t decodedBufferSize = COMPRESSIBLE_NOISE_LENGTH; 465 unsigned maxBits = FUZ_highbit((U32)decodedBufferSize); 466 BYTE* op = (BYTE*)decodedBuffer; 467 BYTE* const oend = (BYTE*)decodedBuffer + COMPRESSIBLE_NOISE_LENGTH; 468 BYTE* ip = (BYTE*)compressedBuffer; 469 BYTE* iend = (BYTE*)compressedBuffer + cSize + 8; 470 471 LZ4F_errorCode_t errorCode = LZ4F_createDecompressionContext(&dCtx, LZ4F_VERSION); 472 if (LZ4F_isError(errorCode)) goto _output_error; 473 474 /* generate skippable frame */ 475 FUZ_writeLE32(ip, LZ4F_MAGIC_SKIPPABLE_START); 476 FUZ_writeLE32(ip+4, (U32)cSize); 477 478 DISPLAYLEVEL(3, "random segment sizes : \n"); 479 while (ip < iend) { 480 unsigned nbBits = FUZ_rand(&randState) % maxBits; 481 size_t iSize = (FUZ_rand(&randState) & ((1<<nbBits)-1)) + 1; 482 size_t oSize = oend-op; 483 if (iSize > (size_t)(iend-ip)) iSize = iend-ip; 484 errorCode = LZ4F_decompress(dCtx, op, &oSize, ip, &iSize, NULL); 485 if (LZ4F_isError(errorCode)) goto _output_error; 486 op += oSize; 487 ip += iSize; 488 } 489 DISPLAYLEVEL(3, "Skipped %i bytes \n", (int)decodedBufferSize); 490 491 /* generate zero-size skippable frame */ 492 DISPLAYLEVEL(3, "zero-size skippable frame\n"); 493 ip = (BYTE*)compressedBuffer; 494 op = (BYTE*)decodedBuffer; 495 FUZ_writeLE32(ip, LZ4F_MAGIC_SKIPPABLE_START+1); 496 FUZ_writeLE32(ip+4, 0); 497 iend = ip+8; 498 499 while (ip < iend) { 500 unsigned nbBits = FUZ_rand(&randState) % maxBits; 501 size_t iSize = (FUZ_rand(&randState) & ((1<<nbBits)-1)) + 1; 502 size_t oSize = oend-op; 503 if (iSize > (size_t)(iend-ip)) iSize = iend-ip; 504 errorCode = LZ4F_decompress(dCtx, op, &oSize, ip, &iSize, NULL); 505 if (LZ4F_isError(errorCode)) goto _output_error; 506 op += oSize; 507 ip += iSize; 508 } 509 DISPLAYLEVEL(3, "Skipped %i bytes \n", (int)(ip - (BYTE*)compressedBuffer - 8)); 510 511 DISPLAYLEVEL(3, "Skippable frame header complete in first call \n"); 512 ip = (BYTE*)compressedBuffer; 513 op = (BYTE*)decodedBuffer; 514 FUZ_writeLE32(ip, LZ4F_MAGIC_SKIPPABLE_START+2); 515 FUZ_writeLE32(ip+4, 10); 516 iend = ip+18; 517 while (ip < iend) { 518 size_t iSize = 10; 519 size_t oSize = 10; 520 if (iSize > (size_t)(iend-ip)) iSize = iend-ip; 521 errorCode = LZ4F_decompress(dCtx, op, &oSize, ip, &iSize, NULL); 522 if (LZ4F_isError(errorCode)) goto _output_error; 523 op += oSize; 524 ip += iSize; 525 } 526 DISPLAYLEVEL(3, "Skipped %i bytes \n", (int)(ip - (BYTE*)compressedBuffer - 8)); 527 } 528 529 DISPLAY("Basic tests completed \n"); 530 _end: 531 free(CNBuffer); 532 free(compressedBuffer); 533 free(decodedBuffer); 534 LZ4F_freeDecompressionContext(dCtx); dCtx = NULL; 535 LZ4F_freeCompressionContext(cctx); cctx = NULL; 536 return testResult; 537 538 _output_error: 539 testResult = 1; 540 DISPLAY("Error detected ! \n"); 541 goto _end; 542 } 543 544 545 static void locateBuffDiff(const void* buff1, const void* buff2, size_t size, unsigned nonContiguous) 546 { 547 int p=0; 548 const BYTE* b1=(const BYTE*)buff1; 549 const BYTE* b2=(const BYTE*)buff2; 550 if (nonContiguous) { 551 DISPLAY("Non-contiguous output test (%i bytes)\n", (int)size); 552 return; 553 } 554 while (b1[p]==b2[p]) p++; 555 DISPLAY("Error at pos %i/%i : %02X != %02X \n", p, (int)size, b1[p], b2[p]); 556 } 557 558 559 int fuzzerTests(U32 seed, unsigned nbTests, unsigned startTest, double compressibility, U32 duration_s) 560 { 561 unsigned testResult = 0; 562 unsigned testNb = 0; 563 size_t const srcDataLength = 9 MB; /* needs to be > 2x4MB to test large blocks */ 564 void* srcBuffer = NULL; 565 size_t const compressedBufferSize = LZ4F_compressFrameBound(srcDataLength, NULL); 566 void* compressedBuffer = NULL; 567 void* decodedBuffer = NULL; 568 U32 coreRand = seed; 569 LZ4F_decompressionContext_t dCtx = NULL; 570 LZ4F_compressionContext_t cCtx = NULL; 571 size_t result; 572 clock_t const startClock = clock(); 573 clock_t const clockDuration = duration_s * CLOCKS_PER_SEC; 574 # define CHECK(cond, ...) if (cond) { DISPLAY("Error => "); DISPLAY(__VA_ARGS__); \ 575 DISPLAY(" (seed %u, test nb %u) \n", seed, testNb); goto _output_error; } 576 577 /* Create buffers */ 578 result = LZ4F_createDecompressionContext(&dCtx, LZ4F_VERSION); 579 CHECK(LZ4F_isError(result), "Allocation failed (error %i)", (int)result); 580 result = LZ4F_createCompressionContext(&cCtx, LZ4F_VERSION); 581 CHECK(LZ4F_isError(result), "Allocation failed (error %i)", (int)result); 582 srcBuffer = malloc(srcDataLength); 583 CHECK(srcBuffer==NULL, "srcBuffer Allocation failed"); 584 compressedBuffer = malloc(compressedBufferSize); 585 CHECK(compressedBuffer==NULL, "compressedBuffer Allocation failed"); 586 decodedBuffer = calloc(1, srcDataLength); /* calloc avoids decodedBuffer being considered "garbage" by scan-build */ 587 CHECK(decodedBuffer==NULL, "decodedBuffer Allocation failed"); 588 FUZ_fillCompressibleNoiseBuffer(srcBuffer, srcDataLength, compressibility, &coreRand); 589 590 /* jump to requested testNb */ 591 for (testNb =0; (testNb < startTest); testNb++) (void)FUZ_rand(&coreRand); /* sync randomizer */ 592 593 /* main fuzzer test loop */ 594 for ( ; (testNb < nbTests) || (clockDuration > FUZ_GetClockSpan(startClock)) ; testNb++) { 595 U32 randState = coreRand ^ prime1; 596 unsigned const srcBits = (FUZ_rand(&randState) % (FUZ_highbit((U32)(srcDataLength-1)) - 1)) + 1; 597 size_t const srcSize = (FUZ_rand(&randState) & ((1<<srcBits)-1)) + 1; 598 size_t const srcStartId = FUZ_rand(&randState) % (srcDataLength - srcSize); 599 const BYTE* const srcStart = (const BYTE*)srcBuffer + srcStartId; 600 unsigned const neverFlush = (FUZ_rand(&randState) & 15) == 1; 601 U64 const crcOrig = XXH64(srcStart, srcSize, 1); 602 LZ4F_preferences_t prefs; 603 const LZ4F_preferences_t* prefsPtr = &prefs; 604 size_t cSize; 605 606 (void)FUZ_rand(&coreRand); /* update seed */ 607 memset(&prefs, 0, sizeof(prefs)); 608 prefs.frameInfo.blockMode = (LZ4F_blockMode_t)(FUZ_rand(&randState) & 1); 609 prefs.frameInfo.blockSizeID = (LZ4F_blockSizeID_t)(4 + (FUZ_rand(&randState) & 3)); 610 prefs.frameInfo.contentChecksumFlag = (LZ4F_contentChecksum_t)(FUZ_rand(&randState) & 1); 611 prefs.frameInfo.contentSize = ((FUZ_rand(&randState) & 0xF) == 1) ? srcSize : 0; 612 prefs.autoFlush = neverFlush ? 0 : (FUZ_rand(&randState) & 7) == 2; 613 prefs.compressionLevel = FUZ_rand(&randState) % 5; 614 if ((FUZ_rand(&randState) & 0xF) == 1) prefsPtr = NULL; 615 616 DISPLAYUPDATE(2, "\r%5u ", testNb); 617 618 if ((FUZ_rand(&randState) & 0xFFF) == 0) { 619 /* create a skippable frame (rare case) */ 620 BYTE* op = (BYTE*)compressedBuffer; 621 FUZ_writeLE32(op, LZ4F_MAGIC_SKIPPABLE_START + (FUZ_rand(&randState) & 15)); 622 FUZ_writeLE32(op+4, (U32)srcSize); 623 cSize = srcSize+8; 624 } else if ((FUZ_rand(&randState) & 0xF) == 2) { /* single pass compression (simple) */ 625 cSize = LZ4F_compressFrame(compressedBuffer, LZ4F_compressFrameBound(srcSize, prefsPtr), srcStart, srcSize, prefsPtr); 626 CHECK(LZ4F_isError(cSize), "LZ4F_compressFrame failed : error %i (%s)", (int)cSize, LZ4F_getErrorName(cSize)); 627 } else { /* multi-segments compression */ 628 const BYTE* ip = srcStart; 629 const BYTE* const iend = srcStart + srcSize; 630 BYTE* op = (BYTE*)compressedBuffer; 631 BYTE* const oend = op + (neverFlush ? LZ4F_compressFrameBound(srcSize, prefsPtr) : compressedBufferSize); /* when flushes are possible, can't guarantee a max compressed size */ 632 unsigned const maxBits = FUZ_highbit((U32)srcSize); 633 LZ4F_compressOptions_t cOptions; 634 memset(&cOptions, 0, sizeof(cOptions)); 635 result = LZ4F_compressBegin(cCtx, op, oend-op, prefsPtr); 636 CHECK(LZ4F_isError(result), "Compression header failed (error %i)", (int)result); 637 op += result; 638 while (ip < iend) { 639 unsigned const nbBitsSeg = FUZ_rand(&randState) % maxBits; 640 size_t const sampleMax = (FUZ_rand(&randState) & ((1<<nbBitsSeg)-1)) + 1; 641 size_t const iSize = MIN(sampleMax, (size_t)(iend-ip)); 642 size_t const oSize = LZ4F_compressBound(iSize, prefsPtr); 643 cOptions.stableSrc = ((FUZ_rand(&randState) & 3) == 1); 644 645 result = LZ4F_compressUpdate(cCtx, op, oSize, ip, iSize, &cOptions); 646 CHECK(LZ4F_isError(result), "Compression failed (error %i : %s)", (int)result, LZ4F_getErrorName(result)); 647 op += result; 648 ip += iSize; 649 650 { unsigned const forceFlush = neverFlush ? 0 : ((FUZ_rand(&randState) & 3) == 1); 651 if (forceFlush) { 652 result = LZ4F_flush(cCtx, op, oend-op, &cOptions); 653 CHECK(LZ4F_isError(result), "Compression failed (error %i)", (int)result); 654 op += result; 655 } } 656 } 657 CHECK(op>=oend, "LZ4F_compressFrameBound overflow"); 658 result = LZ4F_compressEnd(cCtx, op, oend-op, &cOptions); 659 CHECK(LZ4F_isError(result), "Compression completion failed (error %i : %s)", (int)result, LZ4F_getErrorName(result)); 660 op += result; 661 cSize = op-(BYTE*)compressedBuffer; 662 DISPLAYLEVEL(5, "\nCompressed %u bytes into %u \n", (U32)srcSize, (U32)cSize); 663 } 664 665 /* multi-segments decompression */ 666 { const BYTE* ip = (const BYTE*)compressedBuffer; 667 const BYTE* const iend = ip + cSize; 668 BYTE* op = (BYTE*)decodedBuffer; 669 BYTE* const oend = op + srcDataLength; 670 unsigned const suggestedBits = FUZ_highbit((U32)cSize); 671 unsigned const maxBits = MAX(3, suggestedBits); 672 unsigned const nonContiguousDst = FUZ_rand(&randState) % 3; /* 0 : contiguous; 1 : non-contiguous; 2 : dst overwritten */ 673 size_t totalOut = 0; 674 XXH64_state_t xxh64; 675 XXH64_reset(&xxh64, 1); 676 while (ip < iend) { 677 unsigned const nbBitsI = (FUZ_rand(&randState) % (maxBits-1)) + 1; 678 unsigned const nbBitsO = (FUZ_rand(&randState) % (maxBits)) + 1; 679 size_t const iSizeMax = (FUZ_rand(&randState) & ((1<<nbBitsI)-1)) + 1; 680 size_t iSize = MIN(iSizeMax, (size_t)(iend-ip)); 681 size_t const oSizeMax = (FUZ_rand(&randState) & ((1<<nbBitsO)-1)) + 2; 682 size_t oSize = MIN(oSizeMax, (size_t)(oend-op)); 683 LZ4F_decompressOptions_t dOptions; 684 memset(&dOptions, 0, sizeof(dOptions)); 685 dOptions.stableDst = FUZ_rand(&randState) & 1; 686 if (nonContiguousDst==2) dOptions.stableDst = 0; /* overwrite mode */ 687 result = LZ4F_decompress(dCtx, op, &oSize, ip, &iSize, &dOptions); 688 if (LZ4F_getErrorCode(result) == LZ4F_ERROR_contentChecksum_invalid) locateBuffDiff(srcStart, decodedBuffer, srcSize, nonContiguousDst); 689 CHECK(LZ4F_isError(result), "Decompression failed (error %i:%s)", (int)result, LZ4F_getErrorName(result)); 690 XXH64_update(&xxh64, op, (U32)oSize); 691 totalOut += oSize; 692 op += oSize; 693 ip += iSize; 694 op += nonContiguousDst; 695 if (nonContiguousDst==2) op = (BYTE*)decodedBuffer; /* overwritten destination */ 696 } 697 CHECK(result != 0, "Frame decompression failed (error %i)", (int)result); 698 if (totalOut) { /* otherwise, it's a skippable frame */ 699 U64 const crcDecoded = XXH64_digest(&xxh64); 700 if (crcDecoded != crcOrig) locateBuffDiff(srcStart, decodedBuffer, srcSize, nonContiguousDst); 701 CHECK(crcDecoded != crcOrig, "Decompression corruption"); 702 } 703 } 704 } 705 706 DISPLAYLEVEL(2, "\rAll tests completed \n"); 707 708 _end: 709 LZ4F_freeDecompressionContext(dCtx); 710 LZ4F_freeCompressionContext(cCtx); 711 free(srcBuffer); 712 free(compressedBuffer); 713 free(decodedBuffer); 714 715 if (use_pause) { 716 DISPLAY("press enter to finish \n"); 717 (void)getchar(); 718 } 719 return testResult; 720 721 _output_error: 722 testResult = 1; 723 goto _end; 724 } 725 726 727 int FUZ_usage(const char* programName) 728 { 729 DISPLAY( "Usage :\n"); 730 DISPLAY( " %s [args]\n", programName); 731 DISPLAY( "\n"); 732 DISPLAY( "Arguments :\n"); 733 DISPLAY( " -i# : Nb of tests (default:%u) \n", nbTestsDefault); 734 DISPLAY( " -T# : Duration of tests, in seconds (default: use Nb of tests) \n"); 735 DISPLAY( " -s# : Select seed (default:prompt user)\n"); 736 DISPLAY( " -t# : Select starting test number (default:0)\n"); 737 DISPLAY( " -P# : Select compressibility in %% (default:%i%%)\n", FUZ_COMPRESSIBILITY_DEFAULT); 738 DISPLAY( " -v : verbose\n"); 739 DISPLAY( " -h : display help and exit\n"); 740 return 0; 741 } 742 743 744 int main(int argc, const char** argv) 745 { 746 U32 seed=0; 747 int seedset=0; 748 int argNb; 749 int nbTests = nbTestsDefault; 750 int testNb = 0; 751 int proba = FUZ_COMPRESSIBILITY_DEFAULT; 752 int result=0; 753 U32 duration=0; 754 const char* const programName = argv[0]; 755 756 /* Check command line */ 757 for (argNb=1; argNb<argc; argNb++) { 758 const char* argument = argv[argNb]; 759 760 if(!argument) continue; /* Protection if argument empty */ 761 762 /* Decode command (note : aggregated short commands are allowed) */ 763 if (argument[0]=='-') { 764 if (!strcmp(argument, "--no-prompt")) { 765 no_prompt=1; 766 seedset=1; 767 displayLevel=1; 768 continue; 769 } 770 argument++; 771 772 while (*argument!=0) { 773 switch(*argument) 774 { 775 case 'h': 776 return FUZ_usage(programName); 777 case 'v': 778 argument++; 779 displayLevel++; 780 break; 781 case 'q': 782 argument++; 783 displayLevel--; 784 break; 785 case 'p': /* pause at the end */ 786 argument++; 787 use_pause = 1; 788 break; 789 790 case 'i': 791 argument++; 792 nbTests=0; duration=0; 793 while ((*argument>='0') && (*argument<='9')) { 794 nbTests *= 10; 795 nbTests += *argument - '0'; 796 argument++; 797 } 798 break; 799 800 case 'T': 801 argument++; 802 nbTests = 0; duration = 0; 803 for (;;) { 804 switch(*argument) 805 { 806 case 'm': duration *= 60; argument++; continue; 807 case 's': 808 case 'n': argument++; continue; 809 case '0': 810 case '1': 811 case '2': 812 case '3': 813 case '4': 814 case '5': 815 case '6': 816 case '7': 817 case '8': 818 case '9': duration *= 10; duration += *argument++ - '0'; continue; 819 } 820 break; 821 } 822 break; 823 824 case 's': 825 argument++; 826 seed=0; 827 seedset=1; 828 while ((*argument>='0') && (*argument<='9')) { 829 seed *= 10; 830 seed += *argument - '0'; 831 argument++; 832 } 833 break; 834 case 't': 835 argument++; 836 testNb=0; 837 while ((*argument>='0') && (*argument<='9')) { 838 testNb *= 10; 839 testNb += *argument - '0'; 840 argument++; 841 } 842 break; 843 case 'P': /* compressibility % */ 844 argument++; 845 proba=0; 846 while ((*argument>='0') && (*argument<='9')) { 847 proba *= 10; 848 proba += *argument - '0'; 849 argument++; 850 } 851 if (proba<0) proba=0; 852 if (proba>100) proba=100; 853 break; 854 default: 855 ; 856 return FUZ_usage(programName); 857 } 858 } 859 } 860 } 861 862 /* Get Seed */ 863 DISPLAY("Starting lz4frame tester (%i-bits, %s)\n", (int)(sizeof(size_t)*8), LZ4_VERSION_STRING); 864 865 if (!seedset) { 866 time_t const t = time(NULL); 867 U32 const h = XXH32(&t, sizeof(t), 1); 868 seed = h % 10000; 869 } 870 DISPLAY("Seed = %u\n", seed); 871 if (proba!=FUZ_COMPRESSIBILITY_DEFAULT) DISPLAY("Compressibility : %i%%\n", proba); 872 873 if (nbTests<=0) nbTests=1; 874 875 if (testNb==0) result = basicTests(seed, ((double)proba) / 100); 876 if (result) return 1; 877 return fuzzerTests(seed, nbTests, testNb, ((double)proba) / 100, duration); 878 } 879