[C++] fill_null_forward, fill_null_backward and replace_with_mask read the wrong bits on a sliced boolean array
- Dominant language
- C++
- Stars
- 17.1k
- Forks
- 4.3k
- Avg merge
- 3d 13h
- Merged PRs (30d)
- 88
Description
**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.
```python
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
Contributor guide
Assessment
This issue has not been assessed yet.