Skip to content

[C++] fill_null_forward, fill_null_backward and replace_with_mask read the wrong bits on a sliced boolean array #51223

Description

@singhpratech

Describe the bug

On a boolean array with a non-zero offset (a slice), fill_null_forward, fill_null_backward and
replace_with_mask return values that belong to other positions of the parent array: the value
bitmap is read without the slice's offset. A materialised copy of the same slice gives the right
answer, and an int64 slice is handled correctly, so it is specific to the bit-packed boolean path.

pyarrow 25.0.1, Python 3.13.9, macOS 26.6 (arm64), wheel from PyPI.

import pyarrow as pa, pyarrow.compute as pc

full = pa.array([True, False, None, True, True, False, None, True], pa.bool_())
sliced = full.slice(3, 5)                       # [True, True, False, None, True]
copy = pa.array(sliced.to_pylist(), pa.bool_())  # same values, offset 0

print("forward  sliced", pc.fill_null_forward(sliced).to_pylist())
print("forward  copy  ", pc.fill_null_forward(copy).to_pylist())
print("backward sliced", pc.fill_null_backward(sliced).to_pylist())
print("backward copy  ", pc.fill_null_backward(copy).to_pylist())

mask = pa.array([True, False, False, False, False])
repl = pa.array([False], pa.bool_())
print("replace  sliced", pc.replace_with_mask(sliced, mask, repl).to_pylist())
print("replace  copy  ", pc.replace_with_mask(copy, mask, repl).to_pylist())

print("int64 control  ", pc.fill_null_forward(pa.array([1, None, 3, 4, None, 6, None, 8]).slice(3, 5)).to_pylist())

Output:

forward  sliced [True, False, False, False, True]
forward  copy   [True, True, False, False, True]
backward sliced [True, False, False, True, True]
backward copy   [True, True, False, True, True]
replace  sliced [False, False, False, None, True]
replace  copy   [False, True, False, None, True]
int64 control   [4, 4, 6, 6, 8]

In every "sliced" line the second element is False, which is full[1], not full[4] (True):
the untouched positions are copied from bit index i of the parent bitmap instead of offset + i.

Expected behavior

The "sliced" and "copy" lines agree, as they do for int64.

This looks distinct from #45086 (an allocation crash on a boolean ChunkedArray, fixed on main by #50843 and not in a release yet): the values here are wrong, not the allocation.

Component(s)

C++, Python

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions