1/** 2 * This fuzz target performs a lz4 round-trip test (compress & decompress), 3 * compares the result with the original, and calls abort() on corruption. 4 */ 5 6#include <stddef.h> 7#include <stdint.h> 8#include <stdlib.h> 9#include <string.h> 10 11#include "fuzz_data_producer.h" 12#include "fuzz_helpers.h" 13#include "lz4.h" 14#include "lz4_helpers.h" 15#include "lz4frame.h" 16#include "lz4frame_static.h" 17 18static void decompress(LZ4F_dctx *dctx, void *src, void *dst, 19 size_t dstCapacity, size_t readSize) { 20 size_t ret = 1; 21 const void *srcPtr = (const char *) src; 22 void *dstPtr = (char *) dst; 23 const void *const srcEnd = (const char *) srcPtr + readSize; 24 25 while (ret != 0) { 26 while (srcPtr < srcEnd && ret != 0) { 27 /* Any data within dst has been flushed at this stage */ 28 size_t dstSize = dstCapacity; 29 size_t srcSize = (const char *) srcEnd - (const char *) srcPtr; 30 ret = LZ4F_decompress(dctx, dstPtr, &dstSize, srcPtr, &srcSize, 31 /* LZ4F_decompressOptions_t */ NULL); 32 FUZZ_ASSERT(!LZ4F_isError(ret)); 33 34 /* Update input */ 35 srcPtr = (const char *) srcPtr + srcSize; 36 dstPtr = (char *) dstPtr + dstSize; 37 } 38 39 FUZZ_ASSERT(srcPtr <= srcEnd); 40 } 41} 42 43static void compress_round_trip(const uint8_t *data, size_t size, 44 FUZZ_dataProducer_t *producer, LZ4F_preferences_t const prefs) { 45 46 // Choose random uncompressed offset start and end by producing seeds from random data, calculate the remaining 47 // data size that will be used for compression later and use the seeds to actually calculate the offsets 48 size_t const uncompressedOffsetSeed = FUZZ_dataProducer_retrieve32(producer); 49 size_t const uncompressedEndOffsetSeed = FUZZ_dataProducer_retrieve32(producer); 50 size = FUZZ_dataProducer_remainingBytes(producer); 51 52 size_t const uncompressedOffset = FUZZ_getRange_from_uint32(uncompressedOffsetSeed, 0, size); 53 size_t const uncompressedEndOffset = FUZZ_getRange_from_uint32(uncompressedEndOffsetSeed, uncompressedOffset, size); 54 size_t const uncompressedSize = uncompressedEndOffset - uncompressedOffset; 55 FUZZ_ASSERT(uncompressedOffset <= uncompressedEndOffset); 56 FUZZ_ASSERT(uncompressedEndOffset <= size); 57 58 const uint8_t *const uncompressedData = data + uncompressedOffset; 59 60 size_t const dstCapacity = 61 LZ4F_compressFrameBound(LZ4_compressBound(size), &prefs) + 62 uncompressedSize; 63 char *const dst = (char *) malloc(dstCapacity); 64 size_t rtCapacity = dstCapacity; 65 char *const rt = (char *) malloc(rtCapacity); 66 67 FUZZ_ASSERT(dst); 68 FUZZ_ASSERT(rt); 69 70 /* Compression must succeed and round trip correctly. */ 71 LZ4F_compressionContext_t ctx; 72 size_t const ctxCreation = LZ4F_createCompressionContext(&ctx, LZ4F_VERSION); 73 FUZZ_ASSERT(!LZ4F_isError(ctxCreation)); 74 75 size_t const headerSize = LZ4F_compressBegin(ctx, dst, dstCapacity, &prefs); 76 FUZZ_ASSERT(!LZ4F_isError(headerSize)); 77 size_t compressedSize = headerSize; 78 79 /* Compress data before uncompressed offset */ 80 size_t lz4Return = LZ4F_compressUpdate(ctx, dst + compressedSize, dstCapacity, 81 data, uncompressedOffset, NULL); 82 FUZZ_ASSERT(!LZ4F_isError(lz4Return)); 83 compressedSize += lz4Return; 84 85 /* Add uncompressed data */ 86 lz4Return = LZ4F_uncompressedUpdate(ctx, dst + compressedSize, dstCapacity, 87 uncompressedData, uncompressedSize, NULL); 88 FUZZ_ASSERT(!LZ4F_isError(lz4Return)); 89 compressedSize += lz4Return; 90 91 /* Compress data after uncompressed offset */ 92 lz4Return = LZ4F_compressUpdate(ctx, dst + compressedSize, dstCapacity, 93 data + uncompressedEndOffset, 94 size - uncompressedEndOffset, NULL); 95 FUZZ_ASSERT(!LZ4F_isError(lz4Return)); 96 compressedSize += lz4Return; 97 98 /* Finish compression */ 99 lz4Return = LZ4F_compressEnd(ctx, dst + compressedSize, dstCapacity, NULL); 100 FUZZ_ASSERT(!LZ4F_isError(lz4Return)); 101 compressedSize += lz4Return; 102 103 LZ4F_decompressOptions_t opts; 104 memset(&opts, 0, sizeof(opts)); 105 opts.stableDst = 1; 106 LZ4F_dctx *dctx; 107 LZ4F_createDecompressionContext(&dctx, LZ4F_VERSION); 108 FUZZ_ASSERT(dctx); 109 110 decompress(dctx, dst, rt, rtCapacity, compressedSize); 111 112 LZ4F_freeDecompressionContext(dctx); 113 114 FUZZ_ASSERT_MSG(!memcmp(data, rt, size), "Corruption!"); 115 116 free(dst); 117 free(rt); 118 119 FUZZ_dataProducer_free(producer); 120 LZ4F_freeCompressionContext(ctx); 121} 122 123static void compress_independent_block_mode(const uint8_t *data, size_t size) { 124 FUZZ_dataProducer_t *producer = FUZZ_dataProducer_create(data, size); 125 LZ4F_preferences_t prefs = FUZZ_dataProducer_preferences(producer); 126 prefs.frameInfo.blockMode = LZ4F_blockIndependent; 127 compress_round_trip(data, size, producer, prefs); 128} 129 130 131int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { 132 compress_independent_block_mode(data, size); 133 return 0; 134} 135