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
92108pub 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
99116pub 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 ) ) ]
208233pub 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 ) ) ]
216242pub 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]
228264pub ( 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]
265304pub ( 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 ( ) ;
0 commit comments