Skip to content

Commit 68381ae

Browse files
authored
safety comments (#5885)
1 parent 053bc09 commit 68381ae

3 files changed

Lines changed: 44 additions & 0 deletions

File tree

src/impl_/trampoline.rs

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
#![warn(clippy::undocumented_unsafe_blocks, clippy::missing_safety_doc)]
2+
13
//! Trampolines for various pyfunction and pymethod implementations.
24
//!
35
//! They exist to monomorphise std::panic::catch_unwind once into PyO3, rather than inline in every
@@ -20,6 +22,7 @@ pub unsafe fn module_exec(
2022
module: *mut ffi::PyObject,
2123
f: for<'a, 'py> fn(&'a Bound<'py, PyModule>) -> PyResult<()>,
2224
) -> c_int {
25+
// SAFETY: f accepts a Bound object so Python is attached
2326
unsafe {
2427
trampoline(|py| {
2528
let module = module.assume_borrowed_or_err(py)?.cast::<PyModule>()?;
@@ -66,9 +69,14 @@ macro_rules! trampoline {
6669
/// External symbol called by Python, which calls the provided Rust function.
6770
///
6871
/// The Rust function is supplied via the generic parameter `Meth`.
72+
///
73+
/// # Safety
74+
///
75+
/// The interpreter must be attached
6976
pub unsafe extern "C" fn $name<Meth: MethodDef<$name::Func>>(
7077
$($arg_names: $arg_types,)*
7178
) -> $ret {
79+
// SAFETY: caller upholds requirements
7280
unsafe { $name::inner($($arg_names),*, Meth::METH) }
7381
}
7482

@@ -77,8 +85,13 @@ macro_rules! trampoline {
7785
use super::*;
7886

7987
/// Non-generic inner function to ensure only one trampoline instantiated
88+
///
89+
/// # Safety
90+
///
91+
/// The interpreter must be attached
8092
#[inline]
8193
pub(crate) unsafe fn inner($($arg_names: $arg_types),*, f: $name::Func) -> $ret {
94+
// SAFETY: caller upholds requirements
8295
unsafe { trampoline(|py| f(py, $($arg_names,)*)) }
8396
}
8497

@@ -89,18 +102,26 @@ macro_rules! trampoline {
89102
}
90103

91104
/// Noargs is a special case where the `_args` parameter is unused and not passed to the inner `Func`.
105+
/// # Safety
106+
///
107+
/// Interpreter must be attached
92108
pub unsafe extern "C" fn noargs<Meth: MethodDef<noargs::Func>>(
93109
slf: *mut ffi::PyObject,
94110
_args: *mut ffi::PyObject, // unused and value not defined
95111
) -> *mut ffi::PyObject {
112+
// SAFETY: caller upholds requirements
96113
unsafe { noargs::inner(slf, Meth::METH) }
97114
}
98115

99116
pub mod noargs {
100117
use super::*;
101118

119+
/// # Safety
120+
///
121+
/// Interpreter must be attached
102122
#[inline]
103123
pub(crate) unsafe fn inner(slf: *mut ffi::PyObject, f: Func) -> *mut ffi::PyObject {
124+
// SAFETY: caller upholds requirements
104125
unsafe { trampoline(|py| f(py, slf)) }
105126
}
106127

@@ -204,26 +225,41 @@ trampoline! {
204225

205226
/// Releasebufferproc is a special case where the function cannot return an error,
206227
/// so we use trampoline_unraisable.
228+
/// # Safety
229+
///
230+
/// - It must be sound to call the method with slf and buf
231+
/// - Interpreter must be attached
207232
#[cfg(any(not(Py_LIMITED_API), Py_3_11))]
208233
pub unsafe extern "C" fn releasebufferproc<Meth: MethodDef<releasebufferproc::Func>>(
209234
slf: *mut ffi::PyObject,
210235
buf: *mut ffi::Py_buffer,
211236
) {
237+
// SAFETY: caller upholds rquirements
212238
unsafe { releasebufferproc::inner(slf, buf, Meth::METH) }
213239
}
214240

215241
#[cfg(any(not(Py_LIMITED_API), Py_3_11))]
216242
pub mod releasebufferproc {
217243
use super::*;
218244

245+
/// # Safety
246+
///
247+
/// - It must be sound to call f with slf and buf
248+
/// - Interpreter must be attached
219249
#[inline]
220250
pub(crate) unsafe fn inner(slf: *mut ffi::PyObject, buf: *mut ffi::Py_buffer, f: Func) {
251+
// SAFETY: caller upholds requirements
221252
unsafe { trampoline_unraisable(|py| f(py, slf, buf), slf) }
222253
}
223254

224255
pub type Func = unsafe fn(Python<'_>, *mut ffi::PyObject, *mut ffi::Py_buffer) -> PyResult<()>;
225256
}
226257

258+
/// # Safety
259+
///
260+
/// - slf must be either a valid ffi::PyObject or NULL
261+
/// - if slf isn't NULL it must not be used again
262+
/// - The thread must be attached to the interpreter when this is called.
227263
#[inline]
228264
pub(crate) unsafe fn dealloc(
229265
slf: *mut ffi::PyObject,
@@ -233,6 +269,8 @@ pub(crate) unsafe fn dealloc(
233269
// so pass null_mut() to the context.
234270
//
235271
// (Note that we don't allow the implementation `f` to fail.)
272+
//
273+
// SAFETY: caller upholds requirements
236274
unsafe {
237275
trampoline_unraisable(
238276
|py| {
@@ -260,6 +298,7 @@ trampoline!(
260298
/// Panics during execution are trapped so that they don't propagate through any
261299
/// outer FFI boundary.
262300
///
301+
/// # Safety
263302
/// The thread must already be attached to the interpreter when this is called.
264303
#[inline]
265304
pub(crate) unsafe fn trampoline<F, R>(body: F) -> R
@@ -324,6 +363,7 @@ where
324363
if let Err(py_err) = panic::catch_unwind(move || body(py))
325364
.unwrap_or_else(|payload| Err(PanicException::from_panic_payload(payload)))
326365
{
366+
// SAFETY: caller upholds requirements
327367
py_err.write_unraisable(py, unsafe { ctx.assume_borrowed_or_opt(py) }.as_deref());
328368
}
329369
trap.disarm();

src/impl_/unindent.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
#![warn(clippy::undocumented_unsafe_blocks)]
2+
13
use crate::impl_::concat::slice_copy_from_slice;
24

35
/// This is a reimplementation of the `indoc` crate's unindent functionality:

src/impl_/wrap.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
#![warn(clippy::undocumented_unsafe_blocks)]
2+
13
use std::{convert::Infallible, marker::PhantomData, ops::Deref};
24

35
use crate::{

0 commit comments

Comments
 (0)