Skip to content

Segfault in FSE_decompress_usingDTable during round-trip #123

@hgarrereyn

Description

@hgarrereyn

Hi, the following testcase sets up an encoder and decoder table for round-trip compression.

The compression side works fine, however it crashes in FSE_decompress_usingDTable while trying to decompress the data.

See the following testcase and crash report:

testcase.cpp

#include <cstdint>
#include <cstring>
#include <string>
#include <vector>
extern "C" {
#include "/fuzz/install/include/fse.h"
}
#include "gf_util.h"
int main() {
    const unsigned tableLog = 12;
    const unsigned maxSymbolValue = 255;
    // Allocate DTable for decoder
    FSE_DTable* dt = FSE_createDTable(tableLog);
    if (!dt) return 0;

    // Source data: 6 bytes of the same symbol (0x00)
    std::string src(6, '\0');

    // Build normalized counts from src
    std::vector<unsigned> count(maxSymbolValue + 1, 0u);
    for (unsigned char ch : src) count[(unsigned)ch]++;
    std::vector<short> ncount(maxSymbolValue + 1);
    size_t nr = FSE_normalizeCount(ncount.data(), tableLog, count.data(), src.size(), maxSymbolValue);
    if (FSE_isError(nr)) return 0;

    // Build matching decode and encode tables from the same ncount
    if (FSE_isError(FSE_buildDTable(dt, ncount.data(), maxSymbolValue, tableLog))) return 0;
    FSE_CTable* ct = FSE_createCTable(maxSymbolValue, tableLog);
    if (!ct) return 0;
    if (FSE_isError(FSE_buildCTable(ct, ncount.data(), maxSymbolValue, tableLog))) return 0;

    // Compress
    size_t bound = FSE_compressBound(src.size());
    std::string cbuf(bound, '\0');
    size_t cSize = FSE_compress_usingCTable(cbuf.data(), cbuf.size(), src.data(), src.size(), ct);
    FSE_freeCTable(ct);
    if (FSE_isError(cSize) || cSize == 0) return 0;

    // Decompress (crashes inside FSE_decompress_usingDTable_generic)
    std::string dst(src.size(), '\0');
    (void)FSE_decompress_usingDTable(dst.data(), dst.size(), cbuf.data(), cSize, dt);
    return 0;
}

crash report

{
  "Date": "2025-09-29T17:02:31.502178+00:00",
  "Uname": "Linux 518883e872c1 5.15.0-156-generic #166-Ubuntu SMP Sat Aug 9 00:02:46 UTC 2025 x86_64 x86_64 x86_64 GNU/Linux",
  "OS": "Ubuntu",
  "OSRelease": "22.04",
  "Architecture": "amd64",
  "ExecutablePath": "/tmp/tmp0oh_fri3/reproducer",
  "ProcEnviron": [
    "PREFIX=/fuzz/install",
    "LIBAFL_EDGES_MAP_SIZE=800000",
    "PWD=/fuzz/workspace",
    "CXX=gf_libafl_cxx",
    "GRAPHFUZZ_USE_ASAN=1",
    "HOME=/root",
    "ASAN_OPTIONS=hard_rss_limit_mb=1024:detect_leaks=0",
    "TERM=xterm-256color",
    "SHLVL=1",
    "LD_LIBRARY_PATH=/fuzz/install/lib",
    "PATH=/root/.cargo/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
    "CC=gf_libafl_cc",
    "DEBIAN_FRONTEND=noninteractive",
    "OLDPWD=/fuzz/src",
    "_=/usr/local/bin/agfi"
  ],
  "ProcCmdline": "/tmp/tmp0oh_fri3/reproducer",
  "Stdin": "",
  "ProcStatus": [],
  "ProcMaps": [],
  "ProcFiles": [],
  "NetworkConnections": [],
  "CrashSeverity": {
    "Type": "NOT_EXPLOITABLE",
    "ShortDescription": "SourceAv",
    "Description": "Access violation on source operand",
    "Explanation": "The target crashed on an access violation at an address matching the source operand of the current instruction. This likely indicates a read access violation."
  },
  "Stacktrace": [
    "    #0 0x55555566b4af in FSE_decompress_usingDTable_generic /fuzz/src/lib/fse_decompress.c:224:17",
    "    #1 0x55555566b4af in FSE_decompress_usingDTable /fuzz/src/lib/fse_decompress.c:250:26",
    "    #2 0x555555660501 in main /tmp/tmp0oh_fri3/reproducer.cpp:41:11",
    "    #3 0x7ffff7a6dd8f in __libc_start_call_main csu/../sysdeps/nptl/libc_start_call_main.h:58:16",
    "    #4 0x7ffff7a6de3f in __libc_start_main csu/../csu/libc-start.c:392:3",
    "    #5 0x555555581964 in _start (/tmp/tmp0oh_fri3/reproducer+0x2d964) (BuildId: d80293c6d7988f373ea77fdfaceff0f4bc1d0018)"
  ],
  "Registers": {},
  "Disassembly": [],
  "Package": "",
  "PackageVersion": "",
  "PackageArchitecture": "",
  "PackageDescription": "",
  "AsanReport": [
    "==155==ERROR: AddressSanitizer: SEGV on unknown address 0x52900003e204 (pc 0x55555566b4af bp 0x00000000f400 sp 0x7fffffffe970 T0)",
    "==155==The signal is caused by a READ memory access.",
    "    #0 0x55555566b4af in FSE_decompress_usingDTable_generic /fuzz/src/lib/fse_decompress.c:224:17",
    "    #1 0x55555566b4af in FSE_decompress_usingDTable /fuzz/src/lib/fse_decompress.c:250:26",
    "    #2 0x555555660501 in main /tmp/tmp0oh_fri3/reproducer.cpp:41:11",
    "    #3 0x7ffff7a6dd8f in __libc_start_call_main csu/../sysdeps/nptl/libc_start_call_main.h:58:16",
    "    #4 0x7ffff7a6de3f in __libc_start_main csu/../csu/libc-start.c:392:3",
    "    #5 0x555555581964 in _start (/tmp/tmp0oh_fri3/reproducer+0x2d964) (BuildId: d80293c6d7988f373ea77fdfaceff0f4bc1d0018)",
    "",
    "AddressSanitizer can not provide additional info.",
    "SUMMARY: AddressSanitizer: SEGV /fuzz/src/lib/fse_decompress.c:224:17 in FSE_decompress_usingDTable_generic",
    "==155==ABORTING"
  ],
  "MsanReport": [],
  "UbsanReport": [],
  "LuaReport": [],
  "PythonReport": [],
  "GoReport": [],
  "JavaReport": [],
  "RustReport": [],
  "JsReport": [],
  "CSharpReport": [],
  "CrashLine": "/fuzz/src/lib/fse_decompress.c:224:17",
  "Source": [
    "    220        /* tail */",
    "    221        /* note : BIT_reloadDStream(&bitD) >= FSE_DStream_partiallyFilled; Ends at exactly BIT_DStream_completed */",
    "    222        while (1) {",
    "    223            if (op>(omax-2)) return ERROR(dstSize_tooSmall);",
    "--->224            *op++ = FSE_GETSYMBOL(&state1);",
    "    225            if (BIT_reloadDStream(&bitD)==BIT_DStream_overflow) {",
    "    226                *op++ = FSE_GETSYMBOL(&state2);",
    "    227                break;",
    "    228            }",
    "    229    "
  ]
}

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions