-
Notifications
You must be signed in to change notification settings - Fork 118
Open
Description
Fuzzing Crash Report
Analysis
Crash Location: vortex-array/src/arrow/executor/list.rs:122 in the list_view_zctl function
Error Message:
attempt to subtract with overflow
Stack Trace:
0: __rustc::rust_begin_unwind
1: core::panicking::panic_fmt
2: core::panicking::panic_const::panic_const_sub_overflow
3: list_view_zctl<i32>
at ./vortex-array/src/arrow/executor/list.rs:122:20
4: to_arrow_list<i32>
at ./vortex-array/src/arrow/executor/list.rs:51:24
5: execute_arrow
at ./vortex-array/src/arrow/executor/mod.rs:124:47
6: list_view_zctl<i32>
at ./vortex-array/src/arrow/executor/list.rs:151:29
7: to_arrow_list<i32>
at ./vortex-array/src/arrow/executor/list.rs:51:24
8: execute_arrow
at ./vortex-array/src/arrow/executor/mod.rs:124:47
9: into_arrow
at ./vortex-array/src/arrow/mod.rs:45:14
10: arrow_compare
at ./vortex-array/src/compute/compare.rs:371:35
Root Cause:
The fuzzer discovered an integer overflow panic in the Arrow executor when converting a nested ListViewArray to an Arrow array. The crash occurs at line 122 in list_view_zctl:
let final_size = sizes
.scalar_at(sizes.len() - 1) // Line 122 - panics when sizes.len() == 0
.cast(&DType::Primitive(O::PTYPE, Nullability::NonNullable))?;When sizes.len() is 0, the expression sizes.len() - 1 causes an integer underflow panic in debug/fuzz builds.
The crash path:
- A nested
List(List(Utf8))structure with empty arrays is created - During a compare operation, the arrays are converted to Arrow format
- The outer ListViewArray calls
list_view_zctl - The inner ListViewArray also calls
list_view_zctl - The inner call has an empty
sizesarray (length 0) - Attempting
sizes.len() - 1whenlen() == 0causes integer overflow
The debug output shows the structure:
- Outer ListViewArray with 2 elements (offsets: [0, 0], sizes: [0, 0])
- Inner ListViewArray with 0 elements (offsets: empty, sizes: empty)
- Elements are VarBinViewArray with 0 views
This indicates a valid edge case where nested empty lists should be handled, but the current code assumes sizes.len() >= 1.
Debug Output
FuzzFileAction {
array: ListViewArray {
dtype: List(
List(
Utf8(
Nullable,
),
Nullable,
),
Nullable,
),
elements: ListViewArray {
dtype: List(
Utf8(
Nullable,
),
Nullable,
),
elements: VarBinViewArray {
dtype: Utf8(
Nullable,
),
buffers: [],
views: Buffer<vortex_vector::binaryview::view::BinaryView> {
length: 0,
alignment: Alignment(
16,
),
as_slice: [],
},
validity: AllValid,
stats_set: ArrayStats {
inner: RwLock {
data: StatsSet {
values: [],
},
},
},
},
offsets: PrimitiveArray {
dtype: Primitive(
U64,
NonNullable,
),
buffer: BufferHandle(
Host(
Buffer<u8> {
length: 0,
alignment: Alignment(
8,
),
as_slice: [],
},
),
),
validity: NonNullable,
stats_set: ArrayStats {
inner: RwLock {
data: StatsSet {
values: [
(
IsSorted,
Exact(
ScalarValue(
Bool(
true,
),
),
),
),
],
},
},
},
},
sizes: PrimitiveArray {
dtype: Primitive(
U64,
NonNullable,
),
buffer: BufferHandle(
Host(
Buffer<u8> {
length: 0,
alignment: Alignment(
8,
),
as_slice: [],
},
),
),
validity: NonNullable,
stats_set: ArrayStats {
inner: RwLock {
data: StatsSet {
values: [],
},
},
},
},
is_zero_copy_to_list: true,
validity: AllValid,
stats_set: ArrayStats {
inner: RwLock {
data: StatsSet {
values: [],
},
},
},
},
offsets: PrimitiveArray {
dtype: Primitive(
I32,
NonNullable,
),
buffer: BufferHandle(
Host(
Buffer<u8> {
length: 8,
alignment: Alignment(
4,
),
as_slice: [0, 0, 0, 0, 0, 0, 0, 0],
},
),
),
validity: NonNullable,
stats_set: ArrayStats {
inner: RwLock {
data: StatsSet {
values: [
(
IsSorted,
Exact(
ScalarValue(
Bool(
true,
),
),
),
),
],
},
},
},
},
sizes: PrimitiveArray {
dtype: Primitive(
I32,
NonNullable,
),
buffer: BufferHandle(
Host(
Buffer<u8> {
length: 8,
alignment: Alignment(
4,
),
as_slice: [0, 0, 0, 0, 0, 0, 0, 0],
},
),
),
validity: NonNullable,
stats_set: ArrayStats {
inner: RwLock {
data: StatsSet {
values: [],
},
},
},
},
is_zero_copy_to_list: true,
validity: AllValid,
stats_set: ArrayStats {
inner: RwLock {
data: StatsSet {
values: [],
},
},
},
},
projection_expr: None,
filter_expr: None,
compressor_strategy: Compact,
}
Summary
- Target:
file_io - Crash File:
crash-f59d24f0d4e13cdb621ff55a229aa3153a9eaeb0 - Branch: $BRANCH
- Commit: $COMMIT
- Crash Artifact: $ARTIFACT_URL
Reproduction
-
Download the crash artifact:
- Direct download: $ARTIFACT_URL
- Or find
$ARTIFACT_NAMEat: $WORKFLOW_RUN - Extract the zip file
-
Reproduce locally:
# The artifact contains file_io/crash-f59d24f0d4e13cdb621ff55a229aa3153a9eaeb0
cargo +nightly fuzz run -D --sanitizer=none file_io file_io/crash-f59d24f0d4e13cdb621ff55a229aa3153a9eaeb0 -- -rss_limit_mb=0- Get full backtrace:
RUST_BACKTRACE=full cargo +nightly fuzz run -D --sanitizer=none file_io file_io/crash-f59d24f0d4e13cdb621ff55a229aa3153a9eaeb0 -- -rss_limit_mb=0Auto-created by fuzzing workflow with Claude analysis