Coverage Report

Created: 2025-08-09 07:03

/src/zstd/tests/fuzz/decompress_cross_format.c
Line
Count
Source (jump to first uncovered line)
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
// This fuzz target validates decompression of magicless-format compressed data.
12
13
#include <stddef.h>
14
#include <stdlib.h>
15
#include <stdio.h>
16
#include <string.h>
17
#include "fuzz_helpers.h"
18
#define ZSTD_STATIC_LINKING_ONLY
19
#include "zstd.h"
20
#include "fuzz_data_producer.h"
21
22
static ZSTD_DCtx *dctx = NULL;
23
24
int LLVMFuzzerTestOneInput(const uint8_t *src, size_t size)
25
5.43k
{
26
    // Give a random portion of src data to the producer, to use for parameter generation.
27
    // The rest will be interpreted as magicless compressed data.
28
5.43k
    FUZZ_dataProducer_t *producer = FUZZ_dataProducer_create(src, size);
29
5.43k
    size_t magiclessSize = FUZZ_dataProducer_reserveDataPrefix(producer);
30
5.43k
    const uint8_t* const magiclessSrc = src;
31
5.43k
    size_t const dstSize = FUZZ_dataProducer_uint32Range(producer, 0, 10 * size);
32
5.43k
    uint8_t* const standardDst = (uint8_t*)FUZZ_malloc(dstSize);
33
5.43k
    uint8_t* const magiclessDst = (uint8_t*)FUZZ_malloc(dstSize);
34
35
    // Create standard-format src from magicless-format src
36
5.43k
    const uint32_t zstd_magic = ZSTD_MAGICNUMBER;
37
5.43k
    size_t standardSize = sizeof(zstd_magic) + magiclessSize;
38
5.43k
    uint8_t* const standardSrc = (uint8_t*)FUZZ_malloc(standardSize);
39
5.43k
    memcpy(standardSrc, &zstd_magic, sizeof(zstd_magic)); // assume fuzzing on little-endian machine
40
5.43k
    memcpy(standardSrc + sizeof(zstd_magic), magiclessSrc, magiclessSize);
41
42
    // Truncate to a single frame
43
5.43k
    {
44
5.43k
        const size_t standardFrameCompressedSize = ZSTD_findFrameCompressedSize(standardSrc, standardSize);
45
5.43k
        if (ZSTD_isError(standardFrameCompressedSize)) {
46
228
            goto cleanup_and_return;
47
228
        }
48
5.20k
        standardSize = standardFrameCompressedSize;
49
5.20k
        magiclessSize = standardFrameCompressedSize - sizeof(zstd_magic);
50
5.20k
    }
51
52
    // Create DCtx if needed
53
5.20k
    if (!dctx) {
54
5.20k
        dctx = ZSTD_createDCtx();
55
5.20k
        FUZZ_ASSERT(dctx);
56
5.20k
    }
57
58
    // Test one-shot decompression
59
5.20k
    {
60
5.20k
        FUZZ_ZASSERT(ZSTD_DCtx_reset(dctx, ZSTD_reset_session_and_parameters));
61
5.20k
        FUZZ_ZASSERT(ZSTD_DCtx_setParameter(dctx, ZSTD_d_format, ZSTD_f_zstd1));
62
5.20k
        const size_t standardRet = ZSTD_decompressDCtx(
63
5.20k
                                        dctx, standardDst, dstSize, standardSrc, standardSize);
64
65
5.20k
        FUZZ_ZASSERT(ZSTD_DCtx_reset(dctx, ZSTD_reset_session_and_parameters));
66
5.20k
        FUZZ_ZASSERT(ZSTD_DCtx_setParameter(dctx, ZSTD_d_format, ZSTD_f_zstd1_magicless));
67
5.20k
        const size_t magiclessRet = ZSTD_decompressDCtx(
68
5.20k
                                        dctx, magiclessDst, dstSize, magiclessSrc, magiclessSize);
69
70
        // Standard accepts => magicless should accept
71
5.20k
        if (!ZSTD_isError(standardRet)) FUZZ_ZASSERT(magiclessRet);
72
73
        // Magicless accepts => standard should accept
74
        // NOTE: this is nice-to-have, please disable this check if it is difficult to satisfy.
75
5.20k
        if (!ZSTD_isError(magiclessRet)) FUZZ_ZASSERT(standardRet);
76
77
        // If both accept, decompressed size and data should match
78
5.20k
        if (!ZSTD_isError(standardRet) && !ZSTD_isError(magiclessRet)) {
79
243
            FUZZ_ASSERT(standardRet == magiclessRet);
80
243
            if (standardRet > 0) {
81
138
                FUZZ_ASSERT(
82
138
                    memcmp(standardDst, magiclessDst, standardRet) == 0
83
138
                );
84
138
            }
85
243
        }
86
5.20k
    }
87
88
    // Test streaming decompression
89
5.20k
    {
90
5.20k
        ZSTD_inBuffer standardIn = { standardSrc, standardSize, 0 };
91
5.20k
        ZSTD_inBuffer magiclessIn = { magiclessSrc, magiclessSize, 0 };
92
5.20k
        ZSTD_outBuffer standardOut = { standardDst, dstSize, 0 };
93
5.20k
        ZSTD_outBuffer magiclessOut = { magiclessDst, dstSize, 0 };
94
95
5.20k
        FUZZ_ZASSERT(ZSTD_DCtx_reset(dctx, ZSTD_reset_session_and_parameters));
96
5.20k
        FUZZ_ZASSERT(ZSTD_DCtx_setParameter(dctx, ZSTD_d_format, ZSTD_f_zstd1));
97
5.20k
        const size_t standardRet = ZSTD_decompressStream(dctx, &standardOut, &standardIn);
98
99
5.20k
        FUZZ_ZASSERT(ZSTD_DCtx_reset(dctx, ZSTD_reset_session_and_parameters));
100
5.20k
        FUZZ_ZASSERT(ZSTD_DCtx_setParameter(dctx, ZSTD_d_format, ZSTD_f_zstd1_magicless));
101
5.20k
        const size_t magiclessRet = ZSTD_decompressStream(dctx, &magiclessOut, &magiclessIn);
102
103
        // Standard accepts => magicless should accept
104
5.20k
        if (standardRet == 0) FUZZ_ASSERT(magiclessRet == 0);
105
106
        // Magicless accepts => standard should accept
107
        // NOTE: this is nice-to-have, please disable this check if it is difficult to satisfy.
108
5.20k
        if (magiclessRet == 0) FUZZ_ASSERT(standardRet == 0);
109
110
        // If both accept, decompressed size and data should match
111
5.20k
        if (standardRet == 0 && magiclessRet == 0) {
112
426
            FUZZ_ASSERT(standardOut.pos == magiclessOut.pos);
113
426
            if (standardOut.pos > 0) {
114
176
                FUZZ_ASSERT(
115
176
                    memcmp(standardOut.dst, magiclessOut.dst, standardOut.pos) == 0
116
176
                );
117
176
            }
118
426
        }
119
5.20k
    }
120
121
5.43k
cleanup_and_return:
122
5.43k
#ifndef STATEFUL_FUZZING
123
5.43k
    ZSTD_freeDCtx(dctx); dctx = NULL;
124
5.43k
#endif
125
5.43k
    free(standardSrc);
126
5.43k
    free(standardDst);
127
5.43k
    free(magiclessDst);
128
5.43k
    FUZZ_dataProducer_free(producer);
129
5.43k
    return 0;
130
5.20k
}