Skip to content

Fuzzing Crash: VortexError in array_ops #6968

@github-actions

Description

@github-actions

Fuzzing Crash Report

Analysis

Crash Location: fuzz/fuzz_targets/array_ops.rs:33:assert_array_eq

Error Message:

Other error: Mismatch at step 3 at index 0
Expected scalar:
{: {: null, : "95 75 95 ff ff ff ff ff ff ff 0 3b 3b 3b"}, : null}
Actual scalar:
{: {: null, : "95 75 95 ff ff ff ff ff ff ff 0 3b 3b 3b"}, : {: null, : "95 75 95 ff ff ff ff ff ff ff 0 3b 3b 3b"}}
Expected tree:
root: vortex.struct({={=binary?, =binary?}?, ={=binary?, =binary?}?}?, len=11) nbytes=889 B (100.00%) [all_valid]
  metadata: EmptyMetadata
  : vortex.struct({=binary?, =binary?}?, len=11) nbytes=482 B (54.22%)
    metadata: EmptyMetadata
    validity: vortex.bool(bool, len=11) nbytes=2 B (0.41%) [nulls=0, min=false, max=true]
      metadata: BoolMetadata { offset: 0 }
      buffer: bits host 2 B (align=1) (100.00%)
    : vortex.varbinview(binary?, len=11) nbytes=246 B (51.04%)
      metadata: EmptyMetadata
      buffer: buffer_0 host 68 B (align=1) (27.64%)
      buffer: views host 176 B (align=16) (71.54%)
      validity: vortex.bool(bool, len=11) nbytes=2 B (0.81%) [nulls=0, min=false, max=true]
        metadata: BoolMetadata { offset: 0 }
        buffer: bits host 2 B (align=1) (100.00%)
    : vortex.varbinview(binary?, len=11) nbytes=234 B (48.55%)
      metadata: EmptyMetadata
      buffer: buffer_0 host 56 B (align=1) (23.93%)
      buffer: views host 176 B (align=16) (75.21%)
      validity: vortex.bool(bool, len=11) nbytes=2 B (0.85%) [nulls=0, min=false, max=true]
        metadata: BoolMetadata { offset: 0 }
        buffer: bits host 2 B (align=1) (100.00%)
  : vortex.struct({=binary?, =binary?}?, len=11) nbytes=407 B (45.78%)
    metadata: EmptyMetadata
    validity: vortex.bool(bool, len=11) nbytes=2 B (0.49%) [nulls=0, min=false, max=true]
      metadata: BoolMetadata { offset: 0 }
      buffer: bits host 2 B (align=1) (100.00%)
    : vortex.varbinview(binary?, len=11) nbytes=191 B (46.93%)
      metadata: EmptyMetadata
      buffer: buffer_0 host 13 B (align=1) (6.81%)
      buffer: views host 176 B (align=16) (92.15%)
      validity: vortex.bool(bool, len=11) nbytes=2 B (1.05%) [nulls=0, min=false, max=true]
        metadata: BoolMetadata { offset: 0 }
        buffer: bits host 2 B (align=1) (100.00%)
    : vortex.varbinview(binary?, len=11) nbytes=214 B (52.58%)
      metadata: EmptyMetadata
      buffer: buffer_0 host 36 B (align=1) (16.82%)
      buffer: views host 176 B (align=16) (82.24%)
      validity: vortex.bool(bool, len=11) nbytes=2 B (0.93%) [nulls=0, min=false, max=true]
        metadata: BoolMetadata { offset: 0 }
        buffer: bits host 2 B (align=1) (100.00%)
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: __libfuzzer_sys_run
             at ./fuzz/fuzz_targets/array_ops.rs:33:19
   4: rust_fuzzer_test_input
             at /home/runner/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/libfuzzer-sys-0.4.12/src/lib.rs:363:60
   5: {closure#0}
             at /home/runner/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/libfuzzer-sys-0.4.12/src/lib.rs:62:9
   6: do_call<libfuzzer_sys::test_input_wrap::{closure_env#0}, i32>
             at /rustc/db3e99bbab28c6ca778b13222becdea54533d908/library/std/src/panicking.rs:581:40
   7: __rust_try
   8: catch_unwind<i32, libfuzzer_sys::test_input_wrap::{closure_env#0}>
             at /rustc/db3e99bbab28c6ca778b13222becdea54533d908/library/std/src/panicking.rs:544:19
   9: catch_unwind<libfuzzer_sys::test_input_wrap::{closure_env#0}, i32>
             at /rustc/db3e99bbab28c6ca778b13222becdea54533d908/library/std/src/panic.rs:359:14
  10: test_input_wrap
             at /home/runner/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/libfuzzer-sys-0.4.12/src/lib.rs:60:22
  11: _ZN6fuzzer6Fuzzer15ExecuteCallbackEPKhm
             at /home/runner/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/libfuzzer-sys-0.4.12/libfuzzer/FuzzerLoop.cpp:619:13
  12: _ZN6fuzzer10RunOneTestEPNS_6FuzzerEPKcm
             at /home/runner/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/libfuzzer-sys-0.4.12/libfuzzer/FuzzerDriver.cpp:335:6
  13: _ZN6fuzzer12FuzzerDriverEPiPPPcPFiPKhmE
             at /home/runner/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/libfuzzer-sys-0.4.12/libfuzzer/FuzzerDriver.cpp:871:9
  14: main
             at /home/runner/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/libfuzzer-sys-0.4.12/libfuzzer/FuzzerMain.cpp:20:10
  15: <unknown>
  16: __libc_start_main
  17: _start

Root Cause Analysis

The crash is an array equality assertion failure in the array_ops fuzz target (array_ops.rs:33) at step 3 of a fuzz action sequence. The mismatch occurs on a nested struct array with nullable binary fields: the expected scalar has a null value for the second struct field, but the actual scalar incorrectly populates that field with data copied from the first struct field instead of respecting the null. This strongly suggests a bug in how struct array operations (likely slice, filter, or take) propagate validity/nullness through nested struct children — when a parent struct field is null, the child data is being materialized rather than preserved as null. The fix should investigate the struct encoding's implementation of whichever array operation is triggered at step 3, ensuring that null parent entries produce null scalars rather than exposing stale or copied child data.

Summary

Reproduce

cargo +nightly fuzz run -D --sanitizer=none array_ops ./fuzz/artifacts/array_ops/crash-847379185a914ddb7dbdc9b984ff5317fc053976 -- -rss_limit_mb=0
First-time setup: download and extract the crash artifact
  1. Download the crash artifact:

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

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
  1. Get a backtrace:
RUST_BACKTRACE=1 cargo +nightly fuzz run -D --sanitizer=none array_ops ./fuzz/artifacts/array_ops/crash-847379185a914ddb7dbdc9b984ff5317fc053976 -- -rss_limit_mb=0
RUST_BACKTRACE=full cargo +nightly fuzz run -D --sanitizer=none array_ops ./fuzz/artifacts/array_ops/crash-847379185a914ddb7dbdc9b984ff5317fc053976 -- -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