Skip to content

test(fuzz): libFuzzer harness for the v4 colblock decoder (+ 2 UB fixes it found)#84

Merged
balwierz merged 1 commit into
mainfrom
test/fuzz-colblock
Jul 10, 2026
Merged

test(fuzz): libFuzzer harness for the v4 colblock decoder (+ 2 UB fixes it found)#84
balwierz merged 1 commit into
mainfrom
test/fuzz-colblock

Conversation

@balwierz

Copy link
Copy Markdown
Owner

Summary

The other half of the systemic memory-safety pair (after the ASan/UBSan gate in #80): a libFuzzer harness over decode_colblock — the LociSSD v4 codec decoder that reads attacker-controlled offsets/lengths out of a decompressed chunk (the class hardened in #71). It fuzzes the pure function directly (no per-iteration file I/O), so coverage of every codec path (RAW / DELTA / LENGTH / DICT / FRONTCODE / ARENA / BOOL + the null-bitmap prefix) is high and fast (~150k exec/s).

  • tests/fuzz/fuzz_colblock.cpp + -DVV_BUILD_FUZZERS=ON (clang), reusing vv's exact reader-dep link list.
  • decode_colblock is now non-static (declared in include/vv/vvfuzz.hppnot the public reader surface).
  • A 24.04 CI step builds it with clang and runs a 45 s deterministic smoke under ASan+UBSan (a clean tree survives far more iterations, so it's not flaky).

Bugs it found (both fixed, both crafted-file-reachable)

  1. Empty block (n_rows = 0)AppendValues/memcpy were handed the null data() of an empty vector → UB (null pointer passed as argument 2 ... declared never null). Skip the zero-length append.
  2. DELTA/LENGTH cumsum int64 overflow — coordinate reconstruction accumulated in int64, so adversarial deltas overflowed (signed overflow is UB). Accumulate in uint64 (defined wraparound).

Verification

🤖 Generated with Claude Code

…es it found)

Add a libFuzzer harness (tests/fuzz/fuzz_colblock.cpp, VV_BUILD_FUZZERS CMake
option, clang) that fuzzes decode_colblock() directly — the LociSSD v4 codec
decoder that reads attacker-controlled offsets/lengths out of a decompressed
chunk (the class hardened in #71). Fuzzing the pure function (no per-iteration
file I/O) gives high coverage of every codec path under ASan+UBSan. A 24.04 CI
step builds it with clang and runs a 45 s deterministic smoke.

It immediately found two undefined-behaviour bugs reachable via a crafted file,
both now fixed:
- Empty block (n_rows = 0): AppendValues / memcpy were handed the null data()
  of an empty vector — UB. Skip the zero-length append (the builder's Finish()
  yields the correct empty array).
- DELTA / LENGTH coordinate reconstruction accumulated in int64, so adversarial
  deltas overflowed (signed overflow is UB). Accumulate in uint64 (defined
  wraparound); legitimate bounded coordinates are unchanged.

decode_colblock is now non-static so the harness can call it (declared in
include/vv/vvfuzz.hpp — not the public reader surface). Legitimate v4/v4.1 output
is byte-identical; the decoder runs clean over 37 M fuzz iterations. Suite 375.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@balwierz
balwierz merged commit f528fd2 into main Jul 10, 2026
3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant