@@ -70,6 +70,7 @@ impl AttachGuard {
7070 Err ( AttachError :: NotInitialized ) => {
7171 // try to initialize the interpreter and try again
7272 crate :: interpreter_lifecycle:: ensure_initialized ( ) ;
73+ // SAFETY: The interpreter is now initialized and the thread is not attached.
7374 unsafe { Self :: do_attach_unchecked ( ) }
7475 }
7576 #[ cfg( Py_3_13 ) ]
@@ -127,9 +128,12 @@ impl AttachGuard {
127128 /// for a thread to be able to attach to it.
128129 pub ( crate ) unsafe fn attach_unchecked ( ) -> Self {
129130 if thread_is_attached ( ) {
131+ // SAFETY: We just checked that the thread is already attached.
132+ // And the caller promised that the interpreter is initialized.
130133 return unsafe { Self :: assume ( ) } ;
131134 }
132135
136+ // SAFETY: The caller promised that the interpreter is initialized.
133137 unsafe { Self :: do_attach_unchecked ( ) }
134138 }
135139
@@ -166,6 +170,7 @@ impl Drop for AttachGuard {
166170 fn drop ( & mut self ) {
167171 match self {
168172 AttachGuard :: Assumed => { }
173+ // SAFETY: we are dropping an `AttachGuard` that previously called `PyGILState_Ensure`
169174 AttachGuard :: Ensured { gstate } => unsafe {
170175 // Drop the objects in the pool before attempting to release the thread state
171176 ffi:: PyGILState_Release ( * gstate) ;
@@ -206,14 +211,17 @@ impl ReferencePool {
206211 drop ( pending_decrefs) ;
207212
208213 for ptr in decrefs {
214+ // SAFETY: `ptr` is a valid owned reference that was registered via `register_decref`.
209215 unsafe { ffi:: Py_DECREF ( ptr. as_ptr ( ) ) } ;
210216 }
211217 }
212218}
213219
220+ // SAFETY: `ReferencePool` only contains a `Mutex`
214221#[ cfg( not( pyo3_disable_reference_pool) ) ]
215222unsafe impl Send for ReferencePool { }
216223
224+ // SAFETY: `ReferencePool` only contains a `Mutex`
217225#[ cfg( not( pyo3_disable_reference_pool) ) ]
218226unsafe impl Sync for ReferencePool { }
219227
@@ -243,6 +251,7 @@ pub(crate) struct SuspendAttach {
243251impl SuspendAttach {
244252 pub ( crate ) unsafe fn new ( ) -> Self {
245253 let count = ATTACH_COUNT . with ( |c| c. replace ( 0 ) ) ;
254+ // SAFETY: caller must ensure the thread is currently attached.
246255 let tstate = unsafe { ffi:: PyEval_SaveThread ( ) } ;
247256
248257 Self { count, tstate }
@@ -252,6 +261,9 @@ impl SuspendAttach {
252261impl Drop for SuspendAttach {
253262 fn drop ( & mut self ) {
254263 ATTACH_COUNT . with ( |c| c. set ( self . count ) ) ;
264+ // SAFETY: `self.tstate` is a valid thread state that was saved by `PyEval_SaveThread()`
265+ // in `SuspendAttach::new()`. We restore the attach count before calling
266+ // `PyEval_RestoreThread`, so `Python::assume_attached()` is valid after the restore.
255267 unsafe {
256268 ffi:: PyEval_RestoreThread ( self . tstate ) ;
257269
0 commit comments