Skip to content

Commit 72ce9a0

Browse files
committed
Merge remote-tracking branch 'origin/release-0.17'
2 parents afca13e + c6508b5 commit 72ce9a0

File tree

5 files changed

+63
-35
lines changed

5 files changed

+63
-35
lines changed

CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,9 @@
33
- Unreleased
44
- Drop our wrapper for NumPy iterators which were deprecated in v0.16.0 as ndarray's iteration facilities are almost always preferable. ([#324](https://github.com/PyO3/rust-numpy/pull/324))
55

6+
- v0.17.2
7+
- Fix unsound aliasing into `Box<[T]>` when converting them into NumPy arrays. ([#351](https://github.com/PyO3/rust-numpy/pull/351))
8+
69
- v0.17.1
710
- Fix use-after-free in `PyArray::resize`, `PyArray::reshape` and `PyArray::reshape_with_order`. ([#341](https://github.com/PyO3/rust-numpy/pull/341))
811
- Fix UB in `ToNpyDims::as_dims_ptr` with dimensions of dynamic size (-1). ([#344](https://github.com/PyO3/rust-numpy/pull/344))

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "numpy"
3-
version = "0.17.1"
3+
version = "0.17.2"
44
authors = [
55
"The rust-numpy Project Developers",
66
"PyO3 Project and Contributors <https://github.com/PyO3>"

src/array.rs

Lines changed: 28 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -451,7 +451,7 @@ impl<T: Element, D: Dimension> PyArray<T, D> {
451451
where
452452
ID: IntoDimension<Dim = D>,
453453
{
454-
let flags = if is_fortran { 1 } else { 0 };
454+
let flags = c_int::from(is_fortran);
455455
Self::new_uninit(py, dims, ptr::null_mut(), flags)
456456
}
457457

@@ -512,18 +512,14 @@ impl<T: Element, D: Dimension> PyArray<T, D> {
512512
Self::from_owned_ptr(py, ptr)
513513
}
514514

515-
pub(crate) unsafe fn from_raw_parts<'py, ID, C>(
515+
pub(crate) unsafe fn from_raw_parts<'py>(
516516
py: Python<'py>,
517-
dims: ID,
517+
dims: D,
518518
strides: *const npy_intp,
519519
data_ptr: *const T,
520-
container: C,
521-
) -> &'py Self
522-
where
523-
ID: IntoDimension<Dim = D>,
524-
PySliceContainer: From<C>,
525-
{
526-
let container = PyClassInitializer::from(PySliceContainer::from(container))
520+
container: PySliceContainer,
521+
) -> &'py Self {
522+
let container = PyClassInitializer::from(container)
527523
.create_cell(py)
528524
.expect("Failed to create slice container");
529525

@@ -676,10 +672,18 @@ impl<T: Element, D: Dimension> PyArray<T, D> {
676672
/// assert_eq!(pyarray.readonly().as_array(), array![[1, 2], [3, 4]]);
677673
/// });
678674
/// ```
679-
pub fn from_owned_array<'py>(py: Python<'py>, arr: Array<T, D>) -> &'py Self {
675+
pub fn from_owned_array<'py>(py: Python<'py>, mut arr: Array<T, D>) -> &'py Self {
680676
let (strides, dims) = (arr.npy_strides(), arr.raw_dim());
681-
let data_ptr = arr.as_ptr();
682-
unsafe { Self::from_raw_parts(py, dims, strides.as_ptr(), data_ptr, arr) }
677+
let data_ptr = arr.as_mut_ptr();
678+
unsafe {
679+
Self::from_raw_parts(
680+
py,
681+
dims,
682+
strides.as_ptr(),
683+
data_ptr,
684+
PySliceContainer::from(arr),
685+
)
686+
}
683687
}
684688

685689
/// Get a reference of the specified element if the given index is valid.
@@ -1071,10 +1075,18 @@ impl<D: Dimension> PyArray<PyObject, D> {
10711075
/// assert!(pyarray.readonly().as_array().get(0).unwrap().as_ref(py).is_instance_of::<CustomElement>().unwrap());
10721076
/// });
10731077
/// ```
1074-
pub fn from_owned_object_array<'py, T>(py: Python<'py>, arr: Array<Py<T>, D>) -> &'py Self {
1078+
pub fn from_owned_object_array<'py, T>(py: Python<'py>, mut arr: Array<Py<T>, D>) -> &'py Self {
10751079
let (strides, dims) = (arr.npy_strides(), arr.raw_dim());
1076-
let data_ptr = arr.as_ptr() as *const PyObject;
1077-
unsafe { PyArray::from_raw_parts(py, dims, strides.as_ptr(), data_ptr, arr) }
1080+
let data_ptr = arr.as_mut_ptr() as *const PyObject;
1081+
unsafe {
1082+
Self::from_raw_parts(
1083+
py,
1084+
dims,
1085+
strides.as_ptr(),
1086+
data_ptr,
1087+
PySliceContainer::from(arr),
1088+
)
1089+
}
10781090
}
10791091
}
10801092

src/convert.rs

Lines changed: 21 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,15 @@
22
33
use std::{mem, os::raw::c_int, ptr};
44

5-
use ndarray::{ArrayBase, Data, Dimension, IntoDimension, Ix1, OwnedRepr};
5+
use ndarray::{ArrayBase, Data, Dim, Dimension, IntoDimension, Ix1, OwnedRepr};
66
use pyo3::Python;
77

88
use crate::array::PyArray;
99
use crate::dtype::Element;
1010
use crate::error::MAX_DIMENSIONALITY_ERR;
1111
use crate::npyffi::{self, npy_intp};
1212
use crate::sealed::Sealed;
13+
use crate::slice_container::PySliceContainer;
1314

1415
/// Conversion trait from owning Rust types into [`PyArray`].
1516
///
@@ -49,22 +50,34 @@ impl<T: Element> IntoPyArray for Box<[T]> {
4950
type Dim = Ix1;
5051

5152
fn into_pyarray<'py>(self, py: Python<'py>) -> &'py PyArray<Self::Item, Self::Dim> {
52-
let dims = [self.len()];
53+
let container = PySliceContainer::from(self);
54+
let dims = Dim([container.len]);
5355
let strides = [mem::size_of::<T>() as npy_intp];
54-
let data_ptr = self.as_ptr();
55-
unsafe { PyArray::from_raw_parts(py, dims, strides.as_ptr(), data_ptr, self) }
56+
// The data pointer is derived only after dissolving `Box` into `PySliceContainer`
57+
// to avoid unsound aliasing of Box<[T]> which is currently noalias,
58+
// c.f. https://github.com/rust-lang/unsafe-code-guidelines/issues/326
59+
let data_ptr = container.ptr as *mut T;
60+
unsafe { PyArray::from_raw_parts(py, dims, strides.as_ptr(), data_ptr, container) }
5661
}
5762
}
5863

5964
impl<T: Element> IntoPyArray for Vec<T> {
6065
type Item = T;
6166
type Dim = Ix1;
6267

63-
fn into_pyarray<'py>(self, py: Python<'py>) -> &'py PyArray<Self::Item, Self::Dim> {
64-
let dims = [self.len()];
68+
fn into_pyarray<'py>(mut self, py: Python<'py>) -> &'py PyArray<Self::Item, Self::Dim> {
69+
let dims = Dim([self.len()]);
6570
let strides = [mem::size_of::<T>() as npy_intp];
66-
let data_ptr = self.as_ptr();
67-
unsafe { PyArray::from_raw_parts(py, dims, strides.as_ptr(), data_ptr, self) }
71+
let data_ptr = self.as_mut_ptr();
72+
unsafe {
73+
PyArray::from_raw_parts(
74+
py,
75+
dims,
76+
strides.as_ptr(),
77+
data_ptr,
78+
PySliceContainer::from(self),
79+
)
80+
}
6881
}
6982
}
7083

src/slice_container.rs

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
1-
use std::{mem, slice};
1+
use std::{mem, ptr};
22

33
use ndarray::{ArrayBase, Dimension, OwnedRepr};
44
use pyo3::pyclass;
55

66
/// Utility type to safely store `Box<[_]>` or `Vec<_>` on the Python heap
77
#[pyclass]
88
pub(crate) struct PySliceContainer {
9-
ptr: *mut u8,
10-
len: usize,
9+
pub(crate) ptr: *mut u8,
10+
pub(crate) len: usize,
1111
cap: usize,
1212
drop: unsafe fn(*mut u8, usize, usize),
1313
}
@@ -17,18 +17,18 @@ unsafe impl Send for PySliceContainer {}
1717
impl<T: Send> From<Box<[T]>> for PySliceContainer {
1818
fn from(data: Box<[T]>) -> Self {
1919
unsafe fn drop_boxed_slice<T>(ptr: *mut u8, len: usize, _cap: usize) {
20-
let _ = Box::from_raw(slice::from_raw_parts_mut(ptr as *mut T, len) as *mut [T]);
20+
let _ = Box::from_raw(ptr::slice_from_raw_parts_mut(ptr as *mut T, len));
2121
}
2222

2323
// FIXME(adamreichold): Use `Box::into_raw` when
2424
// `*mut [T]::{as_mut_ptr, len}` become stable and compatible with our MSRV.
25-
let ptr = data.as_ptr() as *mut u8;
25+
let mut data = mem::ManuallyDrop::new(data);
26+
27+
let ptr = data.as_mut_ptr() as *mut u8;
2628
let len = data.len();
2729
let cap = 0;
2830
let drop = drop_boxed_slice::<T>;
2931

30-
mem::forget(data);
31-
3232
Self {
3333
ptr,
3434
len,
@@ -46,13 +46,13 @@ impl<T: Send> From<Vec<T>> for PySliceContainer {
4646

4747
// FIXME(adamreichold): Use `Vec::into_raw_parts`
4848
// when it becomes stable and compatible with our MSRV.
49-
let ptr = data.as_ptr() as *mut u8;
49+
let mut data = mem::ManuallyDrop::new(data);
50+
51+
let ptr = data.as_mut_ptr() as *mut u8;
5052
let len = data.len();
5153
let cap = data.capacity();
5254
let drop = drop_vec::<T>;
5355

54-
mem::forget(data);
55-
5656
Self {
5757
ptr,
5858
len,

0 commit comments

Comments
 (0)