Home | History | Annotate | Download | only in programs
      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 *********************************************************/
    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 
    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 
    121 static U32 FUZ_rotl32(U32 u32, U32 nbBits)
    122 {
    123     return ((u32 << nbBits) | (u32 >> (32 - nbBits)));
    124 }
    125 
    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)
    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)
    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 
    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 
    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 
    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 
   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 
   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