Skip to content

Commit e35b769

Browse files
committed
fix OOB memcpy
1 parent 96f080d commit e35b769

File tree

2 files changed

+17
-6
lines changed

2 files changed

+17
-6
lines changed

pandas/_libs/arrays.pyx

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -487,9 +487,12 @@ cdef class BitmaskArray:
487487
# TODO: upstream generic ArrowBitsGet function in nanoarrow
488488
PySlice_Unpack(key, &start, &stop, &step)
489489
if start == 0 and stop > 0 and step == 1:
490+
nbytes = (stop + 7) // 8
491+
if nbytes > self_.bitmap.size_bits:
492+
nbytes = self_.bitmap.size_bits
493+
490494
bma = BitmaskArray.__new__(BitmaskArray)
491495
ArrowBitmapInit(&bitmap)
492-
nbytes = (stop + 7) // 8
493496
ArrowBitmapReserve(&bitmap, nbytes)
494497
memcpy(bitmap.buffer.data, self_.bitmap.buffer.data, nbytes)
495498
bitmap.buffer.size_bytes = nbytes

pandas/tests/arrays/masked/test_bitmask.py

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -121,15 +121,23 @@ def test_getitem_null_slice():
121121
assert (result.bytes[0] >> 2) & 1 == 1
122122

123123

124-
def test_getitem_monotonic_slice():
124+
@pytest.mark.parametrize(
125+
"indexer,mask,expected",
126+
[
127+
pytest.param(slice(2), bytes([0x3]), bytes([0x1]), id="basic_slice"),
128+
pytest.param(
129+
slice(1000), bytes([0x7]), bytes([0x05]), id="slice_exceeding_bounds"
130+
),
131+
],
132+
)
133+
def test_getitem_monotonic_slice(indexer, mask, expected):
125134
bma = BitmaskArray(np.array([True, False, True]))
126-
result = bma[slice(2)]
135+
result = bma[indexer]
127136

128137
assert not result.parent
129-
assert len(result) == 2
130138

131-
assert result.bytes[0] & 1 == 1
132-
assert (result.bytes[0] >> 1) & 1 == 0
139+
# the bits past the length of result are undefined, so explicitly mask them out
140+
assert (result.bytes[0] & mask[0]) == expected[0]
133141

134142

135143
@pytest.mark.parametrize(

0 commit comments

Comments
 (0)