Skip to content

Fuzzing Crash: VortexError in file_io #7004

@github-actions

Description

@github-actions

Fuzzing Crash Report

Analysis

Crash Location: vortex-array/src/scalar/validate.rs:59:validate

Error Message:

unable to construct a decimal `Scalar`:
  Other error: decimal value decimal256(-16999999999999999999999999999999999999999999999999999999999999999999999999983) does not fit in precision of decimal(76,-74)
Stack Trace
stack backtrace:
   0: __rustc::rust_begin_unwind
             at /rustc/db3e99bbab28c6ca778b13222becdea54533d908/library/std/src/panicking.rs:689:5
   1: core::panicking::panic_fmt
             at /rustc/db3e99bbab28c6ca778b13222becdea54533d908/library/core/src/panicking.rs:80:14
   2: panic_display<vortex_error::VortexError>
             at /rustc/db3e99bbab28c6ca778b13222becdea54533d908/library/core/src/panicking.rs:259:5
   3: {closure#1}<vortex_array::scalar::Scalar, vortex_error::VortexError>
             at ./vortex-error/src/lib.rs:500:9
   4: unwrap_or_else<vortex_array::scalar::Scalar, vortex_error::VortexError, vortex_error::{impl#11}::vortex_expect::{closure_env#1}<vortex_array::scalar::Scalar, vortex_error::VortexError>>
             at /rustc/db3e99bbab28c6ca778b13222becdea54533d908/library/core/src/result.rs:1622:23
   5: vortex_expect<vortex_array::scalar::Scalar, vortex_error::VortexError>
             at ./vortex-error/src/lib.rs:340:14
   6: decimal
             at ./vortex-array/src/scalar/constructor.rs:61:10
   7: flush
             at ./vortex-array/src/aggregate_fn/fns/sum/mod.rs:194:17
   8: flush<vortex_array::aggregate_fn::fns::sum::Sum>
             at ./vortex-array/src/aggregate_fn/accumulator.rs:149:35
   9: finish<vortex_array::aggregate_fn::fns::sum::Sum>
             at ./vortex-array/src/aggregate_fn/accumulator.rs:165:28
  10: sum
             at ./vortex-array/src/aggregate_fn/fns/sum/mod.rs:52:22
  11: {closure#2}
             at ./vortex-array/src/stats/array.rs:164:25
  12: then<core::result::Result<vortex_array::scalar::Scalar, vortex_error::VortexError>, vortex_array::stats::array::{impl#3}::compute_stat::{closure_env#2}>
             at /rustc/db3e99bbab28c6ca778b13222becdea54533d908/library/core/src/bool.rs:66:24
  13: compute_stat
             at ./vortex-array/src/stats/array.rs:162:22
  14: push_chunk
             at ./vortex-layout/src/layouts/zoned/zone_map.rs:214:49
  15: process
             at ./vortex-layout/src/layouts/file_stats.rs:107:41
  16: {closure#0}
             at ./vortex-layout/src/layouts/file_stats.rs:38:36
  17: poll_next<core::result::Result<(vortex_layout::sequence::SequenceId, alloc::sync::Arc<dyn vortex_array::array::DynArray, alloc::alloc::Global>), vortex_error::VortexError>, core::pin::Pin<alloc::boxed::Box<(dyn vortex_layout::sequence::SequentialStream<Item=core::result::Result<(vortex_layout::sequence::SequenceId, alloc::sync::Arc<dyn vortex_array::array::DynArray, alloc::alloc::Global>), vortex_error::VortexError>> + core::marker::Send), alloc::alloc::Global>>, vortex_layout::layouts::file_stats::FileStatsAccumulator, core::future::ready::Ready<core::option::Option<core::result::Result<(vortex_layout::sequence::SequenceId, alloc::sync::Arc<dyn vortex_array::array::DynArray, alloc::alloc::Global>), vortex_error::VortexError>>>, vortex_layout::layouts::file_stats::accumulate_stats::{closure_env#0}>
             at /home/runner/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/futures-util-0.3.32/src/stream/stream/scan.rs:92:38
  18: poll_next<futures_util::stream::stream::scan::Scan<core::pin::Pin<alloc::boxed::Box<(dyn vortex_layout::sequence::SequentialStream<Item=core::result::Result<(vortex_layout::sequence::SequenceId, alloc::sync::Arc<dyn vortex_array::array::DynArray, alloc::alloc::Global>), vortex_error::VortexError>> + core::marker::Send), alloc::alloc::Global>>, vortex_layout::layouts::file_stats::FileStatsAccumulator, core::future::ready::Ready<core::option::Option<core::result::Result<(vortex_layout::sequence::SequenceId, alloc::sync::Arc<dyn vortex_array::array::DynArray, alloc::alloc::Global>), vortex_error::VortexError>>>, vortex_layout::layouts::file_stats::accumulate_stats::{closure_env#0}>>
             at ./vortex-layout/src/sequence.rs:311:48
  19: poll_next<alloc::boxed::Box<(dyn vortex_layout::sequence::SequentialStream<Item=core::result::Result<(vortex_layout::sequence::SequenceId, alloc::sync::Arc<dyn vortex_array::array::DynArray, alloc::alloc::Global>), vortex_error::VortexError>> + core::marker::Send), alloc::alloc::Global>>
   ... (234 more frames truncated)

Root Cause Analysis

The crash is a panic in vortex-array/src/scalar/validate.rs:59 when constructing a decimal Scalar whose value exceeds the allowed precision. During a sum aggregation over decimal-typed data, the Sum accumulator in sum/mod.rs:194 flushes an intermediate result that has overflowed the original decimal precision (76 digits with scale -74), producing a value too large to represent. The root cause is that the sum accumulator does not widen the decimal precision to accommodate the growing magnitude of partial sums, so sufficiently large or numerous inputs cause the result to exceed the input type's precision. The fix should either promote the accumulator's decimal type to a wider precision (e.g., always accumulate into the maximum-width decimal) or detect and handle overflow gracefully instead of panicking via vortex_expect.

Summary

Reproduce

cargo +nightly fuzz run -D --sanitizer=none file_io ./fuzz/artifacts/file_io/crash-0164570dfaa7bef3f85335192ff058bc4d4c6ebe -- -rss_limit_mb=0
Reproduction Steps
  1. Download the crash artifact: https://github.com/vortex-data/vortex/actions/runs/23223182092/artifacts/5977004189

  2. Assuming you download the zipfile to ~/Downloads, and your working directory is the repository root:

# Create the artifacts directory if you haven't already.
mkdir -p ./fuzz/artifacts

# Move the zipfile.
mv ~/Downloads/file_io-crash-artifacts.zip ./fuzz/artifacts/

# Unzip the zipfile.
unzip ./fuzz/artifacts/file_io-crash-artifacts.zip -d ./fuzz/artifacts/

# You can remove the zipfile now if you want to.
rm ./fuzz/artifacts/file_io-crash-artifacts.zip
  1. Reproduce the crash:
cargo +nightly fuzz run -D --sanitizer=none file_io ./fuzz/artifacts/file_io/crash-0164570dfaa7bef3f85335192ff058bc4d4c6ebe -- -rss_limit_mb=0

If you want a backtrace:

RUST_BACKTRACE=1 cargo +nightly fuzz run -D --sanitizer=none file_io ./fuzz/artifacts/file_io/crash-0164570dfaa7bef3f85335192ff058bc4d4c6ebe -- -rss_limit_mb=0
RUST_BACKTRACE=full cargo +nightly fuzz run -D --sanitizer=none file_io ./fuzz/artifacts/file_io/crash-0164570dfaa7bef3f85335192ff058bc4d4c6ebe -- -rss_limit_mb=0
Single command to get a backtrace
mkdir -p ./fuzz/artifacts
mv ~/Downloads/file_io-crash-artifacts.zip ./fuzz/artifacts/
unzip ./fuzz/artifacts/file_io-crash-artifacts.zip -d ./fuzz/artifacts/
rm ./fuzz/artifacts/file_io-crash-artifacts.zip
RUST_BACKTRACE=1 cargo +nightly fuzz run -D --sanitizer=none file_io ./fuzz/artifacts/file_io/crash-0164570dfaa7bef3f85335192ff058bc4d4c6ebe -- -rss_limit_mb=0

Auto-created by fuzzing workflow

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugA bug issuefuzzerIssues detected by the fuzzer

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions