-
Notifications
You must be signed in to change notification settings - Fork 107
Description
Fuzzing Crash Report
Analysis
Crash Location: vortex-array/src/arrays/decimal/compute/fill_null.rs:35 (in fill_null function)
Error Message:
top-level fill_null ensure non-null fill value
Stack Trace:
6: fill_null
at ./vortex-array/src/arrays/decimal/compute/fill_null.rs:35:26
7: invoke<vortex_array::arrays::decimal::vtable::DecimalVTable>
at ./vortex-array/src/compute/fill_null.rs:84:13
8: invoke
at ./vortex-array/src/compute/fill_null.rs:114:42
9: invoke
at ./vortex-array/src/compute/mod.rs:149:34
10: fill_null
at ./vortex-array/src/compute/fill_null.rs:54:10
11: run_fuzz_action
at ./fuzz/src/array/mod.rs:594:33
Root Cause:
The fuzzer discovered a bug in the decimal fill_null implementation. When attempting to fill null values in a DecimalArray using a fill value scalar, the code panics because the fill value's decimal_value() returns None, even though the scalar has NonNullable dtype.
Looking at the crash location in vortex-array/src/arrays/decimal/compute/fill_null.rs:35:
let fill_value = fill_value
.as_decimal()
.decimal_value()
.and_then(|v| v.cast::<T>())
.vortex_expect("top-level fill_null ensure non-null fill value");The issue occurs with:
- Array type: DecimalArray with I256 values (decimal256)
- Decimal dtype:
Decimal(precision=39, scale=-53, Nullable) - Fill value scalar:
Decimal(precision=39, scale=-53, NonNullable)with I256 value-341667777821006224650557019145323413491 - Operation sequence:
- Take operation on DecimalArray (produces array with nulls)
- Compress operation
- FillNull operation (crashes here)
The fill value scalar shows as NonNullable and appears to have a valid I256 value in the debug output, but internally decimal_value() returns None, causing the panic. This suggests an issue with:
- How decimal scalars with I256/I128 values store or retrieve their internal values
- Type casting or conversion issues for decimal256 values
- The scalar's internal state being inconsistent with its dtype's nullability
Debug Output
FuzzArrayAction {
array: DecimalArray {
dtype: Decimal(
DecimalDType {
precision: 39,
scale: -53,
},
Nullable,
),
values: Buffer<u8> {
length: 96,
alignment: Alignment(
16,
),
as_slice: [117, 73, 73, 73, 73, 228, 216, 221, 140, 146, 73, 163, 37, 123, 121, 84, ...],
},
values_type: I256,
validity: AllValid,
stats_set: ArrayStats {
inner: RwLock {
data: StatsSet {
values: [],
},
},
},
},
actions: [
(
Take(
BitPackedArray {
offset: 0,
len: 29,
dtype: Primitive(
U64,
Nullable,
),
bit_width: 0,
packed: Buffer<u8> {
length: 0,
alignment: Alignment(
8,
),
as_slice: [],
},
patches: None,
validity: Array(
BoolArray {
dtype: Bool(
NonNullable,
),
bits: BitBuffer {
buffer: Buffer<u8> {
length: 4,
alignment: Alignment(
1,
),
as_slice: [32, 0, 0, 0],
},
offset: 0,
len: 29,
},
validity: NonNullable,
stats_set: ArrayStats {
inner: RwLock {
data: StatsSet {
values: [
(
Sum,
Exact(
ScalarValue(
Primitive(
U64(
1,
),
),
),
),
),
],
},
},
},
},
),
stats_set: ArrayStats {
inner: RwLock {
data: StatsSet {
values: [],
},
},
},
},
),
Array(
DecimalArray {
dtype: Decimal(
DecimalDType {
precision: 39,
scale: -53,
},
Nullable,
),
values: Buffer<u8> {
length: 928,
alignment: Alignment(
16,
),
as_slice: [117, 73, 73, 73, 73, 228, 216, 221, 140, 146, 73, 163, 37, 123, 121, 84, ...],
},
values_type: I256,
validity: Array(
BoolArray {
dtype: Bool(
NonNullable,
),
bits: BitBuffer {
buffer: Buffer<u8> {
length: 4,
alignment: Alignment(
1,
),
as_slice: [32, 0, 0, 0],
},
offset: 0,
len: 29,
},
validity: NonNullable,
stats_set: ArrayStats {
inner: RwLock {
data: StatsSet {
values: [],
},
},
},
},
),
stats_set: ArrayStats {
inner: RwLock {
data: StatsSet {
values: [],
},
},
},
},
),
),
(
Compress(
Default,
),
Array(
DecimalArray {
dtype: Decimal(
DecimalDType {
precision: 39,
scale: -53,
},
Nullable,
),
values: Buffer<u8> {
length: 928,
alignment: Alignment(
16,
),
as_slice: [117, 73, 73, 73, 73, 228, 216, 221, 140, 146, 73, 163, 37, 123, 121, 84, ...],
},
values_type: I256,
validity: Array(
BoolArray {
dtype: Bool(
NonNullable,
),
bits: BitBuffer {
buffer: Buffer<u8> {
length: 4,
alignment: Alignment(
1,
),
as_slice: [32, 0, 0, 0],
},
offset: 0,
len: 29,
},
validity: NonNullable,
stats_set: ArrayStats {
inner: RwLock {
data: StatsSet {
values: [],
},
},
},
},
),
stats_set: ArrayStats {
inner: RwLock {
data: StatsSet {
values: [],
},
},
},
},
),
),
(
FillNull(
Scalar {
dtype: Decimal(
DecimalDType {
precision: 39,
scale: -53,
},
NonNullable,
),
value: ScalarValue(
Decimal(
I256(
i256(
-341667777821006224650557019145323413491,
),
),
),
),
},
),
Array(
DecimalArray {
dtype: Decimal(
DecimalDType {
precision: 39,
scale: -53,
},
NonNullable,
),
values: Buffer<u8> {
length: 928,
alignment: Alignment(
16,
),
as_slice: [13, 0, 0, 0, 128, 224, 79, 240, 209, 78, 100, 13, 248, 45, 245, 254, ...],
},
values_type: I256,
validity: NonNullable,
stats_set: ArrayStats {
inner: RwLock {
data: StatsSet {
values: [],
},
},
},
},
),
),
],
}
Summary
- Target:
array_ops - Crash File:
crash-26eeec44c17b9831b8a1efa622c4426277cf8528 - Branch: ad/zstd-alignment
- Commit: fcc2b2f
- Crash Artifact: https://github.com/vortex-data/vortex/actions/runs/20264722783/artifacts/4884298955
Reproduction
-
Download the crash artifact:
- Direct download: https://github.com/vortex-data/vortex/actions/runs/20264722783/artifacts/4884298955
- Or find
operations-fuzzing-crash-artifactsat: https://github.com/vortex-data/vortex/actions/runs/20264722783 - Extract the zip file
-
Reproduce locally:
# The artifact contains array_ops/crash-26eeec44c17b9831b8a1efa622c4426277cf8528
cargo +nightly fuzz run --sanitizer=none array_ops array_ops/crash-26eeec44c17b9831b8a1efa622c4426277cf8528- Get full backtrace:
RUST_BACKTRACE=full cargo +nightly fuzz run --sanitizer=none array_ops array_ops/crash-26eeec44c17b9831b8a1efa622c4426277cf8528Auto-created by fuzzing workflow with Claude analysis