lz4

Форк
0
/
frametest.c 
1483 строки · 65.6 Кб
1
/*
2
    frameTest - test tool for lz4frame
3
    Copyright (C) Yann Collet 2014-2020
4

5
    GPL v2 License
6

7
    This program is free software; you can redistribute it and/or modify
8
    it under the terms of the GNU General Public License as published by
9
    the Free Software Foundation; either version 2 of the License, or
10
    (at your option) any later version.
11

12
    This program is distributed in the hope that it will be useful,
13
    but WITHOUT ANY WARRANTY; without even the implied warranty of
14
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15
    GNU General Public License for more details.
16

17
    You should have received a copy of the GNU General Public License along
18
    with this program; if not, write to the Free Software Foundation, Inc.,
19
    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20

21
    You can contact the author at :
22
    - LZ4 homepage : http://www.lz4.org
23
    - LZ4 source repository : https://github.com/lz4/lz4
24
*/
25

26
/*-************************************
27
*  Compiler specific
28
**************************************/
29
#ifdef _MSC_VER    /* Visual Studio */
30
#  pragma warning(disable : 26451)     /* disable: Arithmetic overflow */
31
#  pragma warning(disable : 4127)    /* disable: C4127: conditional expression is constant */
32
#endif
33

34

35
/*-************************************
36
*  Includes
37
**************************************/
38
#include "util.h"       /* U32 */
39
#include <stdlib.h>     /* malloc, free */
40
#include <stdio.h>      /* fprintf */
41
#include <string.h>     /* strcmp */
42
#include <time.h>       /* clock_t, clock(), CLOCKS_PER_SEC */
43
#include <assert.h>
44
#include "lz4frame.h"   /* included multiple times to test correctness/safety */
45
#include "lz4frame.h"
46
#define LZ4F_STATIC_LINKING_ONLY
47
#include "lz4frame.h"
48
#include "lz4frame.h"
49
#define LZ4_STATIC_LINKING_ONLY  /* LZ4_DISTANCE_MAX */
50
#include "lz4.h"        /* LZ4_VERSION_STRING */
51
#define XXH_STATIC_LINKING_ONLY
52
#include "xxhash.h"     /* XXH64 */
53

54

55
/* unoptimized version; solves endianness & alignment issues */
56
static void FUZ_writeLE32 (void* dstVoidPtr, U32 value32)
57
{
58
    BYTE* const dstPtr = (BYTE*)dstVoidPtr;
59
    dstPtr[0] = (BYTE) value32;
60
    dstPtr[1] = (BYTE)(value32 >> 8);
61
    dstPtr[2] = (BYTE)(value32 >> 16);
62
    dstPtr[3] = (BYTE)(value32 >> 24);
63
}
64

65

66
/*-************************************
67
*  Constants
68
**************************************/
69
#define KB *(1U<<10)
70
#define MB *(1U<<20)
71
#define GB *(1U<<30)
72

73
static const U32 nbTestsDefault = 256 KB;
74
#define FUZ_COMPRESSIBILITY_DEFAULT 50
75
static const U32 prime1 = 2654435761U;
76
static const U32 prime2 = 2246822519U;
77

78

79
/*-************************************
80
*  Macros
81
**************************************/
82
#define DISPLAY(...)          fprintf(stderr, __VA_ARGS__)
83
#define DISPLAYLEVEL(l, ...)  do { if (displayLevel>=(l)) DISPLAY(__VA_ARGS__); } while (0)
84
#define DISPLAYUPDATE(l, ...) do { if (displayLevel>=(l)) { \
85
            if ((FUZ_GetClockSpan(g_clockTime) > refreshRate) || (displayLevel>=4)) \
86
            { g_clockTime = clock(); DISPLAY(__VA_ARGS__); \
87
            if (displayLevel>=4) fflush(stdout); } } } while (0)
88
static const clock_t refreshRate = CLOCKS_PER_SEC / 6;
89
static clock_t g_clockTime = 0;
90

91

92
/*-***************************************
93
*  Local Parameters
94
*****************************************/
95
static U32 no_prompt = 0;
96
static U32 displayLevel = 2;
97
static U32 use_pause = 0;
98

99

100
/*-*******************************************************
101
*  Fuzzer functions
102
*********************************************************/
103
#define MIN(a,b)  ( (a) < (b) ? (a) : (b) )
104
#define MAX(a,b)  ( (a) > (b) ? (a) : (b) )
105

106
typedef struct {
107
    int nbAllocs;
108
} Test_alloc_state;
109
static Test_alloc_state g_testAllocState = { 0 };
110

111
static void* dummy_malloc(void* state, size_t s)
112
{
113
    Test_alloc_state* const t = (Test_alloc_state*)state;
114
    void* const p = malloc(s);
115
    if (p==NULL) return NULL;
116
    assert(t != NULL);
117
    t->nbAllocs += 1;
118
    DISPLAYLEVEL(6, "Allocating %u bytes at address %p \n", (unsigned)s, p);
119
    DISPLAYLEVEL(5, "nb allocated memory segments : %i \n", t->nbAllocs);
120
    return p;
121
}
122

123
static void* dummy_calloc(void* state, size_t s)
124
{
125
    Test_alloc_state* const t = (Test_alloc_state*)state;
126
    void* const p = calloc(1, s);
127
    if (p==NULL) return NULL;
128
    assert(t != NULL);
129
    t->nbAllocs += 1;
130
    DISPLAYLEVEL(6, "Allocating and zeroing %u bytes at address %p \n", (unsigned)s, p);
131
    DISPLAYLEVEL(5, "nb allocated memory segments : %i \n", t->nbAllocs);
132
    return p;
133
}
134

135
static void dummy_free(void* state, void* p)
136
{
137
    Test_alloc_state* const t = (Test_alloc_state*)state;
138
    if (p==NULL) {
139
        DISPLAYLEVEL(5, "free() on NULL \n");
140
        return;
141
    }
142
    DISPLAYLEVEL(6, "freeing memory at address %p \n", p);
143
    free(p);
144
    assert(t != NULL);
145
    t->nbAllocs -= 1;
146
    DISPLAYLEVEL(5, "nb of allocated memory segments after this free : %i \n", t->nbAllocs);
147
    assert(t->nbAllocs >= 0);
148
}
149

150
static const LZ4F_CustomMem lz4f_cmem_test = {
151
    dummy_malloc,
152
    dummy_calloc,
153
    dummy_free,
154
    &g_testAllocState
155
};
156

157

158
static clock_t FUZ_GetClockSpan(clock_t clockStart)
159
{
160
    return clock() - clockStart;   /* works even if overflow; max span ~ 30 mn */
161
}
162

163
#define FUZ_rotl32(x,r) ((x << r) | (x >> (32 - r)))
164
unsigned int FUZ_rand(unsigned int* src)
165
{
166
    U32 rand32 = *src;
167
    rand32 *= prime1;
168
    rand32 += prime2;
169
    rand32  = FUZ_rotl32(rand32, 13);
170
    *src = rand32;
171
    return rand32 >> 5;
172
}
173

174
#define RAND_BITS(N) (FUZ_rand(randState) & ((1 << (N))-1))
175
#define FUZ_LITERAL (RAND_BITS(6) + '0')
176
#define FUZ_ABOUT(_R) ((FUZ_rand(randState) % (_R)) + (FUZ_rand(randState) % (_R)) + 1)
177
static void FUZ_fillCompressibleNoiseBuffer(void* buffer, size_t bufferSize, double proba, U32* randState)
178
{
179
    BYTE* BBuffer = (BYTE*)buffer;
180
    size_t pos = 0;
181
    U32 P32 = (U32)(32768 * proba);
182

183
    /* First Byte */
184
    BBuffer[pos++] = FUZ_LITERAL;
185

186
    while (pos < bufferSize) {
187
        /* Select : Literal (noise) or copy (within 64K) */
188
        if (RAND_BITS(15) < P32) {
189
            /* Copy (within 64K) */
190
            size_t const lengthRand = FUZ_ABOUT(8) + 4;
191
            size_t const length = MIN(lengthRand, bufferSize - pos);
192
            size_t const end = pos + length;
193
            size_t const offsetRand = RAND_BITS(15) + 1;
194
            size_t const offset = MIN(offsetRand, pos);
195
            size_t match = pos - offset;
196
            while (pos < end) BBuffer[pos++] = BBuffer[match++];
197
        } else {
198
            /* Literal (noise) */
199
            size_t const lengthRand = FUZ_ABOUT(4);
200
            size_t const length = MIN(lengthRand, bufferSize - pos);
201
            size_t const end = pos + length;
202
            while (pos < end) BBuffer[pos++] = FUZ_LITERAL;
203
    }   }
204
}
205

206
static unsigned FUZ_highbit(U32 v32)
207
{
208
    unsigned nbBits = 0;
209
    if (v32==0) return 0;
210
    while (v32) {v32 >>= 1; nbBits ++;}
211
    return nbBits;
212
}
213

214

215
/*-*******************************************************
216
*  Tests
217
*********************************************************/
218

219
#define CONTROL(c) { \
220
    if (!(c)) {      \
221
        DISPLAY("Error (line %i) => %s not respected \n", __LINE__, #c); \
222
        return 1;    \
223
}   }
224

225
static int bug1227(void)
226
{
227
    LZ4F_dctx* dctx;
228
    CONTROL(!LZ4F_isError(LZ4F_createDecompressionContext(&dctx, LZ4F_VERSION)));
229

230
    /* first session */
231
    {   const char s9Buffer[9] = { 0 };
232
        char d9Buffer[sizeof(s9Buffer)];
233
        size_t const c9SizeBound = LZ4F_compressFrameBound(sizeof(s9Buffer), NULL);
234
        void* const c9Buffer = malloc(c9SizeBound);
235
        /* First compress a valid frame */
236
        LZ4F_preferences_t pref = LZ4F_INIT_PREFERENCES;
237
        pref.frameInfo.contentSize = sizeof(s9Buffer);
238
        CONTROL(c9Buffer != NULL);
239
        {   size_t const c9Size = LZ4F_compressFrame(c9Buffer, c9SizeBound, s9Buffer, sizeof(s9Buffer), &pref);
240
            CONTROL(!LZ4F_isError(c9Size));
241
            assert(c9Size > 15);
242
            /* decompress it, but do not complete the process - state not terminated correctly */
243
            {   size_t dstSize = sizeof(d9Buffer);
244
                size_t srcSize = 15;
245
                size_t const d9Size = LZ4F_decompress(dctx, d9Buffer, &dstSize, c9Buffer, &srcSize, NULL);
246
                CONTROL(!LZ4F_isError(d9Size));
247
                CONTROL(srcSize < c9Size); /* not entirely consumed */
248
            }
249
        }
250
        free(c9Buffer);
251
    }
252
    LZ4F_resetDecompressionContext(dctx); /* unfinished session -> reset should make it clean */
253

254
    /* second session : generate a valid 0-size frame with no content size field (default) */
255
    {   size_t const c0SizeBound = LZ4F_compressFrameBound(0, NULL);
256
        void* const c0Buffer = malloc(c0SizeBound);
257
        char d0Buffer[1];
258
        CONTROL(c0Buffer != NULL);
259
        {   size_t const c0Size = LZ4F_compressFrame(c0Buffer, c0SizeBound, NULL, 0, NULL);
260
            CONTROL(!LZ4F_isError(c0Size));
261
            /* now decompress this valid empty frame */
262
            {   size_t dstSize = sizeof(d0Buffer);
263
                size_t srcSize = c0Size;
264
                size_t const d0Size = LZ4F_decompress(dctx, d0Buffer, &dstSize, c0Buffer, &srcSize, NULL);
265
                CONTROL(!LZ4F_isError(d0Size));
266
                CONTROL(dstSize == 0);
267
                CONTROL(srcSize == c0Size);
268
        }   }
269
        free(c0Buffer);
270
    }
271

272
    LZ4F_freeDecompressionContext(dctx);
273
    return 0;
274
}
275

276
#define CHECK_V(v,f) v = f; if (LZ4F_isError(v)) { fprintf(stderr, "%s \n", LZ4F_getErrorName(v)); goto _output_error; }
277
#define CHECK(f)   { LZ4F_errorCode_t const CHECK_V(err_ , f); }
278

279
static int unitTests(U32 seed, double compressibility)
280
{
281
#define COMPRESSIBLE_NOISE_LENGTH (2 MB)
282
    void* const CNBuffer = malloc(COMPRESSIBLE_NOISE_LENGTH);
283
    size_t const cBuffSize = LZ4F_compressFrameBound(COMPRESSIBLE_NOISE_LENGTH, NULL);
284
    void* const compressedBuffer = malloc(cBuffSize);
285
    void* const decodedBuffer = malloc(COMPRESSIBLE_NOISE_LENGTH);
286
    U32 randVal = seed;
287
    U32* const randState = &randVal;
288
    size_t cSize, testSize;
289
    LZ4F_decompressionContext_t dCtx = NULL;
290
    LZ4F_compressionContext_t cctx = NULL;
291
    U64 crcOrig;
292
    int basicTests_error = 0;
293
    LZ4F_preferences_t prefs;
294
    memset(&prefs, 0, sizeof(prefs));
295

296
    if (!CNBuffer || !compressedBuffer || !decodedBuffer) {
297
        DISPLAY("allocation error, not enough memory to start fuzzer tests \n");
298
        goto _output_error;
299
    }
300
    FUZ_fillCompressibleNoiseBuffer(CNBuffer, COMPRESSIBLE_NOISE_LENGTH, compressibility, randState);
301
    crcOrig = XXH64(CNBuffer, COMPRESSIBLE_NOISE_LENGTH, 1);
302

303
    /* LZ4F_compressBound() : special case : srcSize == 0 */
304
    DISPLAYLEVEL(3, "LZ4F_compressBound(0) = ");
305
    {   size_t const cBound = LZ4F_compressBound(0, NULL);
306
        if (cBound < 64 KB) goto _output_error;
307
        DISPLAYLEVEL(3, " %u \n", (U32)cBound);
308
    }
309

310
    /* LZ4F_compressBound() : special case : automatic flushing enabled */
311
    DISPLAYLEVEL(3, "LZ4F_compressBound(1 KB, autoFlush=1) = ");
312
    {   size_t cBound;
313
        LZ4F_preferences_t autoFlushPrefs;
314
        memset(&autoFlushPrefs, 0, sizeof(autoFlushPrefs));
315
        autoFlushPrefs.autoFlush = 1;
316
        cBound = LZ4F_compressBound(1 KB, &autoFlushPrefs);
317
        if (cBound > 64 KB) goto _output_error;
318
        DISPLAYLEVEL(3, " %u \n", (U32)cBound);
319
    }
320

321
    /* LZ4F_compressBound() : special case : automatic flushing disabled */
322
    DISPLAYLEVEL(3, "LZ4F_compressBound(1 KB, autoFlush=0) = ");
323
    {   size_t const cBound = LZ4F_compressBound(1 KB, &prefs);
324
        if (cBound < 64 KB) goto _output_error;
325
        DISPLAYLEVEL(3, " %u \n", (U32)cBound);
326
    }
327

328
    /* Special case : null-content frame */
329
    testSize = 0;
330
    DISPLAYLEVEL(3, "LZ4F_compressFrame, compress null content : ");
331
    CHECK_V(cSize, LZ4F_compressFrame(compressedBuffer, LZ4F_compressFrameBound(testSize, NULL), CNBuffer, testSize, NULL));
332
    DISPLAYLEVEL(3, "null content encoded into a %u bytes frame \n", (unsigned)cSize);
333

334
    DISPLAYLEVEL(3, "LZ4F_createDecompressionContext \n");
335
    CHECK ( LZ4F_createDecompressionContext(&dCtx, LZ4F_VERSION) );
336

337
    DISPLAYLEVEL(3, "LZ4F_getFrameInfo on null-content frame (#157) \n");
338
    assert(cSize >= LZ4F_MIN_SIZE_TO_KNOW_HEADER_LENGTH);
339
    {   LZ4F_frameInfo_t frame_info;
340
        size_t const fhs = LZ4F_headerSize(compressedBuffer, LZ4F_MIN_SIZE_TO_KNOW_HEADER_LENGTH);
341
        size_t avail_in = fhs;
342
        CHECK( fhs );
343
        CHECK( LZ4F_getFrameInfo(dCtx, &frame_info, compressedBuffer, &avail_in) );
344
        if (avail_in != fhs) goto _output_error;  /* must consume all, since header size is supposed to be exact */
345
    }
346

347
    DISPLAYLEVEL(3, "LZ4F_freeDecompressionContext \n");
348
    CHECK( LZ4F_freeDecompressionContext(dCtx) );
349
    dCtx = NULL;
350

351
    /* test one-pass frame compression */
352
    testSize = COMPRESSIBLE_NOISE_LENGTH;
353

354
    DISPLAYLEVEL(3, "LZ4F_compressFrame, using fast level -3 : ");
355
    {   LZ4F_preferences_t fastCompressPrefs;
356
        memset(&fastCompressPrefs, 0, sizeof(fastCompressPrefs));
357
        fastCompressPrefs.compressionLevel = -3;
358
        CHECK_V(cSize, LZ4F_compressFrame(compressedBuffer, LZ4F_compressFrameBound(testSize, NULL), CNBuffer, testSize, &fastCompressPrefs));
359
        DISPLAYLEVEL(3, "Compressed %u bytes into a %u bytes frame \n", (U32)testSize, (U32)cSize);
360
    }
361

362
    DISPLAYLEVEL(3, "LZ4F_compressFrame, using default preferences : ");
363
    CHECK_V(cSize, LZ4F_compressFrame(compressedBuffer, LZ4F_compressFrameBound(testSize, NULL), CNBuffer, testSize, NULL));
364
    DISPLAYLEVEL(3, "Compressed %u bytes into a %u bytes frame \n", (U32)testSize, (U32)cSize);
365

366
    DISPLAYLEVEL(3, "Decompression test : \n");
367
    {   size_t decodedBufferSize = COMPRESSIBLE_NOISE_LENGTH;
368
        size_t compressedBufferSize = cSize;
369

370
        CHECK( LZ4F_createDecompressionContext(&dCtx, LZ4F_VERSION) );
371

372
        DISPLAYLEVEL(3, "Single Pass decompression : ");
373
        CHECK( LZ4F_decompress(dCtx, decodedBuffer, &decodedBufferSize, compressedBuffer, &compressedBufferSize, NULL) );
374
        { U64 const crcDest = XXH64(decodedBuffer, decodedBufferSize, 1);
375
          if (crcDest != crcOrig) goto _output_error; }
376
        DISPLAYLEVEL(3, "Regenerated %u bytes \n", (U32)decodedBufferSize);
377

378
        DISPLAYLEVEL(3, "Reusing decompression context \n");
379
        {   size_t const missingBytes = 4;
380
            size_t iSize = compressedBufferSize - missingBytes;
381
            const BYTE* cBuff = (const BYTE*) compressedBuffer;
382
            BYTE* const ostart = (BYTE*)decodedBuffer;
383
            BYTE* op = ostart;
384
            BYTE* const oend = (BYTE*)decodedBuffer + COMPRESSIBLE_NOISE_LENGTH;
385
            size_t decResult, oSize = COMPRESSIBLE_NOISE_LENGTH;
386
            DISPLAYLEVEL(3, "Missing last %u bytes : ", (U32)missingBytes);
387
            CHECK_V(decResult, LZ4F_decompress(dCtx, op, &oSize, cBuff, &iSize, NULL));
388
            if (decResult != missingBytes) {
389
                DISPLAY("%u bytes missing != %u bytes requested \n", (U32)missingBytes, (U32)decResult);
390
                goto _output_error;
391
            }
392
            DISPLAYLEVEL(3, "indeed, requests %u bytes \n", (unsigned)decResult);
393
            cBuff += iSize;
394
            iSize = decResult;
395
            op += oSize;
396
            oSize = (size_t)(oend-op);
397
            decResult = LZ4F_decompress(dCtx, op, &oSize, cBuff, &iSize, NULL);
398
            if (decResult != 0) goto _output_error;   /* should finish now */
399
            op += oSize;
400
            if (op>oend) { DISPLAY("decompression write overflow \n"); goto _output_error; }
401
            {   U64 const crcDest = XXH64(decodedBuffer, (size_t)(op-ostart), 1);
402
                if (crcDest != crcOrig) goto _output_error;
403
        }   }
404

405
        {   size_t oSize = 0;
406
            size_t iSize = 0;
407
            LZ4F_frameInfo_t fi;
408
            const BYTE* ip = (BYTE*)compressedBuffer;
409

410
            DISPLAYLEVEL(3, "Start by feeding 0 bytes, to get next input size : ");
411
            CHECK( LZ4F_decompress(dCtx, NULL, &oSize, ip, &iSize, NULL) );
412
            //DISPLAYLEVEL(3, " %u  \n", (unsigned)errorCode);
413
            DISPLAYLEVEL(3, " OK  \n");
414

415
            DISPLAYLEVEL(3, "LZ4F_getFrameInfo on zero-size input : ");
416
            {   size_t nullSize = 0;
417
                size_t const fiError = LZ4F_getFrameInfo(dCtx, &fi, ip, &nullSize);
418
                if (LZ4F_getErrorCode(fiError) != LZ4F_ERROR_frameHeader_incomplete) {
419
                    DISPLAYLEVEL(3, "incorrect error : %s != ERROR_frameHeader_incomplete \n",
420
                                    LZ4F_getErrorName(fiError));
421
                    goto _output_error;
422
                }
423
                DISPLAYLEVEL(3, " correctly failed : %s \n", LZ4F_getErrorName(fiError));
424
            }
425

426
            DISPLAYLEVEL(3, "LZ4F_getFrameInfo on not enough input : ");
427
            {   size_t inputSize = 6;
428
                size_t const fiError = LZ4F_getFrameInfo(dCtx, &fi, ip, &inputSize);
429
                if (LZ4F_getErrorCode(fiError) != LZ4F_ERROR_frameHeader_incomplete) {
430
                    DISPLAYLEVEL(3, "incorrect error : %s != ERROR_frameHeader_incomplete \n", LZ4F_getErrorName(fiError));
431
                    goto _output_error;
432
                }
433
                DISPLAYLEVEL(3, " correctly failed : %s \n", LZ4F_getErrorName(fiError));
434
            }
435

436
            DISPLAYLEVEL(3, "LZ4F_getFrameInfo on enough input : ");
437
            iSize = LZ4F_headerSize(ip, LZ4F_MIN_SIZE_TO_KNOW_HEADER_LENGTH);
438
            CHECK( iSize );
439
            CHECK( LZ4F_getFrameInfo(dCtx, &fi, ip, &iSize) );
440
            DISPLAYLEVEL(3, " correctly decoded \n");
441
        }
442

443
        DISPLAYLEVEL(3, "Decode a buggy input : ");
444
        assert(COMPRESSIBLE_NOISE_LENGTH > 64);
445
        assert(cSize > 48);
446
        memcpy(decodedBuffer, (char*)compressedBuffer+16, 32);  /* save correct data */
447
        memcpy((char*)compressedBuffer+16, (const char*)decodedBuffer+32, 32);  /* insert noise */
448
        {   size_t dbSize = COMPRESSIBLE_NOISE_LENGTH;
449
            size_t cbSize = cSize;
450
            size_t const decompressError = LZ4F_decompress(dCtx, decodedBuffer, &dbSize,
451
                                                               compressedBuffer, &cbSize,
452
                                                               NULL);
453
            if (!LZ4F_isError(decompressError)) goto _output_error;
454
            DISPLAYLEVEL(3, "error detected : %s \n", LZ4F_getErrorName(decompressError));
455
        }
456
        memcpy((char*)compressedBuffer+16, decodedBuffer, 32);  /* restore correct data */
457

458
        DISPLAYLEVEL(3, "Reset decompression context, since it's left in error state \n");
459
        LZ4F_resetDecompressionContext(dCtx);   /* always successful */
460

461
        DISPLAYLEVEL(3, "Byte after byte : ");
462
        {   BYTE* const ostart = (BYTE*)decodedBuffer;
463
            BYTE* op = ostart;
464
            BYTE* const oend = (BYTE*)decodedBuffer + COMPRESSIBLE_NOISE_LENGTH;
465
            const BYTE* ip = (const BYTE*) compressedBuffer;
466
            const BYTE* const iend = ip + cSize;
467
            while (ip < iend) {
468
                size_t oSize = (size_t)(oend-op);
469
                size_t iSize = 1;
470
                CHECK( LZ4F_decompress(dCtx, op, &oSize, ip, &iSize, NULL) );
471
                op += oSize;
472
                ip += iSize;
473
            }
474
            {   U64 const crcDest = XXH64(decodedBuffer, COMPRESSIBLE_NOISE_LENGTH, 1);
475
                if (crcDest != crcOrig) goto _output_error;
476
            }
477
            DISPLAYLEVEL(3, "Regenerated %u/%u bytes \n", (unsigned)(op-ostart), (unsigned)COMPRESSIBLE_NOISE_LENGTH);
478
        }
479
    }
480

481
    DISPLAYLEVEL(3, "Using 64 KB block : ");
482
    prefs.frameInfo.blockSizeID = LZ4F_max64KB;
483
    prefs.frameInfo.contentChecksumFlag = LZ4F_contentChecksumEnabled;
484
    CHECK_V(cSize, LZ4F_compressFrame(compressedBuffer, LZ4F_compressFrameBound(testSize, &prefs), CNBuffer, testSize, &prefs));
485
    DISPLAYLEVEL(3, "Compressed %i bytes into a %i bytes frame \n", (int)testSize, (int)cSize);
486

487
    DISPLAYLEVEL(3, "without checksum : ");
488
    prefs.frameInfo.contentChecksumFlag = LZ4F_noContentChecksum;
489
    CHECK_V(cSize, LZ4F_compressFrame(compressedBuffer, LZ4F_compressFrameBound(testSize, &prefs), CNBuffer, testSize, &prefs));
490
    DISPLAYLEVEL(3, "Compressed %i bytes into a %i bytes frame \n", (int)testSize, (int)cSize);
491

492
    DISPLAYLEVEL(3, "Using 256 KB block : ");
493
    prefs.frameInfo.blockSizeID = LZ4F_max256KB;
494
    prefs.frameInfo.contentChecksumFlag = LZ4F_contentChecksumEnabled;
495
    CHECK_V(cSize, LZ4F_compressFrame(compressedBuffer, LZ4F_compressFrameBound(testSize, &prefs), CNBuffer, testSize, &prefs));
496
    DISPLAYLEVEL(3, "Compressed %i bytes into a %i bytes frame \n", (int)testSize, (int)cSize);
497

498
    DISPLAYLEVEL(3, "Decompression test : \n");
499
    {   size_t const decodedBufferSize = COMPRESSIBLE_NOISE_LENGTH;
500
        unsigned const maxBits = FUZ_highbit((U32)decodedBufferSize);
501
        BYTE* const ostart = (BYTE*)decodedBuffer;
502
        BYTE* op = ostart;
503
        BYTE* const oend = ostart + COMPRESSIBLE_NOISE_LENGTH;
504
        const BYTE* ip = (const BYTE*)compressedBuffer;
505
        const BYTE* const iend = (const BYTE*)compressedBuffer + cSize;
506

507
        DISPLAYLEVEL(3, "random segment sizes : ");
508
        while (ip < iend) {
509
            unsigned const nbBits = FUZ_rand(randState) % maxBits;
510
            size_t iSize = RAND_BITS(nbBits) + 1;
511
            size_t oSize = (size_t)(oend-op);
512
            if (iSize > (size_t)(iend-ip)) iSize = (size_t)(iend-ip);
513
            CHECK( LZ4F_decompress(dCtx, op, &oSize, ip, &iSize, NULL) );
514
            op += oSize;
515
            ip += iSize;
516
        }
517
        {   size_t const decodedSize = (size_t)(op - ostart);
518
            U64 const crcDest = XXH64(decodedBuffer, decodedSize, 1);
519
            if (crcDest != crcOrig) goto _output_error;
520
            DISPLAYLEVEL(3, "Regenerated %u bytes \n", (U32)decodedSize);
521
         }
522

523
        CHECK( LZ4F_freeDecompressionContext(dCtx) );
524
        dCtx = NULL;
525
    }
526

527
    DISPLAYLEVEL(3, "without checksum : ");
528
    prefs.frameInfo.contentChecksumFlag = LZ4F_noContentChecksum;
529
    CHECK_V(cSize, LZ4F_compressFrame(compressedBuffer, LZ4F_compressFrameBound(testSize, &prefs), CNBuffer, testSize, &prefs) );
530
    DISPLAYLEVEL(3, "Compressed %i bytes into a %i bytes frame \n", (int)testSize, (int)cSize);
531

532
    DISPLAYLEVEL(3, "Using 1 MB block : ");
533
    prefs.frameInfo.blockSizeID = LZ4F_max1MB;
534
    prefs.frameInfo.contentChecksumFlag = LZ4F_contentChecksumEnabled;
535
    CHECK_V(cSize, LZ4F_compressFrame(compressedBuffer, LZ4F_compressFrameBound(testSize, &prefs), CNBuffer, testSize, &prefs) );
536
    DISPLAYLEVEL(3, "Compressed %i bytes into a %i bytes frame \n", (int)testSize, (int)cSize);
537

538
    DISPLAYLEVEL(3, "without frame checksum : ");
539
    prefs.frameInfo.contentChecksumFlag = LZ4F_noContentChecksum;
540
    CHECK_V(cSize, LZ4F_compressFrame(compressedBuffer, LZ4F_compressFrameBound(testSize, &prefs), CNBuffer, testSize, &prefs) );
541
    DISPLAYLEVEL(3, "Compressed %i bytes into a %i bytes frame \n", (int)testSize, (int)cSize);
542

543
    DISPLAYLEVEL(3, "Using 4 MB block : ");
544
    prefs.frameInfo.blockSizeID = LZ4F_max4MB;
545
    prefs.frameInfo.contentChecksumFlag = LZ4F_contentChecksumEnabled;
546
    {   size_t const dstCapacity = LZ4F_compressFrameBound(testSize, &prefs);
547
        DISPLAYLEVEL(4, "dstCapacity = %u  ; ", (U32)dstCapacity);
548
        CHECK_V(cSize, LZ4F_compressFrame(compressedBuffer, dstCapacity, CNBuffer, testSize, &prefs) );
549
        DISPLAYLEVEL(3, "Compressed %u bytes into a %u bytes frame \n", (U32)testSize, (U32)cSize);
550
    }
551

552
    DISPLAYLEVEL(3, "without frame checksum : ");
553
    prefs.frameInfo.contentChecksumFlag = LZ4F_noContentChecksum;
554
    {   size_t const dstCapacity = LZ4F_compressFrameBound(testSize, &prefs);
555
        DISPLAYLEVEL(4, "dstCapacity = %u  ; ", (U32)dstCapacity);
556
        CHECK_V(cSize, LZ4F_compressFrame(compressedBuffer, dstCapacity, CNBuffer, testSize, &prefs) );
557
        DISPLAYLEVEL(3, "Compressed %u bytes into a %u bytes frame \n", (U32)testSize, (U32)cSize);
558
    }
559

560
    DISPLAYLEVEL(3, "LZ4F_compressFrame with block checksum : ");
561
    memset(&prefs, 0, sizeof(prefs));
562
    prefs.frameInfo.blockChecksumFlag = LZ4F_blockChecksumEnabled;
563
    CHECK_V(cSize, LZ4F_compressFrame(compressedBuffer, LZ4F_compressFrameBound(testSize, &prefs), CNBuffer, testSize, &prefs) );
564
    DISPLAYLEVEL(3, "Compressed %i bytes into a %i bytes frame \n", (int)testSize, (int)cSize);
565

566
    DISPLAYLEVEL(3, "Decompress with block checksum : ");
567
    {   size_t iSize = cSize;
568
        size_t decodedSize = COMPRESSIBLE_NOISE_LENGTH;
569
        LZ4F_decompressionContext_t dctx;
570
        CHECK( LZ4F_createDecompressionContext(&dctx, LZ4F_VERSION) );
571
        CHECK( LZ4F_decompress(dctx, decodedBuffer, &decodedSize, compressedBuffer, &iSize, NULL) );
572
        if (decodedSize != testSize) goto _output_error;
573
        if (iSize != cSize) goto _output_error;
574
        {   U64 const crcDest = XXH64(decodedBuffer, decodedSize, 1);
575
            U64 const crcSrc = XXH64(CNBuffer, testSize, 1);
576
            if (crcDest != crcSrc) goto _output_error;
577
        }
578
        DISPLAYLEVEL(3, "Regenerated %u bytes \n", (U32)decodedSize);
579

580
        CHECK( LZ4F_freeDecompressionContext(dctx) );
581
    }
582

583
    /* frame content size tests */
584
    {   size_t cErr;
585
        BYTE* const ostart = (BYTE*)compressedBuffer;
586
        BYTE* op = ostart;
587
        CHECK( LZ4F_createCompressionContext(&cctx, LZ4F_VERSION) );
588

589
        DISPLAYLEVEL(3, "compress without frameSize : ");
590
        memset(&(prefs.frameInfo), 0, sizeof(prefs.frameInfo));
591
        CHECK_V(cErr, LZ4F_compressBegin(cctx, compressedBuffer, testSize, &prefs));
592
        op += cErr;
593
        CHECK_V(cErr, LZ4F_compressUpdate(cctx, op, LZ4F_compressBound(testSize, &prefs), CNBuffer, testSize, NULL));
594
        op += cErr;
595
        CHECK( LZ4F_compressEnd(cctx, compressedBuffer, testSize, NULL) );
596
        DISPLAYLEVEL(3, "Compressed %i bytes into a %i bytes frame \n", (int)testSize, (int)(op-ostart));
597

598
        DISPLAYLEVEL(3, "compress with frameSize : ");
599
        prefs.frameInfo.contentSize = testSize;
600
        op = ostart;
601
        CHECK_V(cErr, LZ4F_compressBegin(cctx, compressedBuffer, testSize, &prefs));
602
        op += cErr;
603
        CHECK_V(cErr, LZ4F_compressUpdate(cctx, op, LZ4F_compressBound(testSize, &prefs), CNBuffer, testSize, NULL));
604
        op += cErr;
605
        CHECK( LZ4F_compressEnd(cctx, compressedBuffer, testSize, NULL) );
606
        DISPLAYLEVEL(3, "Compressed %i bytes into a %i bytes frame \n", (int)testSize, (int)(op-ostart));
607

608
        DISPLAYLEVEL(3, "compress with wrong frameSize : ");
609
        prefs.frameInfo.contentSize = testSize+1;
610
        op = ostart;
611
        CHECK_V(cErr, LZ4F_compressBegin(cctx, compressedBuffer, testSize, &prefs));
612
        op += cErr;
613
        CHECK_V(cErr, LZ4F_compressUpdate(cctx, op, LZ4F_compressBound(testSize, &prefs), CNBuffer, testSize, NULL));
614
        op += cErr;
615
        cErr = LZ4F_compressEnd(cctx, op, testSize, NULL);
616
        if (!LZ4F_isError(cErr)) goto _output_error;
617
        DISPLAYLEVEL(3, "Error correctly detected : %s \n", LZ4F_getErrorName(cErr));
618

619
        CHECK( LZ4F_freeCompressionContext(cctx) );
620
        cctx = NULL;
621
    }
622

623
    /* dictID tests */
624
    {   size_t cErr;
625
        U32 const dictID = 0x99;
626
        /* test advanced variant with custom allocator functions */
627
        cctx = LZ4F_createCompressionContext_advanced(lz4f_cmem_test, LZ4F_VERSION);
628
        if (cctx==NULL) goto _output_error;
629

630
        DISPLAYLEVEL(3, "insert a dictID : ");
631
        memset(&prefs.frameInfo, 0, sizeof(prefs.frameInfo));
632
        prefs.frameInfo.dictID = dictID;
633
        CHECK_V(cErr, LZ4F_compressBegin(cctx, compressedBuffer, testSize, &prefs));
634
        DISPLAYLEVEL(3, "created frame header of size %i bytes  \n", (int)cErr);
635

636
        DISPLAYLEVEL(3, "read a dictID : ");
637
        CHECK( LZ4F_createDecompressionContext(&dCtx, LZ4F_VERSION) );
638
        memset(&prefs.frameInfo, 0, sizeof(prefs.frameInfo));
639
        CHECK( LZ4F_getFrameInfo(dCtx, &prefs.frameInfo, compressedBuffer, &cErr) );
640
        if (prefs.frameInfo.dictID != dictID) goto _output_error;
641
        DISPLAYLEVEL(3, "%u \n", (U32)prefs.frameInfo.dictID);
642

643
        CHECK( LZ4F_freeDecompressionContext(dCtx) ); dCtx = NULL;
644
        CHECK( LZ4F_freeCompressionContext(cctx) ); cctx = NULL;
645
    }
646

647
    /* Raw Dictionary compression test */
648
    {   size_t const dictSize = 7 KB; /* small enough for LZ4_MEMORY_USAGE == 10 */
649
        size_t const srcSize = 66 KB; /* must be > 64 KB to avoid short-size optimizations */
650
        size_t const dstCapacity = LZ4F_compressFrameBound(srcSize, NULL);
651
        size_t cSizeNoDict, cSizeWithDict;
652
        const void* dict = CNBuffer;
653
        const void* src = (const char*)CNBuffer + dictSize;
654
        char* cPtr = (char*)compressedBuffer;
655
        CHECK( LZ4F_createCompressionContext(&cctx, LZ4F_VERSION) );
656

657
        /* compress without dictionary, just to establish a comparison point */
658
        CHECK_V(cSizeNoDict,
659
                LZ4F_compressFrame(compressedBuffer, dstCapacity,
660
                                    src, srcSize,
661
                                    NULL) );
662
        /* note: NULL preferences ==> 64 KB linked blocks */
663

664
        /* now compress with dictionary */
665
        DISPLAYLEVEL(3, "LZ4F_compressBegin_usingDict: ");
666
        cSizeWithDict = 0;
667
        {   size_t hSize = LZ4F_compressBegin_usingDict(cctx, cPtr, dstCapacity, dict, dictSize, NULL);
668
            //size_t hSize = LZ4F_compressBegin(cctx, cPtr, dstCapacity, NULL);
669
            CHECK(hSize);
670
            cSizeWithDict += hSize;
671
            cPtr += hSize;
672
        }
673
        {   size_t bSize = LZ4F_compressUpdate(cctx, cPtr, dstCapacity, src, srcSize, NULL);
674
            CHECK(bSize);
675
            cSizeWithDict += bSize;
676
            cPtr += bSize;
677
        }
678
        {   size_t endSize = LZ4F_compressEnd(cctx, cPtr, dstCapacity, NULL);
679
            CHECK(endSize);
680
            cSizeWithDict += endSize;
681
        }
682
        DISPLAYLEVEL(3, "compress %u bytes into %u bytes with dict (< %u bytes without) \n",
683
                        (unsigned)srcSize, (unsigned)cSizeWithDict, (unsigned)cSizeNoDict);
684
        if (cSizeWithDict >= cSizeNoDict) {
685
            DISPLAYLEVEL(3, "cSizeWithDict (%u) should have been more compact than cSizeNoDict(%u) \n", (unsigned)cSizeWithDict, (unsigned)cSizeNoDict);
686
            goto _output_error;  /* must be more efficient */
687
        }
688
        crcOrig = XXH64(src, srcSize, 0);
689

690
        DISPLAYLEVEL(3, "LZ4F_decompress_usingDict: ");
691
        {   LZ4F_dctx* dctx;
692
            size_t decodedSize = srcSize;
693
            size_t compressedSize = cSizeWithDict;
694
            CHECK( LZ4F_createDecompressionContext(&dctx, LZ4F_VERSION) );
695
            CHECK( LZ4F_decompress_usingDict(dctx,
696
                                        decodedBuffer, &decodedSize,
697
                                        compressedBuffer, &compressedSize,
698
                                        CNBuffer, dictSize,
699
                                        NULL) );
700
            if (compressedSize != cSizeWithDict) goto _output_error;
701
            if (decodedSize != srcSize) goto _output_error;
702
            { U64 const crcDest = XXH64(decodedBuffer, decodedSize, 0);
703
              if (crcDest != crcOrig) goto _output_error; }
704
            DISPLAYLEVEL(3, "Regenerated %u bytes \n", (U32)decodedSize);
705
            CHECK( LZ4F_freeDecompressionContext(dctx) );
706
        }
707

708
        /* clean */
709
        CHECK( LZ4F_freeCompressionContext(cctx) );
710
    }
711

712
    /* Digested Dictionary (cdict) compression test */
713
    {   size_t const dictSize = 7 KB; /* small enough for LZ4_MEMORY_USAGE == 10 */
714
        size_t const srcSize = 65 KB; /* must be > 64 KB to avoid short-size optimizations */
715
        size_t const dstCapacity = LZ4F_compressFrameBound(srcSize, NULL);
716
        size_t cSizeNoDict, cSizeWithDict;
717
        LZ4F_CDict* const cdict = LZ4F_createCDict(CNBuffer, dictSize);
718
        if (cdict == NULL) goto _output_error;
719
        CHECK( LZ4F_createCompressionContext(&cctx, LZ4F_VERSION) );
720

721
        DISPLAYLEVEL(3, "Testing LZ4F_createCDict_advanced : ");
722
        {   LZ4F_CDict* const cda = LZ4F_createCDict_advanced(lz4f_cmem_test, CNBuffer, dictSize);
723
            if (cda == NULL) goto _output_error;
724
            LZ4F_freeCDict(cda);
725
        }
726
        DISPLAYLEVEL(3, "OK \n");
727

728
        DISPLAYLEVEL(3, "LZ4F_compressFrame_usingCDict, with NULL dict : ");
729
        CHECK_V(cSizeNoDict,
730
                LZ4F_compressFrame_usingCDict(cctx, compressedBuffer, dstCapacity,
731
                                              CNBuffer, srcSize,
732
                                              NULL, NULL) );
733
        DISPLAYLEVEL(3, "%u bytes \n", (unsigned)cSizeNoDict);
734

735
        DISPLAYLEVEL(3, "LZ4F_compressFrame_usingCDict, with dict : ");
736
        CHECK( LZ4F_freeCompressionContext(cctx) );
737
        CHECK( LZ4F_createCompressionContext(&cctx, LZ4F_VERSION) );
738
        CHECK_V(cSizeWithDict,
739
                LZ4F_compressFrame_usingCDict(cctx, compressedBuffer, dstCapacity,
740
                                              CNBuffer, srcSize,
741
                                              cdict, NULL) );
742
        DISPLAYLEVEL(3, "compressed %u bytes into %u bytes \n",
743
                        (unsigned)srcSize, (unsigned)cSizeWithDict);
744
        if (cSizeWithDict > cSizeNoDict) {
745
            DISPLAYLEVEL(3, "cSizeWithDict (%u) should have been more compact than cSizeNoDict(%u) \n", (unsigned)cSizeWithDict, (unsigned)cSizeNoDict);
746
            goto _output_error;  /* must be more efficient */
747
        }
748
        crcOrig = XXH64(CNBuffer, srcSize, 0);
749

750
        DISPLAYLEVEL(3, "LZ4F_decompress_usingDict : ");
751
        {   LZ4F_dctx* dctx;
752
            size_t decodedSize = srcSize;
753
            size_t compressedSize = cSizeWithDict;
754
            CHECK( LZ4F_createDecompressionContext(&dctx, LZ4F_VERSION) );
755
            CHECK( LZ4F_decompress_usingDict(dctx,
756
                                        decodedBuffer, &decodedSize,
757
                                        compressedBuffer, &compressedSize,
758
                                        CNBuffer, dictSize,
759
                                        NULL) );
760
            if (compressedSize != cSizeWithDict) goto _output_error;
761
            if (decodedSize != srcSize) goto _output_error;
762
            { U64 const crcDest = XXH64(decodedBuffer, decodedSize, 0);
763
              if (crcDest != crcOrig) goto _output_error; }
764
            DISPLAYLEVEL(3, "Regenerated %u bytes \n", (U32)decodedSize);
765
            CHECK( LZ4F_freeDecompressionContext(dctx) );
766
        }
767

768
        DISPLAYLEVEL(3, "LZ4F_compressFrame_usingCDict, with dict, negative level : ");
769
        {   size_t cSizeLevelMax;
770
            LZ4F_preferences_t cParams;
771
            memset(&cParams, 0, sizeof(cParams));
772
            cParams.compressionLevel = -3;
773
            CHECK_V(cSizeLevelMax,
774
                LZ4F_compressFrame_usingCDict(cctx, compressedBuffer, dstCapacity,
775
                                              CNBuffer, dictSize,
776
                                              cdict, &cParams) );
777
            DISPLAYLEVEL(3, "%u bytes \n", (unsigned)cSizeLevelMax);
778
        }
779

780
        DISPLAYLEVEL(3, "LZ4F_compressFrame_usingCDict, with dict, level max : ");
781
        {   size_t cSizeLevelMax;
782
            LZ4F_preferences_t cParams;
783
            memset(&cParams, 0, sizeof(cParams));
784
            cParams.compressionLevel = LZ4F_compressionLevel_max();
785
            CHECK_V(cSizeLevelMax,
786
                LZ4F_compressFrame_usingCDict(cctx, compressedBuffer, dstCapacity,
787
                                              CNBuffer, dictSize,
788
                                              cdict, &cParams) );
789
            DISPLAYLEVEL(3, "%u bytes \n", (unsigned)cSizeLevelMax);
790
        }
791

792
        DISPLAYLEVEL(3, "LZ4F_compressFrame_usingCDict, multiple linked blocks : ");
793
        {   size_t cSizeContiguous;
794
            size_t const inSize = dictSize * 3;
795
            size_t const outCapacity = LZ4F_compressFrameBound(inSize, NULL);
796
            LZ4F_preferences_t cParams;
797
            memset(&cParams, 0, sizeof(cParams));
798
            cParams.frameInfo.blockMode = LZ4F_blockLinked;
799
            cParams.frameInfo.blockSizeID = LZ4F_max64KB;
800
            CHECK_V(cSizeContiguous,
801
                LZ4F_compressFrame_usingCDict(cctx, compressedBuffer, outCapacity,
802
                                              CNBuffer, inSize,
803
                                              cdict, &cParams) );
804
            DISPLAYLEVEL(3, "compressed %u bytes into %u bytes \n",
805
                        (unsigned)inSize, (unsigned)cSizeContiguous);
806

807
            DISPLAYLEVEL(3, "LZ4F_decompress_usingDict on multiple linked blocks : ");
808
            {   LZ4F_dctx* dctx;
809
                size_t decodedSize = COMPRESSIBLE_NOISE_LENGTH;
810
                size_t compressedSize = cSizeContiguous;
811
                CHECK( LZ4F_createDecompressionContext(&dctx, LZ4F_VERSION) );
812
                CHECK( LZ4F_decompress_usingDict(dctx,
813
                                            decodedBuffer, &decodedSize,
814
                                            compressedBuffer, &compressedSize,
815
                                            CNBuffer, dictSize,
816
                                            NULL) );
817
                if (compressedSize != cSizeContiguous) goto _output_error;
818
                if (decodedSize != inSize) goto _output_error;
819
                crcOrig = XXH64(CNBuffer, inSize, 0);
820
                { U64 const crcDest = XXH64(decodedBuffer, decodedSize, 0);
821
                  if (crcDest != crcOrig) goto _output_error; }
822
                DISPLAYLEVEL(3, "Regenerated %u bytes \n", (U32)decodedSize);
823
                CHECK( LZ4F_freeDecompressionContext(dctx) );
824
            }
825
        }
826

827
        DISPLAYLEVEL(3, "LZ4F_compressFrame_usingCDict, multiple independent blocks : ");
828
        {   size_t cSizeIndep;
829
            size_t const inSize = dictSize * 3;
830
            size_t const outCapacity = LZ4F_compressFrameBound(inSize, NULL);
831
            LZ4F_preferences_t cParams;
832
            memset(&cParams, 0, sizeof(cParams));
833
            cParams.frameInfo.blockMode = LZ4F_blockIndependent;
834
            cParams.frameInfo.blockSizeID = LZ4F_max64KB;
835
            CHECK_V(cSizeIndep,
836
                LZ4F_compressFrame_usingCDict(cctx, compressedBuffer, outCapacity,
837
                                              CNBuffer, inSize,
838
                                              cdict, &cParams) );
839
            DISPLAYLEVEL(3, "compressed %u bytes into %u bytes \n",
840
                        (unsigned)inSize, (unsigned)cSizeIndep);
841

842
            DISPLAYLEVEL(3, "LZ4F_decompress_usingDict on multiple independent blocks : ");
843
            {   LZ4F_dctx* dctx;
844
                size_t decodedSize = COMPRESSIBLE_NOISE_LENGTH;
845
                size_t compressedSize = cSizeIndep;
846
                CHECK( LZ4F_createDecompressionContext(&dctx, LZ4F_VERSION) );
847
                CHECK( LZ4F_decompress_usingDict(dctx,
848
                                            decodedBuffer, &decodedSize,
849
                                            compressedBuffer, &compressedSize,
850
                                            CNBuffer, dictSize,
851
                                            NULL) );
852
                if (compressedSize != cSizeIndep) goto _output_error;
853
                if (decodedSize != inSize) goto _output_error;
854
                crcOrig = XXH64(CNBuffer, inSize, 0);
855
                { U64 const crcDest = XXH64(decodedBuffer, decodedSize, 0);
856
                  if (crcDest != crcOrig) goto _output_error; }
857
                DISPLAYLEVEL(3, "Regenerated %u bytes \n", (U32)decodedSize);
858
                CHECK( LZ4F_freeDecompressionContext(dctx) );
859
            }
860
        }
861

862
        LZ4F_freeCDict(cdict);
863
        CHECK( LZ4F_freeCompressionContext(cctx) ); cctx = NULL;
864
    }
865

866
    DISPLAYLEVEL(3, "getBlockSize test: \n");
867
    { size_t result;
868
      unsigned blockSizeID;
869
      for (blockSizeID = 4; blockSizeID < 8; ++blockSizeID) {
870
        result = LZ4F_getBlockSize((LZ4F_blockSizeID_t)blockSizeID);
871
        CHECK(result);
872
        DISPLAYLEVEL(3, "Returned block size of %u bytes for blockID %u \n",
873
                         (unsigned)result, blockSizeID);
874
      }
875

876
      /* Test an invalid input that's too large */
877
      result = LZ4F_getBlockSize((LZ4F_blockSizeID_t)8);
878
      if(!LZ4F_isError(result) ||
879
          LZ4F_getErrorCode(result) != LZ4F_ERROR_maxBlockSize_invalid)
880
        goto _output_error;
881

882
      /* Test an invalid input that's too small */
883
      result = LZ4F_getBlockSize((LZ4F_blockSizeID_t)3);
884
      if(!LZ4F_isError(result) ||
885
          LZ4F_getErrorCode(result) != LZ4F_ERROR_maxBlockSize_invalid)
886
        goto _output_error;
887
    }
888

889
    DISPLAYLEVEL(3, "check bug1227: reused dctx after error => ");
890
    if (bug1227()) goto _output_error;
891
    DISPLAYLEVEL(3, "OK \n");
892

893
    DISPLAYLEVEL(3, "Skippable frame test : \n");
894
    {   size_t decodedBufferSize = COMPRESSIBLE_NOISE_LENGTH;
895
        unsigned maxBits = FUZ_highbit((U32)decodedBufferSize);
896
        BYTE* op = (BYTE*)decodedBuffer;
897
        BYTE* const oend = (BYTE*)decodedBuffer + COMPRESSIBLE_NOISE_LENGTH;
898
        BYTE* ip = (BYTE*)compressedBuffer;
899
        BYTE* iend = (BYTE*)compressedBuffer + cSize + 8;
900

901
        CHECK( LZ4F_createDecompressionContext(&dCtx, LZ4F_VERSION) );
902

903
        /* generate skippable frame */
904
        FUZ_writeLE32(ip, LZ4F_MAGIC_SKIPPABLE_START);
905
        FUZ_writeLE32(ip+4, (U32)cSize);
906

907
        DISPLAYLEVEL(3, "random segment sizes : \n");
908
        while (ip < iend) {
909
            unsigned nbBits = FUZ_rand(randState) % maxBits;
910
            size_t iSize = RAND_BITS(nbBits) + 1;
911
            size_t oSize = (size_t)(oend-op);
912
            if (iSize > (size_t)(iend-ip)) iSize = (size_t)(iend-ip);
913
            CHECK( LZ4F_decompress(dCtx, op, &oSize, ip, &iSize, NULL) );
914
            op += oSize;
915
            ip += iSize;
916
        }
917
        DISPLAYLEVEL(3, "Skipped %i bytes \n", (int)decodedBufferSize);
918

919
        /* generate zero-size skippable frame */
920
        DISPLAYLEVEL(3, "zero-size skippable frame\n");
921
        ip = (BYTE*)compressedBuffer;
922
        op = (BYTE*)decodedBuffer;
923
        FUZ_writeLE32(ip, LZ4F_MAGIC_SKIPPABLE_START+1);
924
        FUZ_writeLE32(ip+4, 0);
925
        iend = ip+8;
926

927
        while (ip < iend) {
928
            unsigned const nbBits = FUZ_rand(randState) % maxBits;
929
            size_t iSize = RAND_BITS(nbBits) + 1;
930
            size_t oSize = (size_t)(oend-op);
931
            if (iSize > (size_t)(iend-ip)) iSize = (size_t)(iend-ip);
932
            CHECK( LZ4F_decompress(dCtx, op, &oSize, ip, &iSize, NULL) );
933
            op += oSize;
934
            ip += iSize;
935
        }
936
        DISPLAYLEVEL(3, "Skipped %i bytes \n", (int)(ip - (BYTE*)compressedBuffer - 8));
937

938
        DISPLAYLEVEL(3, "Skippable frame header complete in first call \n");
939
        ip = (BYTE*)compressedBuffer;
940
        op = (BYTE*)decodedBuffer;
941
        FUZ_writeLE32(ip, LZ4F_MAGIC_SKIPPABLE_START+2);
942
        FUZ_writeLE32(ip+4, 10);
943
        iend = ip+18;
944
        while (ip < iend) {
945
            size_t iSize = 10;
946
            size_t oSize = 10;
947
            if (iSize > (size_t)(iend-ip)) iSize = (size_t)(iend-ip);
948
            CHECK( LZ4F_decompress(dCtx, op, &oSize, ip, &iSize, NULL) );
949
            op += oSize;
950
            ip += iSize;
951
        }
952
        DISPLAYLEVEL(3, "Skipped %i bytes \n", (int)(ip - (BYTE*)compressedBuffer - 8));
953
    }
954

955
    DISPLAY("Basic tests completed \n");
956
_end:
957
    free(CNBuffer);
958
    free(compressedBuffer);
959
    free(decodedBuffer);
960
    LZ4F_freeDecompressionContext(dCtx); dCtx = NULL;
961
    LZ4F_freeCompressionContext(cctx); cctx = NULL;
962
    return basicTests_error;
963

964
_output_error:
965
    basicTests_error = 1;
966
    DISPLAY("Error detected ! \n");
967
    goto _end;
968
}
969

970

971
typedef enum { o_contiguous, o_noncontiguous, o_overwrite } o_scenario_e;
972

973
static void locateBuffDiff(const void* buff1, const void* buff2, size_t size, o_scenario_e o_scenario)
974
{
975
    if (displayLevel >= 2) {
976
        size_t p=0;
977
        const BYTE* b1=(const BYTE*)buff1;
978
        const BYTE* b2=(const BYTE*)buff2;
979
        DISPLAY("locateBuffDiff: looking for error position \n");
980
        if (o_scenario != o_contiguous) {
981
            DISPLAY("mode %i: non-contiguous output (%u bytes), cannot search \n",
982
                    (int)o_scenario, (unsigned)size);
983
            return;
984
        }
985
        while (p < size && b1[p]==b2[p]) p++;
986
        if (p != size) {
987
            DISPLAY("Error at pos %i/%i : %02X != %02X \n", (int)p, (int)size, b1[p], b2[p]);
988
        }
989
    }
990
}
991

992
#define EXIT_MSG(...) { DISPLAY("Error => "); DISPLAY(__VA_ARGS__); \
993
                        DISPLAY(" (seed %u, test nb %u)  \n", seed, testNb); exit(1); }
994
#undef CHECK
995
#define CHECK(cond, ...) { if (cond) { EXIT_MSG(__VA_ARGS__); } }
996

997
size_t test_lz4f_decompression_wBuffers(
998
          const void* cSrc, size_t cSize,
999
                void* dst, size_t dstCapacity, o_scenario_e o_scenario,
1000
          const void* srcRef, size_t decompressedSize,
1001
                U64 crcOrig,
1002
                U32* const randState,
1003
                LZ4F_dctx* const dCtx,
1004
                U32 seed, U32 testNb,
1005
                int findErrorPos)
1006
{
1007
    const BYTE* ip = (const BYTE*)cSrc;
1008
    const BYTE* const iend = ip + cSize;
1009

1010
    BYTE* op = (BYTE*)dst;
1011
    BYTE* const oend = op + dstCapacity;
1012

1013
    unsigned const suggestedBits = FUZ_highbit((U32)cSize);
1014
    unsigned const maxBits = MAX(3, suggestedBits);
1015
    size_t totalOut = 0;
1016
    size_t moreToFlush = 0;
1017
    XXH64_state_t xxh64;
1018
    XXH64_reset(&xxh64, 1);
1019
    assert(ip < iend);
1020
    while (ip < iend) {
1021
        unsigned const nbBitsI = (FUZ_rand(randState) % (maxBits-1)) + 1;
1022
        unsigned const nbBitsO = (FUZ_rand(randState) % (maxBits)) + 1;
1023
        size_t const iSizeCand = RAND_BITS(nbBitsI) + 1;
1024
        size_t const iSizeMax = MIN(iSizeCand, (size_t)(iend-ip));
1025
        size_t iSize = iSizeMax;
1026
        size_t const oSizeCand = RAND_BITS(nbBitsO) + 2;
1027
        size_t const oSizeMax = MIN(oSizeCand, (size_t)(oend-op));
1028
        int const sentinelTest = (op + oSizeMax < oend);
1029
        size_t oSize = oSizeMax;
1030
        BYTE const mark = (BYTE)(RAND_BITS(8));
1031
        LZ4F_decompressOptions_t dOptions;
1032
        memset(&dOptions, 0, sizeof(dOptions));
1033
        dOptions.stableDst = RAND_BITS(1);
1034
        if (o_scenario == o_overwrite) dOptions.stableDst = 0;  /* overwrite mode */
1035
        dOptions.skipChecksums = RAND_BITS(1);
1036
        if (sentinelTest) op[oSizeMax] = mark;
1037

1038
        DISPLAYLEVEL(7, "dstCapacity=%u,  presentedInput=%u \n", (unsigned)oSize, (unsigned)iSize);
1039

1040
        /* read data from byte-exact buffer to catch out-of-bound reads */
1041
        {   void* const iBuffer = malloc(iSizeMax);
1042
            /*test NULL supported if size==0 */
1043
            void* const tmpop = RAND_BITS(oSize == 0) ? NULL : op;
1044
            const void* const tmpip = RAND_BITS(iSize == 0) ? NULL : iBuffer;
1045
            assert(iBuffer != NULL);
1046
            memcpy(iBuffer, ip, iSizeMax);
1047
            moreToFlush = LZ4F_decompress(dCtx, tmpop, &oSize, tmpip, &iSize, &dOptions);
1048
            free(iBuffer);
1049
        }
1050
        DISPLAYLEVEL(7, "oSize=%u,  readSize=%u \n", (unsigned)oSize, (unsigned)iSize);
1051

1052
        if (sentinelTest) {
1053
            CHECK(op[oSizeMax] != mark, "op[oSizeMax] = %02X != %02X : "
1054
                    "Decompression overwrites beyond assigned dst size",
1055
                    op[oSizeMax], mark);
1056
        }
1057
        if (LZ4F_getErrorCode(moreToFlush) == LZ4F_ERROR_contentChecksum_invalid) {
1058
            if (findErrorPos) DISPLAYLEVEL(2, "checksum error detected \n");
1059
            if (findErrorPos) locateBuffDiff(srcRef, dst, decompressedSize, o_scenario);
1060
        }
1061
        if (LZ4F_isError(moreToFlush)) return moreToFlush;
1062

1063
        XXH64_update(&xxh64, op, oSize);
1064
        totalOut += oSize;
1065
        op += oSize;
1066
        ip += iSize;
1067
        if (o_scenario == o_noncontiguous) {
1068
            if (op == oend) return LZ4F_ERROR_GENERIC;  /* can theoretically happen with bogus data */
1069
            op++; /* create a gap between consecutive output */
1070
        }
1071
        if (o_scenario==o_overwrite) op = (BYTE*)dst;   /* overwrite destination */
1072
        if ( (op == oend) /* no more room for output; can happen with bogus input */
1073
          && (iSize == 0)) /* no input consumed */
1074
            break;
1075
    }
1076
    if (moreToFlush != 0) return LZ4F_ERROR_decompressionFailed;
1077
    if (totalOut) {  /* otherwise, it's a skippable frame */
1078
        U64 const crcDecoded = XXH64_digest(&xxh64);
1079
        if (crcDecoded != crcOrig) {
1080
            if (findErrorPos) locateBuffDiff(srcRef, dst, decompressedSize, o_scenario);
1081
            return LZ4F_ERROR_contentChecksum_invalid;
1082
    }   }
1083
    return 0;
1084
}
1085

1086

1087
size_t test_lz4f_decompression(const void* cSrc, size_t cSize,
1088
                               const void* srcRef, size_t decompressedSize,
1089
                               U64 crcOrig,
1090
                               U32* const randState,
1091
                               LZ4F_dctx* const dCtx,
1092
                               U32 seed, U32 testNb,
1093
                               int findErrorPos)
1094
{
1095
    o_scenario_e const o_scenario = (o_scenario_e)(FUZ_rand(randState) % 3);   /* 0 : contiguous; 1 : non-contiguous; 2 : dst overwritten */
1096
    /* tighten dst buffer conditions */
1097
    size_t const dstCapacity = (o_scenario == o_noncontiguous) ?
1098
                               (decompressedSize * 2) + 128 :
1099
                               decompressedSize;
1100
    size_t result;
1101
    void* const dstBuffer = malloc(dstCapacity);
1102
    assert(dstBuffer != NULL);
1103

1104
    result = test_lz4f_decompression_wBuffers(cSrc, cSize,
1105
                                     dstBuffer, dstCapacity, o_scenario,
1106
                                     srcRef, decompressedSize,
1107
                                     crcOrig,
1108
                                     randState,
1109
                                     dCtx,
1110
                                     seed, testNb, findErrorPos);
1111

1112
    free(dstBuffer);
1113
    return result;
1114
}
1115

1116

1117
int fuzzerTests(U32 seed, unsigned nbTests, unsigned startTest, double compressibility, U32 duration_s)
1118
{
1119
    unsigned testNb = 0;
1120
    size_t const CNBufferLength = 9 MB;  /* needs to be > 2x4MB to test large blocks */
1121
    void* CNBuffer = NULL;
1122
    size_t const compressedBufferSize = LZ4F_compressFrameBound(CNBufferLength, NULL) + 4 MB;  /* needs some margin */
1123
    void* compressedBuffer = NULL;
1124
    void* decodedBuffer = NULL;
1125
    U32 coreRand = seed;
1126
    LZ4F_decompressionContext_t dCtx = NULL;
1127
    LZ4F_compressionContext_t cCtx = NULL;
1128
    clock_t const startClock = clock();
1129
    clock_t const clockDuration = duration_s * CLOCKS_PER_SEC;
1130

1131
    /* Create states & buffers */
1132
    {   size_t const creationStatus = LZ4F_createDecompressionContext(&dCtx, LZ4F_VERSION);
1133
        CHECK(LZ4F_isError(creationStatus), "Allocation failed (error %i)", (int)creationStatus); }
1134
    {   size_t const creationStatus = LZ4F_createCompressionContext(&cCtx, LZ4F_VERSION);
1135
        CHECK(LZ4F_isError(creationStatus), "Allocation failed (error %i)", (int)creationStatus); }
1136
    CNBuffer = malloc(CNBufferLength);
1137
    CHECK(CNBuffer==NULL, "CNBuffer Allocation failed");
1138
    compressedBuffer = malloc(compressedBufferSize);
1139
    CHECK(compressedBuffer==NULL, "compressedBuffer Allocation failed");
1140
    decodedBuffer = calloc(1, CNBufferLength);   /* calloc avoids decodedBuffer being considered "garbage" by scan-build */
1141
    CHECK(decodedBuffer==NULL, "decodedBuffer Allocation failed");
1142
    FUZ_fillCompressibleNoiseBuffer(CNBuffer, CNBufferLength, compressibility, &coreRand);
1143

1144
    /* jump to requested testNb */
1145
    for (testNb =0; (testNb < startTest); testNb++) (void)FUZ_rand(&coreRand);   /* sync randomizer */
1146

1147
    /* main fuzzer test loop */
1148
    for ( ; (testNb < nbTests) || (clockDuration > FUZ_GetClockSpan(startClock)) ; testNb++) {
1149
        U32 randState = coreRand ^ prime1;
1150
        unsigned const srcBits = (FUZ_rand(&randState) % (FUZ_highbit((U32)(CNBufferLength-1)) - 1)) + 1;
1151
        size_t const srcSize = (FUZ_rand(&randState) & ((1<<srcBits)-1));
1152
        size_t const srcStartId = FUZ_rand(&randState) % (CNBufferLength - srcSize);
1153
        const BYTE* const srcStart = (const BYTE*)CNBuffer + srcStartId;
1154
        unsigned const neverFlush = (FUZ_rand(&randState) & 15) == 1;
1155
        U64 const crcOrig = XXH64(srcStart, srcSize, 1);
1156
        LZ4F_preferences_t prefs;
1157
        const LZ4F_preferences_t* prefsPtr = &prefs;
1158
        size_t cSize;
1159

1160
        (void)FUZ_rand(&coreRand);   /* update seed */
1161
        memset(&prefs, 0, sizeof(prefs));
1162
        prefs.frameInfo.blockMode = (LZ4F_blockMode_t)(FUZ_rand(&randState) & 1);
1163
        prefs.frameInfo.blockSizeID = (LZ4F_blockSizeID_t)(4 + (FUZ_rand(&randState) & 3));
1164
        prefs.frameInfo.blockChecksumFlag = (LZ4F_blockChecksum_t)(FUZ_rand(&randState) & 1);
1165
        prefs.frameInfo.contentChecksumFlag = (LZ4F_contentChecksum_t)(FUZ_rand(&randState) & 1);
1166
        prefs.frameInfo.contentSize = ((FUZ_rand(&randState) & 0xF) == 1) ? srcSize : 0;
1167
        prefs.autoFlush = neverFlush ? 0 : (FUZ_rand(&randState) & 7) == 2;
1168
        prefs.compressionLevel = -5 + (int)(FUZ_rand(&randState) % 11);
1169
        if ((FUZ_rand(&randState) & 0xF) == 1) prefsPtr = NULL;
1170

1171
        DISPLAYUPDATE(2, "\r%5u   ", testNb);
1172

1173
        if ((FUZ_rand(&randState) & 0xFFF) == 0) {
1174
            /* create a skippable frame (rare case) */
1175
            BYTE* op = (BYTE*)compressedBuffer;
1176
            FUZ_writeLE32(op, LZ4F_MAGIC_SKIPPABLE_START + (FUZ_rand(&randState) & 15));
1177
            FUZ_writeLE32(op+4, (U32)srcSize);
1178
            cSize = srcSize+8;
1179

1180
        } else if ((FUZ_rand(&randState) & 0xF) == 2) {  /* single pass compression (simple) */
1181
            cSize = LZ4F_compressFrame(compressedBuffer, LZ4F_compressFrameBound(srcSize, prefsPtr), srcStart, srcSize, prefsPtr);
1182
            CHECK(LZ4F_isError(cSize), "LZ4F_compressFrame failed : error %i (%s)", (int)cSize, LZ4F_getErrorName(cSize));
1183

1184
        } else {   /* multi-segments compression */
1185
            const BYTE* ip = srcStart;
1186
            const BYTE* const iend = srcStart + srcSize;
1187
            BYTE* op = (BYTE*)compressedBuffer;
1188
            BYTE* const oend = op + (neverFlush ? LZ4F_compressFrameBound(srcSize, prefsPtr) : compressedBufferSize);  /* when flushes are possible, can't guarantee a max compressed size */
1189
            unsigned const maxBits = FUZ_highbit((U32)srcSize);
1190
            LZ4F_compressOptions_t cOptions;
1191
            memset(&cOptions, 0, sizeof(cOptions));
1192
            {   size_t const fhSize = LZ4F_compressBegin(cCtx, op, (size_t)(oend-op), prefsPtr);
1193
                CHECK(LZ4F_isError(fhSize), "Compression header failed (error %i)",
1194
                                            (int)fhSize);
1195
                op += fhSize;
1196
            }
1197
            while (ip < iend) {
1198
                unsigned const nbBitsSeg = FUZ_rand(&randState) % maxBits;
1199
                size_t const sampleMax = (FUZ_rand(&randState) & ((1<<nbBitsSeg)-1)) + 1;
1200
                size_t iSize = MIN(sampleMax, (size_t)(iend-ip));
1201
                size_t const oSize = LZ4F_compressBound(iSize, prefsPtr);
1202
                cOptions.stableSrc = ((FUZ_rand(&randState) & 3) == 1);
1203
                DISPLAYLEVEL(6, "Sending %u bytes to compress (stableSrc:%u) \n",
1204
                                (unsigned)iSize, cOptions.stableSrc);
1205

1206
#if 1
1207
                /* insert uncompressed segment */
1208
                if ( (iSize>0)
1209
                  && !neverFlush   /* do not mess with compressBound when neverFlush is set */
1210
                  && prefsPtr != NULL   /* prefs are set */
1211
                  && prefs.frameInfo.blockMode == LZ4F_blockIndependent  /* uncompressedUpdate is only valid with blockMode==independent */
1212
                  && (FUZ_rand(&randState) & 15) == 1 ) {
1213
                    size_t const uSize = FUZ_rand(&randState) % iSize;
1214
                    size_t const flushedSize = LZ4F_uncompressedUpdate(cCtx, op, (size_t)(oend-op), ip, uSize, &cOptions);
1215
                    CHECK(LZ4F_isError(flushedSize), "Insert uncompressed data failed (error %i : %s)",
1216
                            (int)flushedSize, LZ4F_getErrorName(flushedSize));
1217
                    op += flushedSize;
1218
                    ip += uSize;
1219
                    iSize -= uSize;
1220
                }
1221
#endif
1222

1223
                {   size_t const flushedSize = LZ4F_compressUpdate(cCtx, op, oSize, ip, iSize, &cOptions);
1224
                    CHECK(LZ4F_isError(flushedSize), "Compression failed (error %i : %s)",
1225
                            (int)flushedSize, LZ4F_getErrorName(flushedSize));
1226
                    op += flushedSize;
1227
                    ip += iSize;
1228
                }
1229

1230
                {   unsigned const forceFlush = neverFlush ? 0 : ((FUZ_rand(&randState) & 3) == 1);
1231
                    if (forceFlush) {
1232
                        size_t const flushSize = LZ4F_flush(cCtx, op, (size_t)(oend-op), &cOptions);
1233
                        DISPLAYLEVEL(6,"flushing %u bytes \n", (unsigned)flushSize);
1234
                        CHECK(LZ4F_isError(flushSize), "Compression failed (error %i)", (int)flushSize);
1235
                        op += flushSize;
1236
                        if ((FUZ_rand(&randState) % 1024) == 3) {
1237
                            /* add an empty block (requires uncompressed flag) */
1238
                            op[0] = op[1] = op[2] = 0;
1239
                            op[3] = 0x80; /* 0x80000000U in little-endian format */
1240
                            op += 4;
1241
                            if ((prefsPtr!= NULL) && prefsPtr->frameInfo.blockChecksumFlag) {
1242
                                /* add block checksum (even for empty blocks) */
1243
                                FUZ_writeLE32(op, XXH32(op, 0, 0));
1244
                                op += 4;
1245
                }   }   }   }
1246
            }  /* while (ip<iend) */
1247
            CHECK(op>=oend, "LZ4F_compressFrameBound overflow");
1248
            {   size_t const dstEndSafeSize = LZ4F_compressBound(0, prefsPtr);
1249
                int const tooSmallDstEnd = ((FUZ_rand(&randState) & 31) == 3);
1250
                size_t const dstEndTooSmallSize = (FUZ_rand(&randState) % dstEndSafeSize) + 1;
1251
                size_t const dstEndSize = tooSmallDstEnd ? dstEndTooSmallSize : dstEndSafeSize;
1252
                BYTE const canaryByte = (BYTE)(FUZ_rand(&randState) & 255);
1253
                size_t flushedSize;
1254
                DISPLAYLEVEL(7,"canaryByte at pos %u / %u \n",
1255
                            (unsigned)((size_t)(op - (BYTE*)compressedBuffer) + dstEndSize),
1256
                            (unsigned)compressedBufferSize);
1257
                assert(op + dstEndSize < (BYTE*)compressedBuffer + compressedBufferSize);
1258
                op[dstEndSize] = canaryByte;
1259
                flushedSize = LZ4F_compressEnd(cCtx, op, dstEndSize, &cOptions);
1260
                CHECK(op[dstEndSize] != canaryByte, "LZ4F_compressEnd writes beyond dstCapacity !");
1261
                if (LZ4F_isError(flushedSize)) {
1262
                    if (tooSmallDstEnd) /* failure is allowed */ continue;
1263
                    CHECK(!tooSmallDstEnd, "Compression completion failed (error %i : %s)",
1264
                            (int)flushedSize, LZ4F_getErrorName(flushedSize));
1265
                }
1266
                op += flushedSize;
1267
            }
1268
            cSize = (size_t)(op - (BYTE*)compressedBuffer);
1269
            DISPLAYLEVEL(5, "\nCompressed %u bytes into %u \n", (U32)srcSize, (U32)cSize);
1270
        }
1271

1272

1273
        /* multi-segments decompression */
1274
        DISPLAYLEVEL(6, "normal decompression \n");
1275
        {   size_t result = test_lz4f_decompression(compressedBuffer, cSize, srcStart, srcSize, crcOrig, &randState, dCtx, seed, testNb, 1 /*findError*/ );
1276
            CHECK (LZ4F_isError(result), "multi-segment decompression failed (error %i => %s)",
1277
                                        (int)result, LZ4F_getErrorName(result));
1278
        }
1279

1280
        /* insert noise into src - ensure decoder survives with no sanitizer error */
1281
        {   U32 const maxNbBits = FUZ_highbit((U32)cSize);
1282
            size_t pos = 0;
1283
            for (;;) {
1284
                /* keep some original src */
1285
                {   U32 const nbBits = FUZ_rand(&randState) % maxNbBits;
1286
                    size_t const mask = (1<<nbBits) - 1;
1287
                    size_t const skipLength = FUZ_rand(&randState) & mask;
1288
                    pos += skipLength;
1289
                }
1290
                if (pos >= cSize) break;
1291
                /* add noise */
1292
                {   U32 const nbBitsCodes = FUZ_rand(&randState) % maxNbBits;
1293
                    U32 const nbBits = nbBitsCodes ? nbBitsCodes-1 : 0;
1294
                    size_t const mask = (1<<nbBits) - 1;
1295
                    size_t const rNoiseLength = (FUZ_rand(&randState) & mask) + 1;
1296
                    size_t const noiseLength = MIN(rNoiseLength, cSize-pos);
1297
                    size_t const noiseStart = FUZ_rand(&randState) % (CNBufferLength - noiseLength);
1298
                    memcpy((BYTE*)compressedBuffer + pos, (const char*)CNBuffer + noiseStart, noiseLength);
1299
                    pos += noiseLength;
1300
        }   }   }
1301

1302
        /* test decompression on noisy src */
1303
        DISPLAYLEVEL(6, "noisy decompression \n");
1304
        test_lz4f_decompression(compressedBuffer, cSize, srcStart, srcSize, crcOrig, &randState, dCtx, seed, testNb, 0 /*don't search error Pos*/ );
1305
        /* note : we don't analyze result here : it probably failed, which is expected.
1306
         * The sole purpose is to catch potential out-of-bound reads and writes. */
1307
        LZ4F_resetDecompressionContext(dCtx);  /* state must be reset to clean after an error */
1308

1309
    }   /* for ( ; (testNb < nbTests) ; ) */
1310

1311
    DISPLAYLEVEL(2, "\rAll tests completed   \n");
1312

1313
    LZ4F_freeDecompressionContext(dCtx);
1314
    LZ4F_freeCompressionContext(cCtx);
1315
    free(CNBuffer);
1316
    free(compressedBuffer);
1317
    free(decodedBuffer);
1318

1319
    if (use_pause) {
1320
        DISPLAY("press enter to finish \n");
1321
        (void)getchar();
1322
    }
1323
    return 0;
1324
}
1325

1326

1327
int FUZ_usage(const char* programName)
1328
{
1329
    DISPLAY( "Usage :\n");
1330
    DISPLAY( "      %s [args]\n", programName);
1331
    DISPLAY( "\n");
1332
    DISPLAY( "Arguments :\n");
1333
    DISPLAY( " -i#    : Nb of tests (default:%u) \n", nbTestsDefault);
1334
    DISPLAY( " -T#    : Duration of tests, in seconds (default: use Nb of tests) \n");
1335
    DISPLAY( " -s#    : Select seed (default:prompt user)\n");
1336
    DISPLAY( " -t#    : Select starting test number (default:0)\n");
1337
    DISPLAY( " -P#    : Select compressibility in %% (default:%i%%)\n", FUZ_COMPRESSIBILITY_DEFAULT);
1338
    DISPLAY( " -v     : verbose\n");
1339
    DISPLAY( " -h     : display help and exit\n");
1340
    return 0;
1341
}
1342

1343

1344
int main(int argc, const char** argv)
1345
{
1346
    U32 seed=0;
1347
    int seedset=0;
1348
    int argNb;
1349
    unsigned nbTests = nbTestsDefault;
1350
    unsigned testNb = 0;
1351
    int proba = FUZ_COMPRESSIBILITY_DEFAULT;
1352
    U32 duration=0;
1353
    const char* const programName = argv[0];
1354

1355
    /* Check command line */
1356
    for (argNb=1; argNb<argc; argNb++) {
1357
        const char* argument = argv[argNb];
1358

1359
        if(!argument) continue;   /* Protection if argument empty */
1360

1361
        /* Decode command (note : aggregated short commands are allowed) */
1362
        if (argument[0]=='-') {
1363
            if (!strcmp(argument, "--no-prompt")) {
1364
                no_prompt=1;
1365
                seedset=1;
1366
                displayLevel=1;
1367
                continue;
1368
            }
1369
            argument++;
1370

1371
            while (*argument!=0) {
1372
                switch(*argument)
1373
                {
1374
                case 'h':
1375
                    return FUZ_usage(programName);
1376
                case 'v':
1377
                    argument++;
1378
                    displayLevel++;
1379
                    break;
1380
                case 'q':
1381
                    argument++;
1382
                    displayLevel--;
1383
                    break;
1384
                case 'p': /* pause at the end */
1385
                    argument++;
1386
                    use_pause = 1;
1387
                    break;
1388

1389
                case 'i':
1390
                    argument++;
1391
                    nbTests=0; duration=0;
1392
                    while ((*argument>='0') && (*argument<='9')) {
1393
                        nbTests *= 10;
1394
                        nbTests += (unsigned)(*argument - '0');
1395
                        argument++;
1396
                    }
1397
                    break;
1398

1399
                case 'T':
1400
                    argument++;
1401
                    nbTests = 0; duration = 0;
1402
                    for (;;) {
1403
                        switch(*argument)
1404
                        {
1405
                            case 'm': duration *= 60; argument++; continue;
1406
                            case 's':
1407
                            case 'n': argument++; continue;
1408
                            case '0':
1409
                            case '1':
1410
                            case '2':
1411
                            case '3':
1412
                            case '4':
1413
                            case '5':
1414
                            case '6':
1415
                            case '7':
1416
                            case '8':
1417
                            case '9': duration *= 10; duration += (U32)(*argument++ - '0'); continue;
1418
                        }
1419
                        break;
1420
                    }
1421
                    break;
1422

1423
                case 's':
1424
                    argument++;
1425
                    seed=0;
1426
                    seedset=1;
1427
                    while ((*argument>='0') && (*argument<='9')) {
1428
                        seed *= 10;
1429
                        seed += (U32)(*argument - '0');
1430
                        argument++;
1431
                    }
1432
                    break;
1433
                case 't':
1434
                    argument++;
1435
                    testNb=0;
1436
                    while ((*argument>='0') && (*argument<='9')) {
1437
                        testNb *= 10;
1438
                        testNb += (unsigned)(*argument - '0');
1439
                        argument++;
1440
                    }
1441
                    break;
1442
                case 'P':   /* compressibility % */
1443
                    argument++;
1444
                    proba=0;
1445
                    while ((*argument>='0') && (*argument<='9')) {
1446
                        proba *= 10;
1447
                        proba += *argument - '0';
1448
                        argument++;
1449
                    }
1450
                    if (proba<0) proba=0;
1451
                    if (proba>100) proba=100;
1452
                    break;
1453
                default:
1454
                    ;
1455
                    return FUZ_usage(programName);
1456
                }
1457
            }
1458
        } /* if (argument[0]=='-') */
1459
    } /* for (argNb=1; argNb<argc; argNb++) */
1460

1461
    DISPLAY("Starting lz4frame tester (%i-bits, %s) \n", (int)(sizeof(size_t)*8), LZ4_VERSION_STRING);
1462

1463
    /* Select a random seed if none given */
1464
    if (!seedset) {
1465
        time_t const t = time(NULL);
1466
        U32 const h = XXH32(&t, sizeof(t), 1);
1467
        seed = h % 10000;
1468
    }
1469
    DISPLAY("Seed = %u \n", seed);
1470
    if (proba != FUZ_COMPRESSIBILITY_DEFAULT)
1471
        DISPLAY("Compressibility : %i%% \n", proba);
1472

1473
    {   double const compressibility = (double)proba / 100;
1474
        /* start by unit tests if not requesting a specific run nb */
1475
        if (testNb==0) {
1476
            if (unitTests(seed, compressibility))
1477
                return 1;
1478
        }
1479

1480
        nbTests += (nbTests==0);  /* avoid zero */
1481
        return fuzzerTests(seed, nbTests, testNb, compressibility, duration);
1482
    }
1483
}
1484

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.