Skip to content

Fuzzing Crash: Decimal sum returns null instead of expected value after mask operation #5847

@github-actions

Description

@github-actions

Fuzzing Crash Report

Analysis

Crash Location: fuzz/src/array/mod.rs:assert_scalar_eq (line 721)

Error Message:

Scalar mismatch: expected decimal256(10335727954495815150286733452060801618349974312742667669043703035118638596109, precision=76, scale=75), got null in step 2

Stack Trace:

   3: assert_scalar_eq
             at ./fuzz/src/array/mod.rs:721:13
   4: run_fuzz_action
             at ./fuzz/src/array/mod.rs:600:17
   5: __libfuzzer_sys_run
             at ./fuzz/fuzz_targets/array_ops.rs:14:11

Root Cause: The fuzzer discovered an issue with the sum operation on decimal arrays after a mask operation. The test sequence:

  1. Created a ChunkedArray with Decimal(precision=76, scale=75) type containing 12 elements across 2 chunks
  2. Applied a mask operation with a bit pattern [248, 15] (9 true values out of 12, density 0.75)
  3. Attempted to compute the sum (step 2)
  4. Expected sum: decimal256(10335727954495815150286733452060801618349974312742667669043703035118638596109, precision=76, scale=75)
  5. Actual sum: null

This suggests the sum operation may not be correctly handling decimal arrays after masking, possibly due to issues with null propagation or masked value handling in the decimal sum implementation.

Debug Output
FuzzArrayAction {
    array: ChunkedArray {
        dtype: Decimal(
            DecimalDType {
                precision: 76,
                scale: 75,
            },
            Nullable,
        ),
        len: 12,
        chunk_offsets: PrimitiveArray {
            dtype: Primitive(
                U64,
                NonNullable,
            ),
            buffer: Buffer<u8> {
                length: 24,
                alignment: Alignment(
                    8,
                ),
                as_slice: [0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, ...],
            },
            validity: NonNullable,
            stats_set: ArrayStats {
                inner: RwLock {
                    data: StatsSet {
                        values: [],
                    },
                },
            },
        },
        chunks: [
            DecimalArray {
                dtype: Decimal(
                    DecimalDType {
                        precision: 76,
                        scale: 75,
                    },
                    Nullable,
                ),
                values: Buffer<u8> {
                    length: 128,
                    alignment: Alignment(
                        16,
                    ),
                    as_slice: [3, 0, 0, 0, 0, 0, 0, 0, 0, 144, 236, 228, 101, 118, 200, 187, ...],
                },
                values_type: I256,
                validity: AllValid,
                stats_set: ArrayStats {
                    inner: RwLock {
                        data: StatsSet {
                            values: [],
                        },
                    },
                },
            },
            DecimalArray {
                dtype: Decimal(
                    DecimalDType {
                        precision: 76,
                        scale: 75,
                    },
                    Nullable,
                ),
                values: Buffer<u8> {
                    length: 256,
                    alignment: Alignment(
                        16,
                    ),
                    as_slice: [1, 0, 0, 0, 0, 0, 0, 0, 0, 208, 64, 171, 43, 14, 231, 224, ...],
                },
                values_type: I256,
                validity: AllValid,
                stats_set: ArrayStats {
                    inner: RwLock {
                        data: StatsSet {
                            values: [],
                        },
                    },
                },
            },
        ],
        stats_set: ArrayStats {
            inner: RwLock {
                data: StatsSet {
                    values: [],
                },
            },
        },
    },
    actions: [
        (
            Mask(
                Values(
                    MaskValues {
                        buffer: BitBuffer {
                            buffer: Buffer<u8> {
                                length: 2,
                                alignment: Alignment(
                                    1,
                                ),
                                as_slice: [248, 15],
                            },
                            offset: 0,
                            len: 12,
                        },
                        indices: OnceLock(
                            <uninit>,
                        ),
                        slices: OnceLock(
                            <uninit>,
                        ),
                        true_count: 9,
                        density: 0.75,
                    },
                ),
            ),
            Array(
                DecimalArray {
                    dtype: Decimal(
                        DecimalDType {
                            precision: 76,
                            scale: 75,
                        },
                        Nullable,
                    ),
                    values: Buffer<u8> {
                        length: 384,
                        alignment: Alignment(
                            16,
                        ),
                        as_slice: [3, 0, 0, 0, 0, 0, 0, 0, 0, 144, 236, 228, 101, 118, 200, 187, ...],
                    },
                    values_type: I256,
                    validity: Array(
                        BoolArray {
                            dtype: Bool(
                                NonNullable,
                            ),
                            bits: BitBuffer {
                                buffer: Buffer<u8> {
                                    length: 2,
                                    alignment: Alignment(
                                        1,
                                    ),
                                    as_slice: [7, 240],
                                },
                                offset: 0,
                                len: 12,
                            },
                            validity: NonNullable,
                            stats_set: ArrayStats {
                                inner: RwLock {
                                    data: StatsSet {
                                        values: [
                                            (
                                                Sum,
                                                Exact(
                                                    ScalarValue(
                                                        Primitive(
                                                            U64(
                                                                3,
                                                            ),
                                                        ),
                                                    ),
                                                ),
                                            ),
                                        ],
                                    },
                                },
                            },
                        },
                    ),
                    stats_set: ArrayStats {
                        inner: RwLock {
                            data: StatsSet {
                                values: [],
                            },
                        },
                    },
                },
            ),
        ),
        (
            Sum,
            Scalar(
                Scalar {
                    dtype: Decimal(
                        DecimalDType {
                            precision: 76,
                            scale: 75,
                        },
                        Nullable,
                    ),
                    value: ScalarValue(
                        Decimal(
                            I256(
                                i256(
                                    10335727954495815150286733452060801618349974312742667669043703035118638596109,
                                ),
                            ),
                        ),
                    ),
                },
            ),
        ),
        (
            Sum,
            Scalar(
                Scalar {
                    dtype: Decimal(
                        DecimalDType {
                            precision: 76,
                            scale: 75,
                        },
                        Nullable,
                    ),
                    value: ScalarValue(
                        Decimal(
                            I256(
                                i256(
                                    10335727954495815150286733452060801618349974312742667669043703035118638596109,
                                ),
                            ),
                        ),
                    ),
                },
            ),
        ),
    ],
}

Summary

Reproduction

  1. Download the crash artifact:

  2. Reproduce locally:

# The artifact contains array_ops/crash-827867069cacb581ba8bb19ab6a0cd09d26dee48
cargo +nightly fuzz run -D --sanitizer=none array_ops array_ops/crash-827867069cacb581ba8bb19ab6a0cd09d26dee48 -- -rss_limit_mb=0
  1. Get full backtrace:
RUST_BACKTRACE=full cargo +nightly fuzz run -D --sanitizer=none array_ops array_ops/crash-827867069cacb581ba8bb19ab6a0cd09d26dee48 -- -rss_limit_mb=0

Auto-created by fuzzing workflow with Claude analysis

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions