-
Notifications
You must be signed in to change notification settings - Fork 121
Open
Labels
Description
Fuzzing Crash Report
Analysis
Crash Location: vortex-array/src/validity.rs:281 in the Validity::patch function
Error Message:
compare operation should succeed in fuzz test:
Can't patch a nullable validity with non-nullable validity
Stack Trace:
3: patch
at ./vortex-array/src/validity.rs:281:17
4: patch
at ./vortex-array/src/arrays/primitive/array/patch.rs:25:56
5: decompress_unchunked_core
at ./encodings/alp/src/alp/decompress.rs:170:17
6: execute_decompress
at ./encodings/alp/src/alp/decompress.rs:89:9
7: execute
at ./encodings/alp/src/alp/array.rs:171:33
8: execute_canonical<vortex_alp::alp::array::ALPVTable>
at ./vortex-array/src/vtable/dyn_.rs:156:22
9: execute
at ./vortex-array/src/executor.rs:98:24
10: execute<vortex_array::canonical::Canonical>
at ./vortex-array/src/executor.rs:43:9
11: execute
at ./vortex-array/src/expr/vtable.rs:342:50
12: execute<vortex_array::expr::vtable::ExecutionResult>
at ./vortex-array/src/executor.rs:43:9
13: execute
at ./vortex-array/src/expr/exprs/cast.rs:87:53
14: execute<vortex_array::expr::exprs::cast::Cast>
at ./vortex-array/src/expr/vtable.rs:550:22
Root Cause:
The fuzzer discovered a bug in the ALP decompression logic where patching fails due to validity incompatibility. This is the inverse of issue #5766.
The issue occurs when:
- An ALP-encoded ChunkedArray with F32 NonNullable dtype is decompressed
- The base decoded array has nullable validity (either AllValid with nullable dtype or an explicit validity array)
- The patches array has NonNullable validity
- When attempting to apply patches at
encodings/alp/src/alp/decompress.rs:170, the code callsdecoded.patch(&patches) - This calls
Validity::patch()at line 25 ofpatch.rs, which then fails atvalidity.rs:281
Looking at vortex-array/src/validity.rs:275-282:
match (&self, patches) {
(Validity::NonNullable, Validity::NonNullable) => return Ok(Validity::NonNullable),
(Validity::NonNullable, _) => {
vortex_bail!("Can't patch a non-nullable validity with nullable validity")
},
(_, Validity::NonNullable) => {
vortex_bail!("Can't patch a nullable validity with non-nullable validity") // Line 281
},
...
}The panic happens during a compare operation in the fuzzer's file I/O test at file_io.rs:115-116. The compare operation triggers Arrow conversion, which executes the ALP-encoded array, triggering decompression with incompatible validities.
Array Structure:
- ChunkedArray with dtype Primitive(F32, NonNullable), length 5
- 2 chunks: PrimitiveArray(length=1) and PrimitiveArray(length=4)
- Both chunks have NonNullable validity
- After compression and file I/O, the decompression creates a mismatch
Relationship to Other Issues:
- Issue Fuzzing Crash: Validity patch fails in ALP decompression (non-nullable base with nullable patches) #5766: Opposite error ("Can't patch a non-nullable validity with nullable validity")
- Both are manifestations of the same underlying problem in ALP's patch validity handling
Debug Output
FuzzFileAction {
array: ChunkedArray {
dtype: Primitive(
F32,
NonNullable,
),
len: 5,
chunk_offsets: PrimitiveArray {
dtype: Primitive(
U64,
NonNullable,
),
buffer: BufferHandle(
Host(
Buffer<u8> {
length: 24,
alignment: Alignment(
8,
),
as_slice: [0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, ...],
},
),
),
validity: NonNullable,
stats_set: ArrayStats {
inner: RwLock {
data: StatsSet {
values: [],
},
},
},
},
chunks: [
PrimitiveArray {
dtype: Primitive(
F32,
NonNullable,
),
buffer: BufferHandle(
Host(
Buffer<u8> {
length: 4,
alignment: Alignment(
4,
),
as_slice: [1, 0, 193, 65],
},
),
),
validity: NonNullable,
stats_set: ArrayStats {
inner: RwLock {
data: StatsSet {
values: [],
},
},
},
},
PrimitiveArray {
dtype: Primitive(
F32,
NonNullable,
),
buffer: BufferHandle(
Host(
Buffer<u8> {
length: 16,
alignment: Alignment(
4,
),
as_slice: [193, 193, 193, 193, 193, 193, 193, 193, 193, 193, 193, 193, 193, 193, 193, 193],
},
),
),
validity: NonNullable,
stats_set: ArrayStats {
inner: RwLock {
data: StatsSet {
values: [],
},
},
},
},
],
stats_set: ArrayStats {
inner: RwLock {
data: StatsSet {
values: [],
},
},
},
},
projection_expr: None,
filter_expr: None,
compressor_strategy: Default,
}
Summary
- Target:
file_io - Crash File:
crash-29298272e502730f91c1ff3b4c9b7a8c35932aca - Branch: develop
- Commit: b45ee4d
- Crash Artifact: https://github.com/vortex-data/vortex/actions/runs//artifacts/
Reproduction
-
Download the crash artifact:
- Direct download: https://github.com/vortex-data/vortex/actions/runs//artifacts/
- Or find
io-fuzzing-crash-artifactsat: https://github.com/vortex-data/vortex/actions/runs/ - Extract the zip file
-
Reproduce locally:
# The artifact contains file_io/crash-29298272e502730f91c1ff3b4c9b7a8c35932aca
cargo +nightly fuzz run -D --sanitizer=none file_io file_io/crash-29298272e502730f91c1ff3b4c9b7a8c35932aca -- -rss_limit_mb=0- Get full backtrace:
RUST_BACKTRACE=full cargo +nightly fuzz run -D --sanitizer=none file_io file_io/crash-29298272e502730f91c1ff3b4c9b7a8c35932aca -- -rss_limit_mb=0Auto-created by fuzzing workflow with Claude analysis