1 /* 2 * Copyright (c) Meta Platforms, Inc. and affiliates. 3 * All rights reserved. 4 * 5 * This source code is licensed under both the BSD-style license (found in the 6 * LICENSE file in the root directory of this source tree) and the GPLv2 (found 7 * in the COPYING file in the root directory of this source tree). 8 * You may select, at your option, one of the above-listed licenses. 9 */ 10 11 /** 12 * This fuzz target makes sure that whenever a compression dictionary can be 13 * loaded, the data can be round tripped. 14 */ 15 16 #include <stddef.h> 17 #include <stdlib.h> 18 #include <stdio.h> 19 #include <string.h> 20 #include "fuzz_helpers.h" 21 #include "zstd_helpers.h" 22 #include "fuzz_data_producer.h" 23 #include "fuzz_third_party_seq_prod.h" 24 25 /** 26 * Compresses the data and returns the compressed size or an error. 27 */ 28 static size_t compress(void* compressed, size_t compressedCapacity, 29 void const* source, size_t sourceSize, 30 void const* dict, size_t dictSize, 31 ZSTD_dictLoadMethod_e dictLoadMethod, 32 ZSTD_dictContentType_e dictContentType, 33 int const refPrefix) 34 { 35 ZSTD_CCtx* cctx = ZSTD_createCCtx(); 36 if (refPrefix) 37 FUZZ_ZASSERT(ZSTD_CCtx_refPrefix_advanced( 38 cctx, dict, dictSize, dictContentType)); 39 else 40 FUZZ_ZASSERT(ZSTD_CCtx_loadDictionary_advanced( 41 cctx, dict, dictSize, dictLoadMethod, dictContentType)); 42 size_t const compressedSize = ZSTD_compress2( 43 cctx, compressed, compressedCapacity, source, sourceSize); 44 ZSTD_freeCCtx(cctx); 45 return compressedSize; 46 } 47 48 static size_t decompress(void* result, size_t resultCapacity, 49 void const* compressed, size_t compressedSize, 50 void const* dict, size_t dictSize, 51 ZSTD_dictLoadMethod_e dictLoadMethod, 52 ZSTD_dictContentType_e dictContentType, 53 int const refPrefix) 54 { 55 ZSTD_DCtx* dctx = ZSTD_createDCtx(); 56 if (refPrefix) 57 FUZZ_ZASSERT(ZSTD_DCtx_refPrefix_advanced( 58 dctx, dict, dictSize, dictContentType)); 59 else 60 FUZZ_ZASSERT(ZSTD_DCtx_loadDictionary_advanced( 61 dctx, dict, dictSize, dictLoadMethod, dictContentType)); 62 size_t const resultSize = ZSTD_decompressDCtx( 63 dctx, result, resultCapacity, compressed, compressedSize); 64 FUZZ_ZASSERT(resultSize); 65 ZSTD_freeDCtx(dctx); 66 return resultSize; 67 } 68 69 int LLVMFuzzerTestOneInput(const uint8_t *src, size_t size) 70 { 71 FUZZ_SEQ_PROD_SETUP(); 72 FUZZ_dataProducer_t *producer = FUZZ_dataProducer_create(src, size); 73 int const refPrefix = FUZZ_dataProducer_uint32Range(producer, 0, 1) != 0; 74 ZSTD_dictLoadMethod_e const dlm = 75 size = FUZZ_dataProducer_uint32Range(producer, 0, 1); 76 ZSTD_dictContentType_e const dct = 77 FUZZ_dataProducer_uint32Range(producer, 0, 2); 78 size = FUZZ_dataProducer_remainingBytes(producer); 79 80 DEBUGLOG(2, "Dict load method %d", dlm); 81 DEBUGLOG(2, "Dict content type %d", dct); 82 DEBUGLOG(2, "Dict size %u", (unsigned)size); 83 84 void* const rBuf = FUZZ_malloc(size); 85 size_t const cBufSize = ZSTD_compressBound(size); 86 void* const cBuf = FUZZ_malloc(cBufSize); 87 88 size_t const cSize = 89 compress(cBuf, cBufSize, src, size, src, size, dlm, dct, refPrefix); 90 /* compression failing is okay */ 91 if (ZSTD_isError(cSize)) { 92 FUZZ_ASSERT_MSG(dct != ZSTD_dct_rawContent, "Raw must always succeed!"); 93 goto out; 94 } 95 size_t const rSize = 96 decompress(rBuf, size, cBuf, cSize, src, size, dlm, dct, refPrefix); 97 FUZZ_ASSERT_MSG(rSize == size, "Incorrect regenerated size"); 98 FUZZ_ASSERT_MSG(!FUZZ_memcmp(src, rBuf, size), "Corruption!"); 99 100 out: 101 free(cBuf); 102 free(rBuf); 103 FUZZ_dataProducer_free(producer); 104 FUZZ_SEQ_PROD_TEARDOWN(); 105 return 0; 106 } 107