Coverage Report

Created: 2025-07-12 06:54

/src/zstd/tests/fuzz/raw_dictionary_round_trip.c
Line
Count
Source
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 performs a zstd round-trip test (compress & decompress) with
13
 * a raw content dictionary, compares the result with the original, and calls
14
 * abort() on corruption.
15
 */
16
17
#include <stddef.h>
18
#include <stdlib.h>
19
#include <stdio.h>
20
#include <string.h>
21
#include "fuzz_helpers.h"
22
#include "zstd_helpers.h"
23
#include "fuzz_data_producer.h"
24
#include "fuzz_third_party_seq_prod.h"
25
26
static ZSTD_CCtx *cctx = NULL;
27
static ZSTD_DCtx *dctx = NULL;
28
29
static size_t roundTripTest(void *result, size_t resultCapacity,
30
                            void *compressed, size_t compressedCapacity,
31
                            const void *src, size_t srcSize,
32
                            const void *dict, size_t dictSize,
33
                            FUZZ_dataProducer_t *producer)
34
43.2k
{
35
43.2k
    ZSTD_dictContentType_e const dictContentType = ZSTD_dct_rawContent;
36
43.2k
    int const refPrefix = FUZZ_dataProducer_uint32Range(producer, 0, 1) != 0;
37
43.2k
    size_t cSize;
38
39
43.2k
    FUZZ_setRandomParameters(cctx, srcSize, producer);
40
    /* Disable checksum so we can use sizes smaller than compress bound. */
41
43.2k
    FUZZ_ZASSERT(ZSTD_CCtx_setParameter(cctx, ZSTD_c_checksumFlag, 0));
42
43.2k
    if (refPrefix)
43
43.2k
        FUZZ_ZASSERT(ZSTD_CCtx_refPrefix_advanced(
44
31.5k
            cctx, dict, dictSize,
45
31.5k
            ZSTD_dct_rawContent));
46
31.5k
    else
47
43.2k
        FUZZ_ZASSERT(ZSTD_CCtx_loadDictionary_advanced(
48
43.2k
            cctx, dict, dictSize,
49
43.2k
            (ZSTD_dictLoadMethod_e)FUZZ_dataProducer_uint32Range(producer, 0, 1),
50
43.2k
            ZSTD_dct_rawContent));
51
43.2k
    cSize = ZSTD_compress2(cctx, compressed, compressedCapacity, src, srcSize);
52
43.2k
    FUZZ_ZASSERT(cSize);
53
54
43.2k
    if (refPrefix)
55
43.2k
        FUZZ_ZASSERT(ZSTD_DCtx_refPrefix_advanced(
56
31.5k
            dctx, dict, dictSize,
57
31.5k
            dictContentType));
58
31.5k
    else
59
43.2k
        FUZZ_ZASSERT(ZSTD_DCtx_loadDictionary_advanced(
60
43.2k
            dctx, dict, dictSize,
61
43.2k
            (ZSTD_dictLoadMethod_e)FUZZ_dataProducer_uint32Range(producer, 0, 1),
62
43.2k
            dictContentType));
63
43.2k
    {
64
43.2k
        size_t const ret = ZSTD_decompressDCtx(
65
43.2k
                dctx, result, resultCapacity, compressed, cSize);
66
43.2k
        return ret;
67
43.2k
    }
68
43.2k
}
69
70
int LLVMFuzzerTestOneInput(const uint8_t *src, size_t size)
71
70.3k
{
72
70.3k
    FUZZ_SEQ_PROD_SETUP();
73
74
    /* Give a random portion of src data to the producer, to use for
75
    parameter generation. The rest will be used for (de)compression */
76
70.3k
    FUZZ_dataProducer_t *producer = FUZZ_dataProducer_create(src, size);
77
70.3k
    size = FUZZ_dataProducer_reserveDataPrefix(producer);
78
79
70.3k
    uint8_t const* const srcBuf = src;
80
70.3k
    size_t const srcSize = FUZZ_dataProducer_uint32Range(producer, 0, size);
81
70.3k
    uint8_t const* const dictBuf = srcBuf + srcSize;
82
70.3k
    size_t const dictSize = size - srcSize;
83
70.3k
    size_t const decompSize = srcSize;
84
70.3k
    void* const decompBuf = FUZZ_malloc(decompSize);
85
70.3k
    size_t compSize = ZSTD_compressBound(srcSize);
86
70.3k
    void* compBuf;
87
    /* Half of the time fuzz with a 1 byte smaller output size.
88
     * This will still succeed because we force the checksum to be disabled,
89
     * giving us 4 bytes of overhead.
90
     */
91
70.3k
    compSize -= FUZZ_dataProducer_uint32Range(producer, 0, 1);
92
70.3k
    compBuf = FUZZ_malloc(compSize);
93
94
70.3k
    if (!cctx) {
95
70.3k
        cctx = ZSTD_createCCtx();
96
70.3k
        FUZZ_ASSERT(cctx);
97
70.3k
    }
98
70.3k
    if (!dctx) {
99
70.3k
        dctx = ZSTD_createDCtx();
100
70.3k
        FUZZ_ASSERT(dctx);
101
70.3k
    }
102
103
70.3k
    {
104
70.3k
        size_t const result =
105
70.3k
            roundTripTest(decompBuf, decompSize, compBuf, compSize, srcBuf, srcSize, dictBuf, dictSize, producer);
106
70.3k
        FUZZ_ZASSERT(result);
107
70.3k
        FUZZ_ASSERT_MSG(result == srcSize, "Incorrect regenerated size");
108
70.3k
        FUZZ_ASSERT_MSG(!FUZZ_memcmp(src, decompBuf, srcSize), "Corruption!");
109
70.3k
    }
110
70.3k
    free(decompBuf);
111
70.3k
    free(compBuf);
112
70.3k
    FUZZ_dataProducer_free(producer);
113
70.3k
#ifndef STATEFUL_FUZZING
114
70.3k
    ZSTD_freeCCtx(cctx); cctx = NULL;
115
70.3k
    ZSTD_freeDCtx(dctx); dctx = NULL;
116
70.3k
#endif
117
70.3k
    FUZZ_SEQ_PROD_TEARDOWN();
118
70.3k
    return 0;
119
70.3k
}