| Yann Collet | 4ded9e5 | 2016-08-30 10:04:33 -0700 | [diff] [blame] | 1 | /** | 
|  | 2 | * Copyright (c) 2016-present, Yann Collet, Facebook, Inc. | 
|  | 3 | * All rights reserved. | 
|  | 4 | * | 
|  | 5 | * This source code is licensed under the BSD-style license found in the | 
|  | 6 | * LICENSE file in the root directory of this source tree. An additional grant | 
|  | 7 | * of patent rights can be found in the PATENTS file in the same directory. | 
|  | 8 | */ | 
| Yann Collet | d7883a2 | 2016-08-12 16:48:02 +0200 | [diff] [blame] | 9 |  | 
| Yann Collet | d7883a2 | 2016-08-12 16:48:02 +0200 | [diff] [blame] | 10 |  | 
|  | 11 | /*-************************************ | 
|  | 12 | *  Compiler specific | 
|  | 13 | **************************************/ | 
|  | 14 | #ifdef _MSC_VER    /* Visual Studio */ | 
| Przemyslaw Skibinski | 2f6ccee | 2016-12-21 13:23:34 +0100 | [diff] [blame] | 15 | #  pragma warning(disable : 4127)     /* disable: C4127: conditional expression is constant */ | 
| Yann Collet | d7883a2 | 2016-08-12 16:48:02 +0200 | [diff] [blame] | 16 | #  pragma warning(disable : 4146)     /* disable: C4146: minus unsigned expression */ | 
|  | 17 | #endif | 
|  | 18 |  | 
|  | 19 |  | 
|  | 20 | /*-************************************ | 
|  | 21 | *  Includes | 
|  | 22 | **************************************/ | 
|  | 23 | #include <stdlib.h>       /* free */ | 
|  | 24 | #include <stdio.h>        /* fgets, sscanf */ | 
| Yann Collet | ef9999f | 2016-09-01 16:44:48 -0700 | [diff] [blame] | 25 | #include <time.h>         /* clock_t, clock() */ | 
| Yann Collet | d7883a2 | 2016-08-12 16:48:02 +0200 | [diff] [blame] | 26 | #include <string.h>       /* strcmp */ | 
| Przemyslaw Skibinski | 2f6ccee | 2016-12-21 13:23:34 +0100 | [diff] [blame] | 27 | #include "mem.h" | 
| Yann Collet | ef9999f | 2016-09-01 16:44:48 -0700 | [diff] [blame] | 28 | #define ZSTD_STATIC_LINKING_ONLY   /* ZSTD_maxCLevel, ZSTD_customMem */ | 
| Yann Collet | d7883a2 | 2016-08-12 16:48:02 +0200 | [diff] [blame] | 29 | #include "zstd.h"         /* ZSTD_compressBound */ | 
| Yann Collet | e795c8a | 2016-12-13 16:39:36 +0100 | [diff] [blame] | 30 | #include "zstd_errors.h"  /* ZSTD_error_srcSize_wrong */ | 
| Yann Collet | d7883a2 | 2016-08-12 16:48:02 +0200 | [diff] [blame] | 31 | #include "datagen.h"      /* RDG_genBuffer */ | 
| Yann Collet | ef9999f | 2016-09-01 16:44:48 -0700 | [diff] [blame] | 32 | #define XXH_STATIC_LINKING_ONLY   /* XXH64_state_t */ | 
| Yann Collet | d7883a2 | 2016-08-12 16:48:02 +0200 | [diff] [blame] | 33 | #include "xxhash.h"       /* XXH64_* */ | 
|  | 34 |  | 
|  | 35 |  | 
|  | 36 | /*-************************************ | 
|  | 37 | *  Constants | 
|  | 38 | **************************************/ | 
|  | 39 | #define KB *(1U<<10) | 
|  | 40 | #define MB *(1U<<20) | 
|  | 41 | #define GB *(1U<<30) | 
|  | 42 |  | 
|  | 43 | static const U32 nbTestsDefault = 10000; | 
|  | 44 | #define COMPRESSIBLE_NOISE_LENGTH (10 MB) | 
|  | 45 | #define FUZ_COMPRESSIBILITY_DEFAULT 50 | 
|  | 46 | static const U32 prime1 = 2654435761U; | 
|  | 47 | static const U32 prime2 = 2246822519U; | 
|  | 48 |  | 
|  | 49 |  | 
| Yann Collet | d7883a2 | 2016-08-12 16:48:02 +0200 | [diff] [blame] | 50 | /*-************************************ | 
|  | 51 | *  Display Macros | 
|  | 52 | **************************************/ | 
|  | 53 | #define DISPLAY(...)          fprintf(stderr, __VA_ARGS__) | 
|  | 54 | #define DISPLAYLEVEL(l, ...)  if (g_displayLevel>=l) { DISPLAY(__VA_ARGS__); } | 
|  | 55 | static U32 g_displayLevel = 2; | 
|  | 56 |  | 
|  | 57 | #define DISPLAYUPDATE(l, ...) if (g_displayLevel>=l) { \ | 
| Yann Collet | ef9999f | 2016-09-01 16:44:48 -0700 | [diff] [blame] | 58 | if ((FUZ_GetClockSpan(g_displayClock) > g_refreshRate) || (g_displayLevel>=4)) \ | 
|  | 59 | { g_displayClock = clock(); DISPLAY(__VA_ARGS__); \ | 
| Yann Collet | d7883a2 | 2016-08-12 16:48:02 +0200 | [diff] [blame] | 60 | if (g_displayLevel>=4) fflush(stdout); } } | 
| Yann Collet | b3060f7 | 2016-09-09 16:44:16 +0200 | [diff] [blame] | 61 | static const clock_t g_refreshRate = CLOCKS_PER_SEC / 6; | 
| Yann Collet | ef9999f | 2016-09-01 16:44:48 -0700 | [diff] [blame] | 62 | static clock_t g_displayClock = 0; | 
| Yann Collet | d7883a2 | 2016-08-12 16:48:02 +0200 | [diff] [blame] | 63 |  | 
| Yann Collet | ef9999f | 2016-09-01 16:44:48 -0700 | [diff] [blame] | 64 | static clock_t g_clockTime = 0; | 
| Yann Collet | d7883a2 | 2016-08-12 16:48:02 +0200 | [diff] [blame] | 65 |  | 
|  | 66 |  | 
|  | 67 | /*-******************************************************* | 
|  | 68 | *  Fuzzer functions | 
|  | 69 | *********************************************************/ | 
|  | 70 | #define MAX(a,b) ((a)>(b)?(a):(b)) | 
|  | 71 |  | 
| Yann Collet | ef9999f | 2016-09-01 16:44:48 -0700 | [diff] [blame] | 72 | static clock_t FUZ_GetClockSpan(clock_t clockStart) | 
| Yann Collet | d7883a2 | 2016-08-12 16:48:02 +0200 | [diff] [blame] | 73 | { | 
| Yann Collet | ef9999f | 2016-09-01 16:44:48 -0700 | [diff] [blame] | 74 | return clock() - clockStart;  /* works even when overflow. Max span ~ 30 mn */ | 
| Yann Collet | d7883a2 | 2016-08-12 16:48:02 +0200 | [diff] [blame] | 75 | } | 
|  | 76 |  | 
|  | 77 | /*! FUZ_rand() : | 
|  | 78 | @return : a 27 bits random value, from a 32-bits `seed`. | 
|  | 79 | `seed` is also modified */ | 
| Yann Collet | 9516234 | 2016-10-25 16:19:52 -0700 | [diff] [blame] | 80 | #define FUZ_rotl32(x,r) ((x << r) | (x >> (32 - r))) | 
| Yann Collet | d7883a2 | 2016-08-12 16:48:02 +0200 | [diff] [blame] | 81 | unsigned int FUZ_rand(unsigned int* seedPtr) | 
|  | 82 | { | 
|  | 83 | U32 rand32 = *seedPtr; | 
|  | 84 | rand32 *= prime1; | 
|  | 85 | rand32 += prime2; | 
|  | 86 | rand32  = FUZ_rotl32(rand32, 13); | 
|  | 87 | *seedPtr = rand32; | 
|  | 88 | return rand32 >> 5; | 
|  | 89 | } | 
|  | 90 |  | 
| Yann Collet | d7883a2 | 2016-08-12 16:48:02 +0200 | [diff] [blame] | 91 | static void* allocFunction(void* opaque, size_t size) | 
|  | 92 | { | 
|  | 93 | void* address = malloc(size); | 
|  | 94 | (void)opaque; | 
|  | 95 | return address; | 
|  | 96 | } | 
|  | 97 |  | 
|  | 98 | static void freeFunction(void* opaque, void* address) | 
|  | 99 | { | 
|  | 100 | (void)opaque; | 
|  | 101 | free(address); | 
|  | 102 | } | 
|  | 103 |  | 
| Yann Collet | cb32763 | 2016-08-23 00:30:31 +0200 | [diff] [blame] | 104 |  | 
|  | 105 | /*====================================================== | 
|  | 106 | *   Basic Unit tests | 
|  | 107 | ======================================================*/ | 
|  | 108 |  | 
| Yann Collet | d7883a2 | 2016-08-12 16:48:02 +0200 | [diff] [blame] | 109 | static int basicUnitTests(U32 seed, double compressibility, ZSTD_customMem customMem) | 
|  | 110 | { | 
| Yann Collet | b3060f7 | 2016-09-09 16:44:16 +0200 | [diff] [blame] | 111 | size_t const CNBufferSize = COMPRESSIBLE_NOISE_LENGTH; | 
| Yann Collet | d7883a2 | 2016-08-12 16:48:02 +0200 | [diff] [blame] | 112 | void* CNBuffer = malloc(CNBufferSize); | 
|  | 113 | size_t const skippableFrameSize = 11; | 
|  | 114 | size_t const compressedBufferSize = (8 + skippableFrameSize) + ZSTD_compressBound(COMPRESSIBLE_NOISE_LENGTH); | 
|  | 115 | void* compressedBuffer = malloc(compressedBufferSize); | 
|  | 116 | size_t const decodedBufferSize = CNBufferSize; | 
|  | 117 | void* decodedBuffer = malloc(decodedBufferSize); | 
|  | 118 | size_t cSize; | 
| Yann Collet | b3060f7 | 2016-09-09 16:44:16 +0200 | [diff] [blame] | 119 | int testResult = 0; | 
| Yann Collet | d7883a2 | 2016-08-12 16:48:02 +0200 | [diff] [blame] | 120 | U32 testNb=0; | 
|  | 121 | ZSTD_CStream* zc = ZSTD_createCStream_advanced(customMem); | 
|  | 122 | ZSTD_DStream* zd = ZSTD_createDStream_advanced(customMem); | 
| Yann Collet | 9ffbeea | 2016-12-02 18:37:38 -0800 | [diff] [blame] | 123 | ZSTD_inBuffer  inBuff, inBuff2; | 
| Yann Collet | 53e17fb | 2016-08-17 01:39:22 +0200 | [diff] [blame] | 124 | ZSTD_outBuffer outBuff; | 
| Yann Collet | d7883a2 | 2016-08-12 16:48:02 +0200 | [diff] [blame] | 125 |  | 
|  | 126 | /* Create compressible test buffer */ | 
|  | 127 | if (!CNBuffer || !compressedBuffer || !decodedBuffer || !zc || !zd) { | 
|  | 128 | DISPLAY("Not enough memory, aborting\n"); | 
|  | 129 | goto _output_error; | 
|  | 130 | } | 
|  | 131 | RDG_genBuffer(CNBuffer, CNBufferSize, compressibility, 0., seed); | 
|  | 132 |  | 
|  | 133 | /* generate skippable frame */ | 
|  | 134 | MEM_writeLE32(compressedBuffer, ZSTD_MAGIC_SKIPPABLE_START); | 
|  | 135 | MEM_writeLE32(((char*)compressedBuffer)+4, (U32)skippableFrameSize); | 
|  | 136 | cSize = skippableFrameSize + 8; | 
|  | 137 |  | 
|  | 138 | /* Basic compression test */ | 
|  | 139 | DISPLAYLEVEL(4, "test%3i : compress %u bytes : ", testNb++, COMPRESSIBLE_NOISE_LENGTH); | 
|  | 140 | ZSTD_initCStream_usingDict(zc, CNBuffer, 128 KB, 1); | 
| Yann Collet | 53e17fb | 2016-08-17 01:39:22 +0200 | [diff] [blame] | 141 | outBuff.dst = (char*)(compressedBuffer)+cSize; | 
|  | 142 | outBuff.size = compressedBufferSize; | 
|  | 143 | outBuff.pos = 0; | 
|  | 144 | inBuff.src = CNBuffer; | 
|  | 145 | inBuff.size = CNBufferSize; | 
|  | 146 | inBuff.pos = 0; | 
|  | 147 | { size_t const r = ZSTD_compressStream(zc, &outBuff, &inBuff); | 
| Yann Collet | d7883a2 | 2016-08-12 16:48:02 +0200 | [diff] [blame] | 148 | if (ZSTD_isError(r)) goto _output_error; } | 
| Yann Collet | 53e17fb | 2016-08-17 01:39:22 +0200 | [diff] [blame] | 149 | if (inBuff.pos != inBuff.size) goto _output_error;   /* entire input should be consumed */ | 
|  | 150 | { size_t const r = ZSTD_endStream(zc, &outBuff); | 
| Yann Collet | 9a021c1 | 2016-08-26 09:05:06 +0200 | [diff] [blame] | 151 | if (r != 0) goto _output_error; }  /* error, or some data not flushed */ | 
| Yann Collet | 53e17fb | 2016-08-17 01:39:22 +0200 | [diff] [blame] | 152 | cSize += outBuff.pos; | 
| Yann Collet | d7883a2 | 2016-08-12 16:48:02 +0200 | [diff] [blame] | 153 | DISPLAYLEVEL(4, "OK (%u bytes : %.2f%%)\n", (U32)cSize, (double)cSize/COMPRESSIBLE_NOISE_LENGTH*100); | 
|  | 154 |  | 
| Yann Collet | cb32763 | 2016-08-23 00:30:31 +0200 | [diff] [blame] | 155 | DISPLAYLEVEL(4, "test%3i : check CStream size : ", testNb++); | 
| Yann Collet | 70e3b31 | 2016-08-23 01:18:06 +0200 | [diff] [blame] | 156 | { size_t const s = ZSTD_sizeof_CStream(zc); | 
| Yann Collet | cb32763 | 2016-08-23 00:30:31 +0200 | [diff] [blame] | 157 | if (ZSTD_isError(s)) goto _output_error; | 
|  | 158 | DISPLAYLEVEL(4, "OK (%u bytes) \n", (U32)s); | 
|  | 159 | } | 
|  | 160 |  | 
| Yann Collet | d7883a2 | 2016-08-12 16:48:02 +0200 | [diff] [blame] | 161 | /* skippable frame test */ | 
|  | 162 | DISPLAYLEVEL(4, "test%3i : decompress skippable frame : ", testNb++); | 
|  | 163 | ZSTD_initDStream_usingDict(zd, CNBuffer, 128 KB); | 
| Yann Collet | 53e17fb | 2016-08-17 01:39:22 +0200 | [diff] [blame] | 164 | inBuff.src = compressedBuffer; | 
|  | 165 | inBuff.size = cSize; | 
|  | 166 | inBuff.pos = 0; | 
|  | 167 | outBuff.dst = decodedBuffer; | 
|  | 168 | outBuff.size = CNBufferSize; | 
|  | 169 | outBuff.pos = 0; | 
|  | 170 | { size_t const r = ZSTD_decompressStream(zd, &outBuff, &inBuff); | 
| Yann Collet | d7883a2 | 2016-08-12 16:48:02 +0200 | [diff] [blame] | 171 | if (r != 0) goto _output_error; } | 
| Yann Collet | 53e17fb | 2016-08-17 01:39:22 +0200 | [diff] [blame] | 172 | if (outBuff.pos != 0) goto _output_error;   /* skippable frame len is 0 */ | 
| Yann Collet | d7883a2 | 2016-08-12 16:48:02 +0200 | [diff] [blame] | 173 | DISPLAYLEVEL(4, "OK \n"); | 
|  | 174 |  | 
|  | 175 | /* Basic decompression test */ | 
| Yann Collet | 9ffbeea | 2016-12-02 18:37:38 -0800 | [diff] [blame] | 176 | inBuff2 = inBuff; | 
| Yann Collet | d7883a2 | 2016-08-12 16:48:02 +0200 | [diff] [blame] | 177 | DISPLAYLEVEL(4, "test%3i : decompress %u bytes : ", testNb++, COMPRESSIBLE_NOISE_LENGTH); | 
|  | 178 | ZSTD_initDStream_usingDict(zd, CNBuffer, 128 KB); | 
| Yann Collet | 17e482e | 2016-08-23 16:58:10 +0200 | [diff] [blame] | 179 | { size_t const r = ZSTD_setDStreamParameter(zd, ZSTDdsp_maxWindowSize, 1000000000);  /* large limit */ | 
|  | 180 | if (ZSTD_isError(r)) goto _output_error; } | 
| Yann Collet | 9ffbeea | 2016-12-02 18:37:38 -0800 | [diff] [blame] | 181 | { size_t const remaining = ZSTD_decompressStream(zd, &outBuff, &inBuff); | 
|  | 182 | if (remaining != 0) goto _output_error; }  /* should reach end of frame == 0; otherwise, some data left, or an error */ | 
|  | 183 | if (outBuff.pos != CNBufferSize) goto _output_error;   /* should regenerate the same amount */ | 
|  | 184 | if (inBuff.pos != inBuff.size) goto _output_error;   /* should have read the entire frame */ | 
|  | 185 | DISPLAYLEVEL(4, "OK \n"); | 
|  | 186 |  | 
|  | 187 | /* Re-use without init */ | 
|  | 188 | DISPLAYLEVEL(4, "test%3i : decompress again without init (re-use previous settings): ", testNb++); | 
|  | 189 | outBuff.pos = 0; | 
|  | 190 | { size_t const remaining = ZSTD_decompressStream(zd, &outBuff, &inBuff2); | 
|  | 191 | if (remaining != 0) goto _output_error; }  /* should reach end of frame == 0; otherwise, some data left, or an error */ | 
| Yann Collet | 53e17fb | 2016-08-17 01:39:22 +0200 | [diff] [blame] | 192 | if (outBuff.pos != CNBufferSize) goto _output_error;   /* should regenerate the same amount */ | 
|  | 193 | if (inBuff.pos != inBuff.size) goto _output_error;   /* should have read the entire frame */ | 
| Yann Collet | d7883a2 | 2016-08-12 16:48:02 +0200 | [diff] [blame] | 194 | DISPLAYLEVEL(4, "OK \n"); | 
|  | 195 |  | 
|  | 196 | /* check regenerated data is byte exact */ | 
|  | 197 | DISPLAYLEVEL(4, "test%3i : check decompressed result : ", testNb++); | 
|  | 198 | {   size_t i; | 
|  | 199 | for (i=0; i<CNBufferSize; i++) { | 
|  | 200 | if (((BYTE*)decodedBuffer)[i] != ((BYTE*)CNBuffer)[i]) goto _output_error; | 
|  | 201 | }   } | 
|  | 202 | DISPLAYLEVEL(4, "OK \n"); | 
|  | 203 |  | 
| Yann Collet | cb32763 | 2016-08-23 00:30:31 +0200 | [diff] [blame] | 204 | DISPLAYLEVEL(4, "test%3i : check DStream size : ", testNb++); | 
| Yann Collet | 70e3b31 | 2016-08-23 01:18:06 +0200 | [diff] [blame] | 205 | { size_t const s = ZSTD_sizeof_DStream(zd); | 
| Yann Collet | cb32763 | 2016-08-23 00:30:31 +0200 | [diff] [blame] | 206 | if (ZSTD_isError(s)) goto _output_error; | 
|  | 207 | DISPLAYLEVEL(4, "OK (%u bytes) \n", (U32)s); | 
|  | 208 | } | 
|  | 209 |  | 
| Yann Collet | d7883a2 | 2016-08-12 16:48:02 +0200 | [diff] [blame] | 210 | /* Byte-by-byte decompression test */ | 
|  | 211 | DISPLAYLEVEL(4, "test%3i : decompress byte-by-byte : ", testNb++); | 
| Yann Collet | 3ecbe6a | 2016-09-14 17:26:59 +0200 | [diff] [blame] | 212 | {   /* skippable frame */ | 
|  | 213 | size_t r = 1; | 
| Yann Collet | d7883a2 | 2016-08-12 16:48:02 +0200 | [diff] [blame] | 214 | ZSTD_initDStream_usingDict(zd, CNBuffer, 128 KB); | 
| Yann Collet | 53e17fb | 2016-08-17 01:39:22 +0200 | [diff] [blame] | 215 | inBuff.src = compressedBuffer; | 
|  | 216 | outBuff.dst = decodedBuffer; | 
|  | 217 | inBuff.pos = 0; | 
|  | 218 | outBuff.pos = 0; | 
| Yann Collet | d7883a2 | 2016-08-12 16:48:02 +0200 | [diff] [blame] | 219 | while (r) {   /* skippable frame */ | 
| Yann Collet | 53e17fb | 2016-08-17 01:39:22 +0200 | [diff] [blame] | 220 | inBuff.size = inBuff.pos + 1; | 
|  | 221 | outBuff.size = outBuff.pos + 1; | 
|  | 222 | r = ZSTD_decompressStream(zd, &outBuff, &inBuff); | 
| Yann Collet | d7883a2 | 2016-08-12 16:48:02 +0200 | [diff] [blame] | 223 | if (ZSTD_isError(r)) goto _output_error; | 
|  | 224 | } | 
| Yann Collet | 3ecbe6a | 2016-09-14 17:26:59 +0200 | [diff] [blame] | 225 | /* normal frame */ | 
| Yann Collet | d7883a2 | 2016-08-12 16:48:02 +0200 | [diff] [blame] | 226 | ZSTD_initDStream_usingDict(zd, CNBuffer, 128 KB); | 
|  | 227 | r=1; | 
| Yann Collet | 3ecbe6a | 2016-09-14 17:26:59 +0200 | [diff] [blame] | 228 | while (r) { | 
| Yann Collet | 53e17fb | 2016-08-17 01:39:22 +0200 | [diff] [blame] | 229 | inBuff.size = inBuff.pos + 1; | 
|  | 230 | outBuff.size = outBuff.pos + 1; | 
|  | 231 | r = ZSTD_decompressStream(zd, &outBuff, &inBuff); | 
| Yann Collet | d7883a2 | 2016-08-12 16:48:02 +0200 | [diff] [blame] | 232 | if (ZSTD_isError(r)) goto _output_error; | 
|  | 233 | } | 
|  | 234 | } | 
| Yann Collet | 53e17fb | 2016-08-17 01:39:22 +0200 | [diff] [blame] | 235 | if (outBuff.pos != CNBufferSize) goto _output_error;   /* should regenerate the same amount */ | 
|  | 236 | if (inBuff.pos != cSize) goto _output_error;   /* should have read the entire frame */ | 
| Yann Collet | d7883a2 | 2016-08-12 16:48:02 +0200 | [diff] [blame] | 237 | DISPLAYLEVEL(4, "OK \n"); | 
|  | 238 |  | 
|  | 239 | /* check regenerated data is byte exact */ | 
|  | 240 | DISPLAYLEVEL(4, "test%3i : check decompressed result : ", testNb++); | 
|  | 241 | {   size_t i; | 
|  | 242 | for (i=0; i<CNBufferSize; i++) { | 
|  | 243 | if (((BYTE*)decodedBuffer)[i] != ((BYTE*)CNBuffer)[i]) goto _output_error;; | 
|  | 244 | }   } | 
|  | 245 | DISPLAYLEVEL(4, "OK \n"); | 
|  | 246 |  | 
| Yann Collet | e795c8a | 2016-12-13 16:39:36 +0100 | [diff] [blame] | 247 | /* _srcSize compression test */ | 
|  | 248 | DISPLAYLEVEL(4, "test%3i : compress_srcSize %u bytes : ", testNb++, COMPRESSIBLE_NOISE_LENGTH); | 
|  | 249 | ZSTD_initCStream_srcSize(zc, 1, CNBufferSize); | 
| Yann Collet | d564faa | 2016-12-18 21:39:15 +0100 | [diff] [blame] | 250 | outBuff.dst = (char*)(compressedBuffer); | 
| Yann Collet | e795c8a | 2016-12-13 16:39:36 +0100 | [diff] [blame] | 251 | outBuff.size = compressedBufferSize; | 
|  | 252 | outBuff.pos = 0; | 
|  | 253 | inBuff.src = CNBuffer; | 
|  | 254 | inBuff.size = CNBufferSize; | 
|  | 255 | inBuff.pos = 0; | 
|  | 256 | { size_t const r = ZSTD_compressStream(zc, &outBuff, &inBuff); | 
|  | 257 | if (ZSTD_isError(r)) goto _output_error; } | 
|  | 258 | if (inBuff.pos != inBuff.size) goto _output_error;   /* entire input should be consumed */ | 
|  | 259 | { size_t const r = ZSTD_endStream(zc, &outBuff); | 
|  | 260 | if (r != 0) goto _output_error; }  /* error, or some data not flushed */ | 
| Yann Collet | d564faa | 2016-12-18 21:39:15 +0100 | [diff] [blame] | 261 | { unsigned long long origSize = ZSTD_getDecompressedSize(outBuff.dst, outBuff.pos); | 
|  | 262 | DISPLAY("outBuff.pos : %u \n", (U32)outBuff.pos); | 
|  | 263 | DISPLAY("origSize = %u \n", (U32)origSize); | 
|  | 264 | if ((size_t)origSize != CNBufferSize) goto _output_error; }  /* exact original size must be present */ | 
| Yann Collet | e795c8a | 2016-12-13 16:39:36 +0100 | [diff] [blame] | 265 | DISPLAYLEVEL(4, "OK (%u bytes : %.2f%%)\n", (U32)cSize, (double)cSize/COMPRESSIBLE_NOISE_LENGTH*100); | 
|  | 266 |  | 
|  | 267 | /* wrong _srcSize compression test */ | 
|  | 268 | DISPLAYLEVEL(4, "test%3i : wrong srcSize : %u bytes : ", testNb++, COMPRESSIBLE_NOISE_LENGTH-1); | 
|  | 269 | ZSTD_initCStream_srcSize(zc, 1, CNBufferSize-1); | 
| Yann Collet | d564faa | 2016-12-18 21:39:15 +0100 | [diff] [blame] | 270 | outBuff.dst = (char*)(compressedBuffer); | 
| Yann Collet | e795c8a | 2016-12-13 16:39:36 +0100 | [diff] [blame] | 271 | outBuff.size = compressedBufferSize; | 
|  | 272 | outBuff.pos = 0; | 
|  | 273 | inBuff.src = CNBuffer; | 
|  | 274 | inBuff.size = CNBufferSize; | 
|  | 275 | inBuff.pos = 0; | 
|  | 276 | { size_t const r = ZSTD_compressStream(zc, &outBuff, &inBuff); | 
|  | 277 | if (ZSTD_isError(r)) goto _output_error; } | 
|  | 278 | if (inBuff.pos != inBuff.size) goto _output_error;   /* entire input should be consumed */ | 
|  | 279 | { size_t const r = ZSTD_endStream(zc, &outBuff); | 
|  | 280 | if (ZSTD_getErrorCode(r) != ZSTD_error_srcSize_wrong) goto _output_error;    /* must fail : wrong srcSize */ | 
|  | 281 | DISPLAYLEVEL(4, "OK (error detected : %s) \n", ZSTD_getErrorName(r)); } | 
|  | 282 |  | 
| Yann Collet | 12083a4 | 2016-09-06 15:01:51 +0200 | [diff] [blame] | 283 | /* Complex context re-use scenario */ | 
|  | 284 | DISPLAYLEVEL(4, "test%3i : context re-use : ", testNb++); | 
|  | 285 | ZSTD_freeCStream(zc); | 
|  | 286 | zc = ZSTD_createCStream_advanced(customMem); | 
|  | 287 | if (zc==NULL) goto _output_error;   /* memory allocation issue */ | 
|  | 288 | /* use 1 */ | 
|  | 289 | {   size_t const inSize = 513; | 
|  | 290 | ZSTD_initCStream_advanced(zc, NULL, 0, ZSTD_getParams(19, inSize, 0), inSize);   /* needs btopt + search3 to trigger hashLog3 */ | 
|  | 291 | inBuff.src = CNBuffer; | 
|  | 292 | inBuff.size = inSize; | 
|  | 293 | inBuff.pos = 0; | 
|  | 294 | outBuff.dst = (char*)(compressedBuffer)+cSize; | 
|  | 295 | outBuff.size = ZSTD_compressBound(inSize); | 
|  | 296 | outBuff.pos = 0; | 
|  | 297 | { size_t const r = ZSTD_compressStream(zc, &outBuff, &inBuff); | 
|  | 298 | if (ZSTD_isError(r)) goto _output_error; } | 
|  | 299 | if (inBuff.pos != inBuff.size) goto _output_error;   /* entire input should be consumed */ | 
|  | 300 | { size_t const r = ZSTD_endStream(zc, &outBuff); | 
|  | 301 | if (r != 0) goto _output_error; }  /* error, or some data not flushed */ | 
|  | 302 | } | 
|  | 303 | /* use 2 */ | 
|  | 304 | {   size_t const inSize = 1025;   /* will not continue, because tables auto-adjust and are therefore different size */ | 
|  | 305 | ZSTD_initCStream_advanced(zc, NULL, 0, ZSTD_getParams(19, inSize, 0), inSize);   /* needs btopt + search3 to trigger hashLog3 */ | 
|  | 306 | inBuff.src = CNBuffer; | 
|  | 307 | inBuff.size = inSize; | 
|  | 308 | inBuff.pos = 0; | 
|  | 309 | outBuff.dst = (char*)(compressedBuffer)+cSize; | 
|  | 310 | outBuff.size = ZSTD_compressBound(inSize); | 
|  | 311 | outBuff.pos = 0; | 
|  | 312 | { size_t const r = ZSTD_compressStream(zc, &outBuff, &inBuff); | 
|  | 313 | if (ZSTD_isError(r)) goto _output_error; } | 
|  | 314 | if (inBuff.pos != inBuff.size) goto _output_error;   /* entire input should be consumed */ | 
|  | 315 | { size_t const r = ZSTD_endStream(zc, &outBuff); | 
|  | 316 | if (r != 0) goto _output_error; }  /* error, or some data not flushed */ | 
|  | 317 | } | 
|  | 318 | DISPLAYLEVEL(4, "OK \n"); | 
|  | 319 |  | 
| Yann Collet | 9516234 | 2016-10-25 16:19:52 -0700 | [diff] [blame] | 320 | /* CDict scenario */ | 
|  | 321 | DISPLAYLEVEL(4, "test%3i : digested dictionary : ", testNb++); | 
|  | 322 | {   ZSTD_CDict* const cdict = ZSTD_createCDict(CNBuffer, 128 KB, 1); | 
|  | 323 | size_t const initError = ZSTD_initCStream_usingCDict(zc, cdict); | 
|  | 324 | if (ZSTD_isError(initError)) goto _output_error; | 
|  | 325 | cSize = 0; | 
|  | 326 | outBuff.dst = compressedBuffer; | 
|  | 327 | outBuff.size = compressedBufferSize; | 
|  | 328 | outBuff.pos = 0; | 
|  | 329 | inBuff.src = CNBuffer; | 
|  | 330 | inBuff.size = CNBufferSize; | 
|  | 331 | inBuff.pos = 0; | 
|  | 332 | { size_t const r = ZSTD_compressStream(zc, &outBuff, &inBuff); | 
|  | 333 | if (ZSTD_isError(r)) goto _output_error; } | 
|  | 334 | if (inBuff.pos != inBuff.size) goto _output_error;   /* entire input should be consumed */ | 
|  | 335 | { size_t const r = ZSTD_endStream(zc, &outBuff); | 
|  | 336 | if (r != 0) goto _output_error; }  /* error, or some data not flushed */ | 
|  | 337 | cSize = outBuff.pos; | 
|  | 338 | ZSTD_freeCDict(cdict); | 
|  | 339 | DISPLAYLEVEL(4, "OK (%u bytes : %.2f%%)\n", (U32)cSize, (double)cSize/CNBufferSize*100); | 
|  | 340 | } | 
|  | 341 |  | 
| Yann Collet | 12083a4 | 2016-09-06 15:01:51 +0200 | [diff] [blame] | 342 | DISPLAYLEVEL(4, "test%3i : check CStream size : ", testNb++); | 
|  | 343 | { size_t const s = ZSTD_sizeof_CStream(zc); | 
|  | 344 | if (ZSTD_isError(s)) goto _output_error; | 
|  | 345 | DISPLAYLEVEL(4, "OK (%u bytes) \n", (U32)s); | 
|  | 346 | } | 
|  | 347 |  | 
| Yann Collet | 335ad5d | 2016-10-25 17:47:02 -0700 | [diff] [blame] | 348 | /* DDict scenario */ | 
|  | 349 | DISPLAYLEVEL(4, "test%3i : decompress %u bytes with digested dictionary : ", testNb++, (U32)CNBufferSize); | 
|  | 350 | {   ZSTD_DDict* const ddict = ZSTD_createDDict(CNBuffer, 128 KB); | 
|  | 351 | size_t const initError = ZSTD_initDStream_usingDDict(zd, ddict); | 
|  | 352 | if (ZSTD_isError(initError)) goto _output_error; | 
|  | 353 | inBuff.src = compressedBuffer; | 
|  | 354 | inBuff.size = cSize; | 
|  | 355 | inBuff.pos = 0; | 
|  | 356 | outBuff.dst = decodedBuffer; | 
|  | 357 | outBuff.size = CNBufferSize; | 
|  | 358 | outBuff.pos = 0; | 
|  | 359 | { size_t const r = ZSTD_decompressStream(zd, &outBuff, &inBuff); | 
|  | 360 | if (r != 0) goto _output_error; }  /* should reach end of frame == 0; otherwise, some data left, or an error */ | 
|  | 361 | if (outBuff.pos != CNBufferSize) goto _output_error;   /* should regenerate the same amount */ | 
|  | 362 | if (inBuff.pos != inBuff.size) goto _output_error;   /* should have read the entire frame */ | 
|  | 363 | ZSTD_freeDDict(ddict); | 
|  | 364 | DISPLAYLEVEL(4, "OK \n"); | 
|  | 365 | } | 
|  | 366 |  | 
| Yann Collet | 12083a4 | 2016-09-06 15:01:51 +0200 | [diff] [blame] | 367 | /* test ZSTD_setDStreamParameter() resilience */ | 
| Yann Collet | 17e482e | 2016-08-23 16:58:10 +0200 | [diff] [blame] | 368 | DISPLAYLEVEL(4, "test%3i : wrong parameter for ZSTD_setDStreamParameter(): ", testNb++); | 
|  | 369 | { size_t const r = ZSTD_setDStreamParameter(zd, (ZSTD_DStreamParameter_e)999, 1);  /* large limit */ | 
|  | 370 | if (!ZSTD_isError(r)) goto _output_error; } | 
|  | 371 | DISPLAYLEVEL(4, "OK \n"); | 
|  | 372 |  | 
|  | 373 | /* Memory restriction */ | 
|  | 374 | DISPLAYLEVEL(4, "test%3i : maxWindowSize < frame requirement : ", testNb++); | 
|  | 375 | ZSTD_initDStream_usingDict(zd, CNBuffer, 128 KB); | 
|  | 376 | { size_t const r = ZSTD_setDStreamParameter(zd, ZSTDdsp_maxWindowSize, 1000);  /* too small limit */ | 
|  | 377 | if (ZSTD_isError(r)) goto _output_error; } | 
|  | 378 | inBuff.src = compressedBuffer; | 
|  | 379 | inBuff.size = cSize; | 
|  | 380 | inBuff.pos = 0; | 
|  | 381 | outBuff.dst = decodedBuffer; | 
|  | 382 | outBuff.size = CNBufferSize; | 
|  | 383 | outBuff.pos = 0; | 
|  | 384 | { size_t const r = ZSTD_decompressStream(zd, &outBuff, &inBuff); | 
|  | 385 | if (!ZSTD_isError(r)) goto _output_error;  /* must fail : frame requires > 100 bytes */ | 
|  | 386 | DISPLAYLEVEL(4, "OK (%s)\n", ZSTD_getErrorName(r)); } | 
|  | 387 |  | 
|  | 388 |  | 
| Yann Collet | d7883a2 | 2016-08-12 16:48:02 +0200 | [diff] [blame] | 389 | _end: | 
|  | 390 | ZSTD_freeCStream(zc); | 
|  | 391 | ZSTD_freeDStream(zd); | 
|  | 392 | free(CNBuffer); | 
|  | 393 | free(compressedBuffer); | 
|  | 394 | free(decodedBuffer); | 
|  | 395 | return testResult; | 
|  | 396 |  | 
|  | 397 | _output_error: | 
|  | 398 | testResult = 1; | 
|  | 399 | DISPLAY("Error detected in Unit tests ! \n"); | 
|  | 400 | goto _end; | 
|  | 401 | } | 
|  | 402 |  | 
|  | 403 |  | 
| Yann Collet | 3ecbe6a | 2016-09-14 17:26:59 +0200 | [diff] [blame] | 404 | /* ======   Fuzzer tests   ====== */ | 
|  | 405 |  | 
| Yann Collet | d7883a2 | 2016-08-12 16:48:02 +0200 | [diff] [blame] | 406 | static size_t findDiff(const void* buf1, const void* buf2, size_t max) | 
|  | 407 | { | 
|  | 408 | const BYTE* b1 = (const BYTE*)buf1; | 
|  | 409 | const BYTE* b2 = (const BYTE*)buf2; | 
|  | 410 | size_t u; | 
|  | 411 | for (u=0; u<max; u++) { | 
|  | 412 | if (b1[u] != b2[u]) break; | 
|  | 413 | } | 
|  | 414 | return u; | 
|  | 415 | } | 
|  | 416 |  | 
|  | 417 | static size_t FUZ_rLogLength(U32* seed, U32 logLength) | 
|  | 418 | { | 
|  | 419 | size_t const lengthMask = ((size_t)1 << logLength) - 1; | 
|  | 420 | return (lengthMask+1) + (FUZ_rand(seed) & lengthMask); | 
|  | 421 | } | 
|  | 422 |  | 
|  | 423 | static size_t FUZ_randomLength(U32* seed, U32 maxLog) | 
|  | 424 | { | 
|  | 425 | U32 const logLength = FUZ_rand(seed) % maxLog; | 
|  | 426 | return FUZ_rLogLength(seed, logLength); | 
|  | 427 | } | 
|  | 428 |  | 
|  | 429 | #define MIN(a,b)   ( (a) < (b) ? (a) : (b) ) | 
|  | 430 |  | 
|  | 431 | #define CHECK(cond, ...) if (cond) { DISPLAY("Error => "); DISPLAY(__VA_ARGS__); \ | 
|  | 432 | DISPLAY(" (seed %u, test nb %u)  \n", seed, testNb); goto _output_error; } | 
|  | 433 |  | 
|  | 434 | static int fuzzerTests(U32 seed, U32 nbTests, unsigned startTest, double compressibility) | 
|  | 435 | { | 
|  | 436 | static const U32 maxSrcLog = 24; | 
|  | 437 | static const U32 maxSampleLog = 19; | 
| Yann Collet | 58d5dfe | 2016-09-25 01:34:03 +0200 | [diff] [blame] | 438 | size_t const srcBufferSize = (size_t)1<<maxSrcLog; | 
| Yann Collet | d7883a2 | 2016-08-12 16:48:02 +0200 | [diff] [blame] | 439 | BYTE* cNoiseBuffer[5]; | 
| Yann Collet | 58d5dfe | 2016-09-25 01:34:03 +0200 | [diff] [blame] | 440 | size_t const copyBufferSize= srcBufferSize + (1<<maxSampleLog); | 
|  | 441 | BYTE*  const copyBuffer = (BYTE*)malloc (copyBufferSize); | 
|  | 442 | size_t const cBufferSize   = ZSTD_compressBound(srcBufferSize); | 
|  | 443 | BYTE*  const cBuffer = (BYTE*)malloc (cBufferSize); | 
|  | 444 | size_t const dstBufferSize = srcBufferSize; | 
|  | 445 | BYTE*  const dstBuffer = (BYTE*)malloc (dstBufferSize); | 
| Yann Collet | d7883a2 | 2016-08-12 16:48:02 +0200 | [diff] [blame] | 446 | U32 result = 0; | 
|  | 447 | U32 testNb = 0; | 
|  | 448 | U32 coreSeed = seed; | 
| Yann Collet | 58d5dfe | 2016-09-25 01:34:03 +0200 | [diff] [blame] | 449 | ZSTD_CStream* zc = ZSTD_createCStream();   /* will be reset sometimes */ | 
|  | 450 | ZSTD_DStream* zd = ZSTD_createDStream();   /* will be reset sometimes */ | 
|  | 451 | ZSTD_DStream* const zd_noise = ZSTD_createDStream(); | 
|  | 452 | clock_t const startClock = clock(); | 
|  | 453 | const BYTE* dict=NULL;   /* can keep same dict on 2 consecutive tests */ | 
| Yann Collet | cf409a7 | 2016-09-26 16:41:05 +0200 | [diff] [blame] | 454 | size_t dictSize = 0; | 
|  | 455 | U32 oldTestLog = 0; | 
| Yann Collet | d7883a2 | 2016-08-12 16:48:02 +0200 | [diff] [blame] | 456 |  | 
|  | 457 | /* allocations */ | 
| Yann Collet | d7883a2 | 2016-08-12 16:48:02 +0200 | [diff] [blame] | 458 | cNoiseBuffer[0] = (BYTE*)malloc (srcBufferSize); | 
|  | 459 | cNoiseBuffer[1] = (BYTE*)malloc (srcBufferSize); | 
|  | 460 | cNoiseBuffer[2] = (BYTE*)malloc (srcBufferSize); | 
|  | 461 | cNoiseBuffer[3] = (BYTE*)malloc (srcBufferSize); | 
|  | 462 | cNoiseBuffer[4] = (BYTE*)malloc (srcBufferSize); | 
| Yann Collet | d7883a2 | 2016-08-12 16:48:02 +0200 | [diff] [blame] | 463 | CHECK (!cNoiseBuffer[0] || !cNoiseBuffer[1] || !cNoiseBuffer[2] || !cNoiseBuffer[3] || !cNoiseBuffer[4] || | 
| Yann Collet | 58d5dfe | 2016-09-25 01:34:03 +0200 | [diff] [blame] | 464 | !copyBuffer || !dstBuffer || !cBuffer || !zc || !zd || !zd_noise , | 
| Yann Collet | d7883a2 | 2016-08-12 16:48:02 +0200 | [diff] [blame] | 465 | "Not enough memory, fuzzer tests cancelled"); | 
|  | 466 |  | 
|  | 467 | /* Create initial samples */ | 
|  | 468 | RDG_genBuffer(cNoiseBuffer[0], srcBufferSize, 0.00, 0., coreSeed);    /* pure noise */ | 
|  | 469 | RDG_genBuffer(cNoiseBuffer[1], srcBufferSize, 0.05, 0., coreSeed);    /* barely compressible */ | 
|  | 470 | RDG_genBuffer(cNoiseBuffer[2], srcBufferSize, compressibility, 0., coreSeed); | 
|  | 471 | RDG_genBuffer(cNoiseBuffer[3], srcBufferSize, 0.95, 0., coreSeed);    /* highly compressible */ | 
|  | 472 | RDG_genBuffer(cNoiseBuffer[4], srcBufferSize, 1.00, 0., coreSeed);    /* sparse content */ | 
|  | 473 | memset(copyBuffer, 0x65, copyBufferSize);                             /* make copyBuffer considered initialized */ | 
| Yann Collet | 58d5dfe | 2016-09-25 01:34:03 +0200 | [diff] [blame] | 474 | ZSTD_initDStream_usingDict(zd, NULL, 0);  /* ensure at least one init */ | 
| Yann Collet | d7883a2 | 2016-08-12 16:48:02 +0200 | [diff] [blame] | 475 |  | 
|  | 476 | /* catch up testNb */ | 
|  | 477 | for (testNb=1; testNb < startTest; testNb++) | 
|  | 478 | FUZ_rand(&coreSeed); | 
|  | 479 |  | 
|  | 480 | /* test loop */ | 
| Yann Collet | ef9999f | 2016-09-01 16:44:48 -0700 | [diff] [blame] | 481 | for ( ; (testNb <= nbTests) || (FUZ_GetClockSpan(startClock) < g_clockTime) ; testNb++ ) { | 
| Yann Collet | d7883a2 | 2016-08-12 16:48:02 +0200 | [diff] [blame] | 482 | U32 lseed; | 
|  | 483 | const BYTE* srcBuffer; | 
| Yann Collet | 58d5dfe | 2016-09-25 01:34:03 +0200 | [diff] [blame] | 484 | size_t totalTestSize, totalGenSize, cSize; | 
| Yann Collet | d7883a2 | 2016-08-12 16:48:02 +0200 | [diff] [blame] | 485 | XXH64_state_t xxhState; | 
|  | 486 | U64 crcOrig; | 
| Yann Collet | 58d5dfe | 2016-09-25 01:34:03 +0200 | [diff] [blame] | 487 | U32 resetAllowed = 1; | 
| Yann Collet | cf409a7 | 2016-09-26 16:41:05 +0200 | [diff] [blame] | 488 | size_t maxTestSize; | 
| Yann Collet | d7883a2 | 2016-08-12 16:48:02 +0200 | [diff] [blame] | 489 |  | 
|  | 490 | /* init */ | 
| Yann Collet | 4c0b44f | 2016-11-01 11:13:22 -0700 | [diff] [blame] | 491 | if (nbTests >= testNb) { DISPLAYUPDATE(2, "\r%6u/%6u    ", testNb, nbTests); } | 
|  | 492 | else { DISPLAYUPDATE(2, "\r%6u          ", testNb); } | 
| Yann Collet | d7883a2 | 2016-08-12 16:48:02 +0200 | [diff] [blame] | 493 | FUZ_rand(&coreSeed); | 
|  | 494 | lseed = coreSeed ^ prime1; | 
|  | 495 |  | 
| Yann Collet | 3ecbe6a | 2016-09-14 17:26:59 +0200 | [diff] [blame] | 496 | /* states full reset (deliberately not synchronized) */ | 
|  | 497 | /* some issues can only happen when reusing states */ | 
| Yann Collet | 58d5dfe | 2016-09-25 01:34:03 +0200 | [diff] [blame] | 498 | if ((FUZ_rand(&lseed) & 0xFF) == 131) { ZSTD_freeCStream(zc); zc = ZSTD_createCStream(); resetAllowed=0; } | 
|  | 499 | if ((FUZ_rand(&lseed) & 0xFF) == 132) { ZSTD_freeDStream(zd); zd = ZSTD_createDStream(); ZSTD_initDStream_usingDict(zd, NULL, 0);  /* ensure at least one init */ } | 
| Yann Collet | d7883a2 | 2016-08-12 16:48:02 +0200 | [diff] [blame] | 500 |  | 
|  | 501 | /* srcBuffer selection [0-4] */ | 
|  | 502 | {   U32 buffNb = FUZ_rand(&lseed) & 0x7F; | 
|  | 503 | if (buffNb & 7) buffNb=2;   /* most common : compressible (P) */ | 
|  | 504 | else { | 
|  | 505 | buffNb >>= 3; | 
|  | 506 | if (buffNb & 7) { | 
|  | 507 | const U32 tnb[2] = { 1, 3 };   /* barely/highly compressible */ | 
|  | 508 | buffNb = tnb[buffNb >> 3]; | 
|  | 509 | } else { | 
|  | 510 | const U32 tnb[2] = { 0, 4 };   /* not compressible / sparse */ | 
|  | 511 | buffNb = tnb[buffNb >> 3]; | 
|  | 512 | }   } | 
|  | 513 | srcBuffer = cNoiseBuffer[buffNb]; | 
|  | 514 | } | 
|  | 515 |  | 
|  | 516 | /* compression init */ | 
| Yann Collet | cf409a7 | 2016-09-26 16:41:05 +0200 | [diff] [blame] | 517 | if ((FUZ_rand(&lseed)&1) /* at beginning, to keep same nb of rand */ | 
|  | 518 | && oldTestLog /* at least one test happened */ && resetAllowed) { | 
|  | 519 | maxTestSize = FUZ_randomLength(&lseed, oldTestLog+2); | 
|  | 520 | if (maxTestSize >= srcBufferSize) maxTestSize = srcBufferSize-1; | 
|  | 521 | {   U64 const pledgedSrcSize = (FUZ_rand(&lseed) & 3) ? 0 : maxTestSize; | 
|  | 522 | size_t const resetError = ZSTD_resetCStream(zc, pledgedSrcSize); | 
|  | 523 | CHECK(ZSTD_isError(resetError), "ZSTD_resetCStream error : %s", ZSTD_getErrorName(resetError)); | 
|  | 524 | } | 
| Yann Collet | 58d5dfe | 2016-09-25 01:34:03 +0200 | [diff] [blame] | 525 | } else { | 
|  | 526 | U32 const testLog = FUZ_rand(&lseed) % maxSrcLog; | 
| Yann Collet | d7883a2 | 2016-08-12 16:48:02 +0200 | [diff] [blame] | 527 | U32 const cLevel = (FUZ_rand(&lseed) % (ZSTD_maxCLevel() - (testLog/3))) + 1; | 
|  | 528 | maxTestSize = FUZ_rLogLength(&lseed, testLog); | 
| Yann Collet | cf409a7 | 2016-09-26 16:41:05 +0200 | [diff] [blame] | 529 | oldTestLog = testLog; | 
| Yann Collet | d7883a2 | 2016-08-12 16:48:02 +0200 | [diff] [blame] | 530 | /* random dictionary selection */ | 
| Yann Collet | 58d5dfe | 2016-09-25 01:34:03 +0200 | [diff] [blame] | 531 | dictSize  = ((FUZ_rand(&lseed)&63)==1) ? FUZ_randomLength(&lseed, maxSampleLog) : 0; | 
| Yann Collet | d7883a2 | 2016-08-12 16:48:02 +0200 | [diff] [blame] | 532 | {   size_t const dictStart = FUZ_rand(&lseed) % (srcBufferSize - dictSize); | 
|  | 533 | dict = srcBuffer + dictStart; | 
|  | 534 | } | 
| Yann Collet | cf409a7 | 2016-09-26 16:41:05 +0200 | [diff] [blame] | 535 | {   U64 const pledgedSrcSize = (FUZ_rand(&lseed) & 3) ? 0 : maxTestSize; | 
|  | 536 | ZSTD_parameters params = ZSTD_getParams(cLevel, pledgedSrcSize, dictSize); | 
| Yann Collet | d7883a2 | 2016-08-12 16:48:02 +0200 | [diff] [blame] | 537 | params.fParams.checksumFlag = FUZ_rand(&lseed) & 1; | 
|  | 538 | params.fParams.noDictIDFlag = FUZ_rand(&lseed) & 1; | 
| Yann Collet | cf409a7 | 2016-09-26 16:41:05 +0200 | [diff] [blame] | 539 | {   size_t const initError = ZSTD_initCStream_advanced(zc, dict, dictSize, params, pledgedSrcSize); | 
| Yann Collet | b3060f7 | 2016-09-09 16:44:16 +0200 | [diff] [blame] | 540 | CHECK (ZSTD_isError(initError),"ZSTD_initCStream_advanced error : %s", ZSTD_getErrorName(initError)); | 
| Yann Collet | d7883a2 | 2016-08-12 16:48:02 +0200 | [diff] [blame] | 541 | }   }   } | 
|  | 542 |  | 
|  | 543 | /* multi-segments compression test */ | 
|  | 544 | XXH64_reset(&xxhState, 0); | 
| Yann Collet | 2f26394 | 2016-09-26 14:06:08 +0200 | [diff] [blame] | 545 | {   ZSTD_outBuffer outBuff = { cBuffer, cBufferSize, 0 } ; | 
| Yann Collet | 58d5dfe | 2016-09-25 01:34:03 +0200 | [diff] [blame] | 546 | U32 n; | 
| Yann Collet | 2f26394 | 2016-09-26 14:06:08 +0200 | [diff] [blame] | 547 | for (n=0, cSize=0, totalTestSize=0 ; totalTestSize < maxTestSize ; n++) { | 
| Yann Collet | e795c8a | 2016-12-13 16:39:36 +0100 | [diff] [blame] | 548 | /* compress random chunks into randomly sized dst buffers */ | 
| Yann Collet | 2f26394 | 2016-09-26 14:06:08 +0200 | [diff] [blame] | 549 | {   size_t const randomSrcSize = FUZ_randomLength(&lseed, maxSampleLog); | 
|  | 550 | size_t const srcSize = MIN (maxTestSize-totalTestSize, randomSrcSize); | 
|  | 551 | size_t const srcStart = FUZ_rand(&lseed) % (srcBufferSize - srcSize); | 
| Yann Collet | d7883a2 | 2016-08-12 16:48:02 +0200 | [diff] [blame] | 552 | size_t const randomDstSize = FUZ_randomLength(&lseed, maxSampleLog); | 
|  | 553 | size_t const dstBuffSize = MIN(cBufferSize - cSize, randomDstSize); | 
| Yann Collet | 2f26394 | 2016-09-26 14:06:08 +0200 | [diff] [blame] | 554 | ZSTD_inBuffer inBuff = { srcBuffer+srcStart, srcSize, 0 }; | 
| Yann Collet | 53e17fb | 2016-08-17 01:39:22 +0200 | [diff] [blame] | 555 | outBuff.size = outBuff.pos + dstBuffSize; | 
| Yann Collet | d7883a2 | 2016-08-12 16:48:02 +0200 | [diff] [blame] | 556 |  | 
| Yann Collet | 53e17fb | 2016-08-17 01:39:22 +0200 | [diff] [blame] | 557 | { size_t const compressionError = ZSTD_compressStream(zc, &outBuff, &inBuff); | 
| Yann Collet | d7883a2 | 2016-08-12 16:48:02 +0200 | [diff] [blame] | 558 | CHECK (ZSTD_isError(compressionError), "compression error : %s", ZSTD_getErrorName(compressionError)); } | 
| Yann Collet | d7883a2 | 2016-08-12 16:48:02 +0200 | [diff] [blame] | 559 |  | 
| Yann Collet | 53e17fb | 2016-08-17 01:39:22 +0200 | [diff] [blame] | 560 | XXH64_update(&xxhState, srcBuffer+srcStart, inBuff.pos); | 
|  | 561 | memcpy(copyBuffer+totalTestSize, srcBuffer+srcStart, inBuff.pos); | 
|  | 562 | totalTestSize += inBuff.pos; | 
| Yann Collet | d7883a2 | 2016-08-12 16:48:02 +0200 | [diff] [blame] | 563 | } | 
|  | 564 |  | 
|  | 565 | /* random flush operation, to mess around */ | 
|  | 566 | if ((FUZ_rand(&lseed) & 15) == 0) { | 
|  | 567 | size_t const randomDstSize = FUZ_randomLength(&lseed, maxSampleLog); | 
| Yann Collet | 53e17fb | 2016-08-17 01:39:22 +0200 | [diff] [blame] | 568 | size_t const adjustedDstSize = MIN(cBufferSize - cSize, randomDstSize); | 
|  | 569 | outBuff.size = outBuff.pos + adjustedDstSize; | 
|  | 570 | {   size_t const flushError = ZSTD_flushStream(zc, &outBuff); | 
| Yann Collet | d7883a2 | 2016-08-12 16:48:02 +0200 | [diff] [blame] | 571 | CHECK (ZSTD_isError(flushError), "flush error : %s", ZSTD_getErrorName(flushError)); | 
|  | 572 | }   }   } | 
|  | 573 |  | 
|  | 574 | /* final frame epilogue */ | 
|  | 575 | {   size_t remainingToFlush = (size_t)(-1); | 
|  | 576 | while (remainingToFlush) { | 
|  | 577 | size_t const randomDstSize = FUZ_randomLength(&lseed, maxSampleLog); | 
|  | 578 | size_t const adjustedDstSize = MIN(cBufferSize - cSize, randomDstSize); | 
|  | 579 | U32 const enoughDstSize = (adjustedDstSize >= remainingToFlush); | 
| Yann Collet | 53e17fb | 2016-08-17 01:39:22 +0200 | [diff] [blame] | 580 | outBuff.size = outBuff.pos + adjustedDstSize; | 
|  | 581 | remainingToFlush = ZSTD_endStream(zc, &outBuff); | 
| Yann Collet | d7883a2 | 2016-08-12 16:48:02 +0200 | [diff] [blame] | 582 | CHECK (ZSTD_isError(remainingToFlush), "flush error : %s", ZSTD_getErrorName(remainingToFlush)); | 
|  | 583 | CHECK (enoughDstSize && remainingToFlush, "ZSTD_endStream() not fully flushed (%u remaining), but enough space available", (U32)remainingToFlush); | 
|  | 584 | }   } | 
|  | 585 | crcOrig = XXH64_digest(&xxhState); | 
| Yann Collet | 53e17fb | 2016-08-17 01:39:22 +0200 | [diff] [blame] | 586 | cSize = outBuff.pos; | 
| Yann Collet | d7883a2 | 2016-08-12 16:48:02 +0200 | [diff] [blame] | 587 | } | 
|  | 588 |  | 
|  | 589 | /* multi - fragments decompression test */ | 
| Yann Collet | 58d5dfe | 2016-09-25 01:34:03 +0200 | [diff] [blame] | 590 | if (!dictSize /* don't reset if dictionary : could be different */ && (FUZ_rand(&lseed) & 1)) { | 
| Yann Collet | 9516234 | 2016-10-25 16:19:52 -0700 | [diff] [blame] | 591 | CHECK (ZSTD_isError(ZSTD_resetDStream(zd)), "ZSTD_resetDStream failed"); | 
| Yann Collet | 9ffbeea | 2016-12-02 18:37:38 -0800 | [diff] [blame] | 592 | } else { | 
| Yann Collet | 58d5dfe | 2016-09-25 01:34:03 +0200 | [diff] [blame] | 593 | ZSTD_initDStream_usingDict(zd, dict, dictSize); | 
| Yann Collet | 9ffbeea | 2016-12-02 18:37:38 -0800 | [diff] [blame] | 594 | } | 
| Yann Collet | d7883a2 | 2016-08-12 16:48:02 +0200 | [diff] [blame] | 595 | {   size_t decompressionResult = 1; | 
| Yann Collet | 53e17fb | 2016-08-17 01:39:22 +0200 | [diff] [blame] | 596 | ZSTD_inBuffer  inBuff = { cBuffer, cSize, 0 }; | 
|  | 597 | ZSTD_outBuffer outBuff= { dstBuffer, dstBufferSize, 0 }; | 
|  | 598 | for (totalGenSize = 0 ; decompressionResult ; ) { | 
| Yann Collet | d7883a2 | 2016-08-12 16:48:02 +0200 | [diff] [blame] | 599 | size_t const readCSrcSize = FUZ_randomLength(&lseed, maxSampleLog); | 
|  | 600 | size_t const randomDstSize = FUZ_randomLength(&lseed, maxSampleLog); | 
|  | 601 | size_t const dstBuffSize = MIN(dstBufferSize - totalGenSize, randomDstSize); | 
| Yann Collet | 53e17fb | 2016-08-17 01:39:22 +0200 | [diff] [blame] | 602 | inBuff.size = inBuff.pos + readCSrcSize; | 
|  | 603 | outBuff.size = inBuff.pos + dstBuffSize; | 
|  | 604 | decompressionResult = ZSTD_decompressStream(zd, &outBuff, &inBuff); | 
| Yann Collet | d7883a2 | 2016-08-12 16:48:02 +0200 | [diff] [blame] | 605 | CHECK (ZSTD_isError(decompressionResult), "decompression error : %s", ZSTD_getErrorName(decompressionResult)); | 
| Yann Collet | d7883a2 | 2016-08-12 16:48:02 +0200 | [diff] [blame] | 606 | } | 
|  | 607 | CHECK (decompressionResult != 0, "frame not fully decoded"); | 
| Yann Collet | 53e17fb | 2016-08-17 01:39:22 +0200 | [diff] [blame] | 608 | CHECK (outBuff.pos != totalTestSize, "decompressed data : wrong size") | 
|  | 609 | CHECK (inBuff.pos != cSize, "compressed data should be fully read") | 
| Yann Collet | d7883a2 | 2016-08-12 16:48:02 +0200 | [diff] [blame] | 610 | {   U64 const crcDest = XXH64(dstBuffer, totalTestSize, 0); | 
|  | 611 | if (crcDest!=crcOrig) findDiff(copyBuffer, dstBuffer, totalTestSize); | 
|  | 612 | CHECK (crcDest!=crcOrig, "decompressed data corrupted"); | 
|  | 613 | }   } | 
|  | 614 |  | 
|  | 615 | /*=====   noisy/erroneous src decompression test   =====*/ | 
|  | 616 |  | 
|  | 617 | /* add some noise */ | 
|  | 618 | {   U32 const nbNoiseChunks = (FUZ_rand(&lseed) & 7) + 2; | 
|  | 619 | U32 nn; for (nn=0; nn<nbNoiseChunks; nn++) { | 
|  | 620 | size_t const randomNoiseSize = FUZ_randomLength(&lseed, maxSampleLog); | 
|  | 621 | size_t const noiseSize  = MIN((cSize/3) , randomNoiseSize); | 
|  | 622 | size_t const noiseStart = FUZ_rand(&lseed) % (srcBufferSize - noiseSize); | 
|  | 623 | size_t const cStart = FUZ_rand(&lseed) % (cSize - noiseSize); | 
|  | 624 | memcpy(cBuffer+cStart, srcBuffer+noiseStart, noiseSize); | 
|  | 625 | }   } | 
|  | 626 |  | 
|  | 627 | /* try decompression on noisy data */ | 
| Yann Collet | 58d5dfe | 2016-09-25 01:34:03 +0200 | [diff] [blame] | 628 | ZSTD_initDStream(zd_noise);   /* note : no dictionary */ | 
| Yann Collet | 53e17fb | 2016-08-17 01:39:22 +0200 | [diff] [blame] | 629 | {   ZSTD_inBuffer  inBuff = { cBuffer, cSize, 0 }; | 
|  | 630 | ZSTD_outBuffer outBuff= { dstBuffer, dstBufferSize, 0 }; | 
|  | 631 | while (outBuff.pos < dstBufferSize) { | 
| Yann Collet | d7883a2 | 2016-08-12 16:48:02 +0200 | [diff] [blame] | 632 | size_t const randomCSrcSize = FUZ_randomLength(&lseed, maxSampleLog); | 
|  | 633 | size_t const randomDstSize = FUZ_randomLength(&lseed, maxSampleLog); | 
| Yann Collet | 53e17fb | 2016-08-17 01:39:22 +0200 | [diff] [blame] | 634 | size_t const adjustedDstSize = MIN(dstBufferSize - outBuff.pos, randomDstSize); | 
|  | 635 | outBuff.size = outBuff.pos + adjustedDstSize; | 
|  | 636 | inBuff.size  = inBuff.pos + randomCSrcSize; | 
|  | 637 | {   size_t const decompressError = ZSTD_decompressStream(zd, &outBuff, &inBuff); | 
| Yann Collet | d7883a2 | 2016-08-12 16:48:02 +0200 | [diff] [blame] | 638 | if (ZSTD_isError(decompressError)) break;   /* error correctly detected */ | 
|  | 639 | }   }   }   } | 
|  | 640 | DISPLAY("\r%u fuzzer tests completed   \n", testNb); | 
|  | 641 |  | 
|  | 642 | _cleanup: | 
|  | 643 | ZSTD_freeCStream(zc); | 
|  | 644 | ZSTD_freeDStream(zd); | 
| Yann Collet | 58d5dfe | 2016-09-25 01:34:03 +0200 | [diff] [blame] | 645 | ZSTD_freeDStream(zd_noise); | 
| Yann Collet | d7883a2 | 2016-08-12 16:48:02 +0200 | [diff] [blame] | 646 | free(cNoiseBuffer[0]); | 
|  | 647 | free(cNoiseBuffer[1]); | 
|  | 648 | free(cNoiseBuffer[2]); | 
|  | 649 | free(cNoiseBuffer[3]); | 
|  | 650 | free(cNoiseBuffer[4]); | 
|  | 651 | free(copyBuffer); | 
|  | 652 | free(cBuffer); | 
|  | 653 | free(dstBuffer); | 
|  | 654 | return result; | 
|  | 655 |  | 
|  | 656 | _output_error: | 
|  | 657 | result = 1; | 
|  | 658 | goto _cleanup; | 
|  | 659 | } | 
|  | 660 |  | 
|  | 661 |  | 
|  | 662 | /*-******************************************************* | 
|  | 663 | *  Command line | 
|  | 664 | *********************************************************/ | 
|  | 665 | int FUZ_usage(const char* programName) | 
|  | 666 | { | 
|  | 667 | DISPLAY( "Usage :\n"); | 
|  | 668 | DISPLAY( "      %s [args]\n", programName); | 
|  | 669 | DISPLAY( "\n"); | 
|  | 670 | DISPLAY( "Arguments :\n"); | 
|  | 671 | DISPLAY( " -i#    : Nb of tests (default:%u) \n", nbTestsDefault); | 
|  | 672 | DISPLAY( " -s#    : Select seed (default:prompt user)\n"); | 
|  | 673 | DISPLAY( " -t#    : Select starting test number (default:0)\n"); | 
|  | 674 | DISPLAY( " -P#    : Select compressibility in %% (default:%i%%)\n", FUZ_COMPRESSIBILITY_DEFAULT); | 
|  | 675 | DISPLAY( " -v     : verbose\n"); | 
|  | 676 | DISPLAY( " -p     : pause at the end\n"); | 
|  | 677 | DISPLAY( " -h     : display help and exit\n"); | 
|  | 678 | return 0; | 
|  | 679 | } | 
|  | 680 |  | 
|  | 681 |  | 
|  | 682 | int main(int argc, const char** argv) | 
|  | 683 | { | 
|  | 684 | U32 seed=0; | 
|  | 685 | int seedset=0; | 
|  | 686 | int argNb; | 
|  | 687 | int nbTests = nbTestsDefault; | 
|  | 688 | int testNb = 0; | 
|  | 689 | int proba = FUZ_COMPRESSIBILITY_DEFAULT; | 
|  | 690 | int result=0; | 
|  | 691 | U32 mainPause = 0; | 
|  | 692 | const char* programName = argv[0]; | 
|  | 693 | ZSTD_customMem customMem = { allocFunction, freeFunction, NULL }; | 
|  | 694 | ZSTD_customMem customNULL = { NULL, NULL, NULL }; | 
|  | 695 |  | 
|  | 696 | /* Check command line */ | 
|  | 697 | for(argNb=1; argNb<argc; argNb++) { | 
|  | 698 | const char* argument = argv[argNb]; | 
|  | 699 | if(!argument) continue;   /* Protection if argument empty */ | 
|  | 700 |  | 
|  | 701 | /* Parsing commands. Aggregated commands are allowed */ | 
|  | 702 | if (argument[0]=='-') { | 
|  | 703 | argument++; | 
|  | 704 |  | 
|  | 705 | while (*argument!=0) { | 
|  | 706 | switch(*argument) | 
|  | 707 | { | 
|  | 708 | case 'h': | 
|  | 709 | return FUZ_usage(programName); | 
|  | 710 | case 'v': | 
|  | 711 | argument++; | 
|  | 712 | g_displayLevel=4; | 
|  | 713 | break; | 
|  | 714 | case 'q': | 
|  | 715 | argument++; | 
|  | 716 | g_displayLevel--; | 
|  | 717 | break; | 
|  | 718 | case 'p': /* pause at the end */ | 
|  | 719 | argument++; | 
|  | 720 | mainPause = 1; | 
|  | 721 | break; | 
|  | 722 |  | 
|  | 723 | case 'i': | 
|  | 724 | argument++; | 
| Yann Collet | ef9999f | 2016-09-01 16:44:48 -0700 | [diff] [blame] | 725 | nbTests=0; g_clockTime=0; | 
| Yann Collet | d7883a2 | 2016-08-12 16:48:02 +0200 | [diff] [blame] | 726 | while ((*argument>='0') && (*argument<='9')) { | 
|  | 727 | nbTests *= 10; | 
|  | 728 | nbTests += *argument - '0'; | 
|  | 729 | argument++; | 
|  | 730 | } | 
|  | 731 | break; | 
|  | 732 |  | 
|  | 733 | case 'T': | 
|  | 734 | argument++; | 
| Yann Collet | ef9999f | 2016-09-01 16:44:48 -0700 | [diff] [blame] | 735 | nbTests=0; g_clockTime=0; | 
| Yann Collet | d7883a2 | 2016-08-12 16:48:02 +0200 | [diff] [blame] | 736 | while ((*argument>='0') && (*argument<='9')) { | 
| Yann Collet | ef9999f | 2016-09-01 16:44:48 -0700 | [diff] [blame] | 737 | g_clockTime *= 10; | 
|  | 738 | g_clockTime += *argument - '0'; | 
| Yann Collet | d7883a2 | 2016-08-12 16:48:02 +0200 | [diff] [blame] | 739 | argument++; | 
|  | 740 | } | 
| Yann Collet | ef9999f | 2016-09-01 16:44:48 -0700 | [diff] [blame] | 741 | if (*argument=='m') g_clockTime *=60, argument++; | 
| Yann Collet | d7883a2 | 2016-08-12 16:48:02 +0200 | [diff] [blame] | 742 | if (*argument=='n') argument++; | 
| Yann Collet | ef9999f | 2016-09-01 16:44:48 -0700 | [diff] [blame] | 743 | g_clockTime *= CLOCKS_PER_SEC; | 
| Yann Collet | d7883a2 | 2016-08-12 16:48:02 +0200 | [diff] [blame] | 744 | break; | 
|  | 745 |  | 
|  | 746 | case 's': | 
|  | 747 | argument++; | 
|  | 748 | seed=0; | 
|  | 749 | seedset=1; | 
|  | 750 | while ((*argument>='0') && (*argument<='9')) { | 
|  | 751 | seed *= 10; | 
|  | 752 | seed += *argument - '0'; | 
|  | 753 | argument++; | 
|  | 754 | } | 
|  | 755 | break; | 
|  | 756 |  | 
|  | 757 | case 't': | 
|  | 758 | argument++; | 
|  | 759 | testNb=0; | 
|  | 760 | while ((*argument>='0') && (*argument<='9')) { | 
|  | 761 | testNb *= 10; | 
|  | 762 | testNb += *argument - '0'; | 
|  | 763 | argument++; | 
|  | 764 | } | 
|  | 765 | break; | 
|  | 766 |  | 
|  | 767 | case 'P':   /* compressibility % */ | 
|  | 768 | argument++; | 
|  | 769 | proba=0; | 
|  | 770 | while ((*argument>='0') && (*argument<='9')) { | 
|  | 771 | proba *= 10; | 
|  | 772 | proba += *argument - '0'; | 
|  | 773 | argument++; | 
|  | 774 | } | 
|  | 775 | if (proba<0) proba=0; | 
|  | 776 | if (proba>100) proba=100; | 
|  | 777 | break; | 
|  | 778 |  | 
|  | 779 | default: | 
|  | 780 | return FUZ_usage(programName); | 
|  | 781 | } | 
|  | 782 | }   }   }   /* for(argNb=1; argNb<argc; argNb++) */ | 
|  | 783 |  | 
|  | 784 | /* Get Seed */ | 
| Yann Collet | bb85581 | 2016-08-25 19:11:11 +0200 | [diff] [blame] | 785 | DISPLAY("Starting zstream tester (%i-bits, %s)\n", (int)(sizeof(size_t)*8), ZSTD_VERSION_STRING); | 
| Yann Collet | d7883a2 | 2016-08-12 16:48:02 +0200 | [diff] [blame] | 786 |  | 
| Yann Collet | ef9999f | 2016-09-01 16:44:48 -0700 | [diff] [blame] | 787 | if (!seedset) { | 
|  | 788 | time_t const t = time(NULL); | 
|  | 789 | U32 const h = XXH32(&t, sizeof(t), 1); | 
|  | 790 | seed = h % 10000; | 
|  | 791 | } | 
|  | 792 |  | 
| Yann Collet | d7883a2 | 2016-08-12 16:48:02 +0200 | [diff] [blame] | 793 | DISPLAY("Seed = %u\n", seed); | 
|  | 794 | if (proba!=FUZ_COMPRESSIBILITY_DEFAULT) DISPLAY("Compressibility : %i%%\n", proba); | 
|  | 795 |  | 
|  | 796 | if (nbTests<=0) nbTests=1; | 
|  | 797 |  | 
|  | 798 | if (testNb==0) { | 
|  | 799 | result = basicUnitTests(0, ((double)proba) / 100, customNULL);  /* constant seed for predictability */ | 
|  | 800 | if (!result) { | 
|  | 801 | DISPLAYLEVEL(4, "Unit tests using customMem :\n") | 
|  | 802 | result = basicUnitTests(0, ((double)proba) / 100, customMem);  /* use custom memory allocation functions */ | 
|  | 803 | }   } | 
|  | 804 |  | 
|  | 805 | if (!result) | 
|  | 806 | result = fuzzerTests(seed, nbTests, testNb, ((double)proba) / 100); | 
|  | 807 |  | 
|  | 808 | if (mainPause) { | 
|  | 809 | int unused; | 
|  | 810 | DISPLAY("Press Enter \n"); | 
|  | 811 | unused = getchar(); | 
|  | 812 | (void)unused; | 
|  | 813 | } | 
|  | 814 | return result; | 
|  | 815 | } |