Skip to content

Commit 83c8e19

Browse files
committed
Fix SliceBox-induced type confusion by manually performing type erasure.
1 parent daa317c commit 83c8e19

File tree

2 files changed

+30
-17
lines changed

2 files changed

+30
-17
lines changed

src/slice_box.rs

Lines changed: 26 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -4,40 +4,49 @@ use pyo3::pyclass_slots::PyClassDummySlot;
44
use pyo3::type_object::{LazyStaticType, PyTypeInfo};
55
use pyo3::{ffi, types::PyAny, PyCell};
66

7-
pub(crate) struct SliceBox<T> {
8-
data: Box<[T]>,
7+
pub(crate) struct SliceBox {
8+
ptr: *mut [u8],
9+
drop: unsafe fn(*mut [u8]),
910
}
1011

11-
impl<T> SliceBox<T> {
12-
pub(crate) fn new(data: Box<[T]>) -> Self {
13-
Self { data }
12+
unsafe impl Send for SliceBox {}
13+
14+
impl SliceBox {
15+
pub(crate) fn new<T: Send>(data: Box<[T]>) -> Self {
16+
unsafe fn drop_boxed_slice<T>(ptr: *mut [u8]) {
17+
let _ = Box::from_raw(ptr as *mut [T]);
18+
}
19+
20+
let ptr = Box::into_raw(data) as *mut [u8];
21+
let drop = drop_boxed_slice::<T>;
22+
23+
Self { ptr, drop }
24+
}
25+
}
26+
27+
impl Drop for SliceBox {
28+
fn drop(&mut self) {
29+
unsafe {
30+
(self.drop)(self.ptr);
31+
}
1432
}
1533
}
1634

17-
impl<T> PyClass for SliceBox<T>
18-
where
19-
T: Send,
20-
{
35+
impl PyClass for SliceBox {
2136
type Dict = PyClassDummySlot;
2237
type WeakRef = PyClassDummySlot;
2338
type BaseNativeType = PyAny;
2439
}
2540

26-
impl<T> PyClassImpl for SliceBox<T>
27-
where
28-
T: Send,
29-
{
41+
impl PyClassImpl for SliceBox {
3042
const DOC: &'static str = "Memory store for PyArray using rust's Box<[T]> \0";
3143

3244
type BaseType = PyAny;
3345
type Layout = PyCell<Self>;
3446
type ThreadChecker = ThreadCheckerStub<Self>;
3547
}
3648

37-
unsafe impl<T> PyTypeInfo for SliceBox<T>
38-
where
39-
T: Send,
40-
{
49+
unsafe impl PyTypeInfo for SliceBox {
4150
type AsRefTarget = PyCell<Self>;
4251
const NAME: &'static str = "SliceBox";
4352
const MODULE: Option<&'static str> = Some("_rust_numpy");

tests/to_py.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -248,6 +248,10 @@ fn slice_box_type_confusion() {
248248

249249
let _py_arr = nd_arr.into_pyarray(py);
250250

251+
// Dropping `_arr` used to trigger a segmentation fault due to calling `Py_DECREF`
252+
// on 1, 2 and 3 interpreted as pointers into the Python heap
253+
// after having created a `SliceBox<PyObject>` backing `_py_arr`,
254+
// c.f. https://github.com/PyO3/rust-numpy/issues/232.
251255
let vec = vec![1, 2, 3];
252256
let _arr = vec.into_pyarray(py);
253257
});

0 commit comments

Comments
 (0)