Skip to content

Fuzzing Crash: VortexError in array_ops #7200

@github-actions

Description

@github-actions

Fuzzing Crash Report

Analysis

Crash Location: vortex-array/src/patches.rs:680:slice

Error Message:

attempt to subtract with overflow
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: core::panicking::panic_const::panic_const_sub_overflow
             at /rustc/db3e99bbab28c6ca778b13222becdea54533d908/library/core/src/panicking.rs:175:17
   3: {closure#1}
             at ./vortex-array/src/patches.rs:680:20
   4: map<&alloc::sync::Arc<dyn vortex_array::array::DynArray, alloc::alloc::Global>, core::result::Result<usize, vortex_error::VortexError>, vortex_array::patches::{impl#1}::slice::{closure_env#1}>
             at /rustc/db3e99bbab28c6ca778b13222becdea54533d908/library/core/src/option.rs:1165:29
   5: slice
             at ./vortex-array/src/patches.rs:674:14
   6: {closure#0}
             at ./encodings/fastlanes/src/bitpacking/compute/slice.rs:35:32
   7: map<&vortex_array::patches::Patches, core::result::Result<core::option::Option<vortex_array::patches::Patches>, vortex_error::VortexError>, vortex_fastlanes::bitpacking::compute::slice::{impl#0}::slice::{closure_env#0}>
             at /rustc/db3e99bbab28c6ca778b13222becdea54533d908/library/core/src/option.rs:1165:29
   8: slice
             at ./encodings/fastlanes/src/bitpacking/compute/slice.rs:35:22
   9: reduce_parent<vortex_fastlanes::bitpacking::vtable::BitPacked>
             at ./vortex-array/src/arrays/slice/mod.rs:94:9
  10: reduce_parent<vortex_fastlanes::bitpacking::vtable::BitPacked, vortex_array::arrays::slice::SliceReduceAdaptor<vortex_fastlanes::bitpacking::vtable::BitPacked>>
             at ./vortex-array/src/optimizer/rules.rs:113:19
  11: evaluate<vortex_fastlanes::bitpacking::vtable::BitPacked>
             at ./vortex-array/src/optimizer/rules.rs:180:41
  12: reduce_parent
             at ./encodings/fastlanes/src/bitpacking/vtable/mod.rs:172:15
  13: reduce_parent<vortex_fastlanes::bitpacking::vtable::BitPacked>
             at ./vortex-array/src/vtable/dyn_.rs:146:29
  14: try_optimize
             at ./vortex-array/src/optimizer/mod.rs:58:53
  15: optimize
             at ./vortex-array/src/optimizer/mod.rs:29:12
  16: slice<vortex_fastlanes::bitpacking::vtable::BitPacked>
             at ./vortex-array/src/array/mod.rs:454:14
  17: slice
             at ./vortex-array/src/arrays/dict/compute/slice.rs:19:41
  18: reduce_parent<vortex_array::arrays::dict::vtable::Dict>
             at ./vortex-array/src/arrays/slice/mod.rs:94:9
  19: reduce_parent<vortex_array::arrays::dict::vtable::Dict, vortex_array::arrays::slice::SliceReduceAdaptor<vortex_array::arrays::dict::vtable::Dict>>
   ... (87 more frames truncated)

Root Cause Analysis

The crash is a subtraction overflow panic at patches.rs:680, where slice_start_idx is less than base_offset during a Patches::slice operation. This occurs when slicing a BitPacked array (via a Dict encoding) triggers the optimizer's slice reduction, and the chunk_offsets' first element (base_offset) ends up larger than the computed slice_start_idx, likely due to an off-by-one in chunk index calculation or an edge case where the slice range doesn't align with chunk boundaries. The fix should add a bounds check or use saturating_sub, or more precisely ensure that the chunk_start_idx calculation on line 666 correctly identifies the chunk containing slice_start_idx so that the base_offset retrieved from chunk_offsets is always <= slice_start_idx.

Summary

Reproduce

cargo +nightly fuzz run -D --sanitizer=none array_ops ./fuzz/artifacts/array_ops/crash-78a4bdcaa9ca8a1ae1d02c2b6dfa71c64b2319f3 -- -rss_limit_mb=0
Reproduction Steps
  1. Download the crash artifact: https://github.com/vortex-data/vortex/actions/runs/23695323317/artifacts/6161706342

  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/array_ops-crash-artifacts.zip ./fuzz/artifacts/

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

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

If you want a backtrace:

RUST_BACKTRACE=1 cargo +nightly fuzz run -D --sanitizer=none array_ops ./fuzz/artifacts/array_ops/crash-78a4bdcaa9ca8a1ae1d02c2b6dfa71c64b2319f3 -- -rss_limit_mb=0
RUST_BACKTRACE=full cargo +nightly fuzz run -D --sanitizer=none array_ops ./fuzz/artifacts/array_ops/crash-78a4bdcaa9ca8a1ae1d02c2b6dfa71c64b2319f3 -- -rss_limit_mb=0
Single command to get a backtrace
mkdir -p ./fuzz/artifacts
mv ~/Downloads/array_ops-crash-artifacts.zip ./fuzz/artifacts/
unzip ./fuzz/artifacts/array_ops-crash-artifacts.zip -d ./fuzz/artifacts/
rm ./fuzz/artifacts/array_ops-crash-artifacts.zip
RUST_BACKTRACE=1 cargo +nightly fuzz run -D --sanitizer=none array_ops ./fuzz/artifacts/array_ops/crash-78a4bdcaa9ca8a1ae1d02c2b6dfa71c64b2319f3 -- -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