Coverage Report

Created: 2025-11-09 06:43

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/zstd/tests/fuzz/huf_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),
13
 * compares the result with the original, and calls abort() on corruption.
14
 */
15
16
#include <stddef.h>
17
#include <stdlib.h>
18
#include <stdio.h>
19
#include <string.h>
20
#include "common/cpu.h"
21
#include "compress/hist.h"
22
#include "common/huf.h"
23
#include "fuzz_helpers.h"
24
#include "fuzz_data_producer.h"
25
#include "common/bits.h"
26
27
static size_t adjustTableLog(size_t tableLog, size_t maxSymbol)
28
4.87k
{
29
4.87k
    size_t const alphabetSize = maxSymbol + 1;
30
4.87k
    size_t minTableLog = ZSTD_highbit32(alphabetSize) + 1;
31
4.87k
    if ((alphabetSize & (alphabetSize - 1)) != 0) {
32
1.80k
        ++minTableLog;
33
1.80k
    }
34
4.87k
    assert(minTableLog <= 9);
35
4.87k
    if (tableLog < minTableLog)
36
2.05k
        return minTableLog;
37
2.82k
    else
38
2.82k
        return tableLog;
39
4.87k
}
40
41
int LLVMFuzzerTestOneInput(const uint8_t *src, size_t size)
42
4.90k
{
43
4.90k
    FUZZ_dataProducer_t *producer = FUZZ_dataProducer_create(src, size);
44
    /* Select random parameters: #streams, X1 or X2 decoding, bmi2 */
45
4.90k
    int const streams = FUZZ_dataProducer_int32Range(producer, 0, 1);
46
4.90k
    int const symbols = FUZZ_dataProducer_int32Range(producer, 0, 1);
47
4.90k
    int const flags = 0
48
4.90k
        | (ZSTD_cpuid_bmi2(ZSTD_cpuid()) && FUZZ_dataProducer_int32Range(producer, 0, 1) ? HUF_flags_bmi2 : 0)
49
4.90k
        | (FUZZ_dataProducer_int32Range(producer, 0, 1) ? HUF_flags_optimalDepth : 0)
50
4.90k
        | (FUZZ_dataProducer_int32Range(producer, 0, 1) ? HUF_flags_preferRepeat : 0)
51
4.90k
        | (FUZZ_dataProducer_int32Range(producer, 0, 1) ? HUF_flags_suspectUncompressible : 0)
52
4.90k
        | (FUZZ_dataProducer_int32Range(producer, 0, 1) ? HUF_flags_disableAsm : 0)
53
4.90k
        | (FUZZ_dataProducer_int32Range(producer, 0, 1) ? HUF_flags_disableFast : 0);
54
    /* Select a random cBufSize - it may be too small */
55
4.90k
    size_t const cBufSize = FUZZ_dataProducer_uint32Range(producer, 0, 4 * size);
56
    /* Select a random tableLog - we'll adjust it up later */
57
4.90k
    size_t tableLog = FUZZ_dataProducer_uint32Range(producer, 1, 12);
58
4.90k
    size_t const kMaxSize = 256 * 1024;
59
4.90k
    size = FUZZ_dataProducer_remainingBytes(producer);
60
4.90k
    if (size > kMaxSize)
61
37
        size = kMaxSize;
62
63
4.90k
    if (size <= 1) {
64
13
        FUZZ_dataProducer_free(producer);
65
13
        return 0;
66
13
    }
67
68
4.89k
    uint32_t maxSymbol = 255;
69
70
4.89k
    U32 count[256];
71
4.89k
    size_t const mostFrequent = HIST_count(count, &maxSymbol, src, size);
72
4.89k
    FUZZ_ZASSERT(mostFrequent);
73
4.89k
    if (mostFrequent == size) {
74
        /* RLE */
75
15
        FUZZ_dataProducer_free(producer);
76
15
        return 0;
77
78
15
    }
79
4.87k
    FUZZ_ASSERT(maxSymbol <= 255);
80
4.87k
    tableLog = adjustTableLog(tableLog, maxSymbol);
81
82
4.87k
    size_t const wkspSize = HUF_WORKSPACE_SIZE;
83
4.87k
    void* wksp = FUZZ_malloc(wkspSize);
84
4.87k
    void* rBuf = FUZZ_malloc(size);
85
4.87k
    void* cBuf = FUZZ_malloc(cBufSize);
86
4.87k
    HUF_CElt* ct = (HUF_CElt*)FUZZ_malloc(HUF_CTABLE_SIZE(maxSymbol));
87
4.87k
    HUF_DTable* dt = (HUF_DTable*)FUZZ_malloc(HUF_DTABLE_SIZE(tableLog) * sizeof(HUF_DTable));
88
4.87k
    dt[0] = tableLog * 0x01000001;
89
90
4.87k
    tableLog = HUF_optimalTableLog(tableLog, size, maxSymbol, wksp, wkspSize, ct, count, flags);
91
4.87k
    FUZZ_ASSERT(tableLog <= 12);
92
4.87k
    tableLog = HUF_buildCTable_wksp(ct, count, maxSymbol, tableLog, wksp, wkspSize);
93
4.87k
    FUZZ_ZASSERT(tableLog);
94
4.87k
    size_t const tableSize = HUF_writeCTable_wksp(cBuf, cBufSize, ct, maxSymbol, tableLog, wksp, wkspSize);
95
4.87k
    if (ERR_isError(tableSize)) {
96
        /* Errors on uncompressible data or cBufSize too small */
97
136
        goto _out;
98
136
    }
99
4.74k
    FUZZ_ZASSERT(tableSize);
100
4.74k
    if (symbols == 0) {
101
1.97k
        FUZZ_ZASSERT(HUF_readDTableX1_wksp(dt, cBuf, tableSize, wksp, wkspSize, flags));
102
2.76k
    } else {
103
2.76k
        size_t const ret = HUF_readDTableX2_wksp(dt, cBuf, tableSize, wksp, wkspSize, flags);
104
2.76k
        if (ERR_getErrorCode(ret) == ZSTD_error_tableLog_tooLarge) {
105
7
            FUZZ_ZASSERT(HUF_readDTableX1_wksp(dt, cBuf, tableSize, wksp, wkspSize, flags));
106
2.76k
        } else {
107
2.76k
            FUZZ_ZASSERT(ret);
108
2.76k
        }
109
2.76k
    }
110
111
4.74k
    size_t cSize;
112
4.74k
    size_t rSize;
113
4.74k
    if (streams == 0) {
114
1.45k
        cSize = HUF_compress1X_usingCTable(cBuf, cBufSize, src, size, ct, flags);
115
1.45k
        FUZZ_ZASSERT(cSize);
116
1.45k
        if (cSize != 0)
117
1.33k
            rSize = HUF_decompress1X_usingDTable(rBuf, size, cBuf, cSize, dt, flags);
118
3.28k
    } else {
119
3.28k
        cSize = HUF_compress4X_usingCTable(cBuf, cBufSize, src, size, ct, flags);
120
3.28k
        FUZZ_ZASSERT(cSize);
121
3.28k
        if (cSize != 0)
122
3.05k
            rSize = HUF_decompress4X_usingDTable(rBuf, size, cBuf, cSize, dt, flags);
123
3.28k
    }
124
4.74k
    if (cSize != 0) {
125
4.39k
        FUZZ_ZASSERT(rSize);
126
4.39k
        FUZZ_ASSERT_MSG(rSize == size, "Incorrect regenerated size");
127
4.39k
        FUZZ_ASSERT_MSG(!FUZZ_memcmp(src, rBuf, size), "Corruption!");
128
4.39k
    }
129
4.87k
_out:
130
4.87k
    free(rBuf);
131
4.87k
    free(cBuf);
132
4.87k
    free(ct);
133
4.87k
    free(dt);
134
4.87k
    free(wksp);
135
4.87k
    FUZZ_dataProducer_free(producer);
136
4.87k
    return 0;
137
4.74k
}