Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix unintentional unsafe_op_in_unsafe_fn trigger #4674

Merged
merged 2 commits into from
Nov 2, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions newsfragments/4674.fixed.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Fixes unintentional `unsafe_op_in_unsafe_fn` trigger by adjusting macro hygiene.
30 changes: 17 additions & 13 deletions pyo3-macros-backend/src/method.rs
Original file line number Diff line number Diff line change
Expand Up @@ -270,9 +270,9 @@ impl FnType {
::std::convert::Into::into(
#pyo3_path::impl_::pymethods::BoundRef::ref_from_ptr(#py, &*(&#slf as *const _ as *const *mut _))
.downcast_unchecked::<#pyo3_path::types::PyType>()
),
)
};
Some(ret)
Some(quote! { unsafe { #ret }, })
}
FnType::FnModule(span) => {
let py = syn::Ident::new("py", Span::call_site());
Expand All @@ -283,9 +283,9 @@ impl FnType {
::std::convert::Into::into(
#pyo3_path::impl_::pymethods::BoundRef::ref_from_ptr(#py, &*(&#slf as *const _ as *const *mut _))
.downcast_unchecked::<#pyo3_path::types::PyModule>()
),
)
};
Some(ret)
Some(quote! { unsafe { #ret }, })
}
FnType::FnNew | FnType::FnStatic | FnType::ClassAttribute => None,
}
Expand Down Expand Up @@ -332,6 +332,8 @@ impl SelfType {
let py = syn::Ident::new("py", Span::call_site());
let slf = syn::Ident::new("_slf", Span::call_site());
let Ctx { pyo3_path, .. } = ctx;
let bound_ref =
quote! { unsafe { #pyo3_path::impl_::pymethods::BoundRef::ref_from_ptr(#py, &#slf) } };
match self {
SelfType::Receiver { span, mutable } => {
let method = if *mutable {
Expand All @@ -344,7 +346,7 @@ impl SelfType {
error_mode.handle_error(
quote_spanned! { *span =>
#pyo3_path::impl_::extract_argument::#method::<#cls>(
#pyo3_path::impl_::pymethods::BoundRef::ref_from_ptr(#py, &#slf).0,
#bound_ref.0,
&mut #holder,
)
},
Expand All @@ -355,7 +357,7 @@ impl SelfType {
let pyo3_path = pyo3_path.to_tokens_spanned(*span);
error_mode.handle_error(
quote_spanned! { *span =>
#pyo3_path::impl_::pymethods::BoundRef::ref_from_ptr(#py, &#slf).downcast::<#cls>()
#bound_ref.downcast::<#cls>()
.map_err(::std::convert::Into::<#pyo3_path::PyErr>::into)
.and_then(
#[allow(unknown_lints, clippy::unnecessary_fallible_conversions)] // In case slf is Py<Self> (unknown_lints can be removed when MSRV is 1.75+)
Expand Down Expand Up @@ -665,14 +667,14 @@ impl<'a> FnSpec<'a> {
FnType::Fn(SelfType::Receiver { mutable: false, .. }) => {
quote! {{
#(let #arg_names = #args;)*
let __guard = #pyo3_path::impl_::coroutine::RefGuard::<#cls>::new(&#pyo3_path::impl_::pymethods::BoundRef::ref_from_ptr(py, &_slf))?;
let __guard = unsafe { #pyo3_path::impl_::coroutine::RefGuard::<#cls>::new(&#pyo3_path::impl_::pymethods::BoundRef::ref_from_ptr(py, &_slf))? };
async move { function(&__guard, #(#arg_names),*).await }
}}
}
FnType::Fn(SelfType::Receiver { mutable: true, .. }) => {
quote! {{
#(let #arg_names = #args;)*
let mut __guard = #pyo3_path::impl_::coroutine::RefMutGuard::<#cls>::new(&#pyo3_path::impl_::pymethods::BoundRef::ref_from_ptr(py, &_slf))?;
let mut __guard = unsafe { #pyo3_path::impl_::coroutine::RefMutGuard::<#cls>::new(&#pyo3_path::impl_::pymethods::BoundRef::ref_from_ptr(py, &_slf))? };
async move { function(&mut __guard, #(#arg_names),*).await }
}}
}
Expand Down Expand Up @@ -862,11 +864,13 @@ impl<'a> FnSpec<'a> {
_args: *mut #pyo3_path::ffi::PyObject,
) -> *mut #pyo3_path::ffi::PyObject
{
#pyo3_path::impl_::trampoline::noargs(
_slf,
_args,
#wrapper
)
unsafe {
#pyo3_path::impl_::trampoline::noargs(
_slf,
_args,
#wrapper
)
}
}
trampoline
},
Expand Down
2 changes: 1 addition & 1 deletion pyo3-macros-backend/src/module.rs
Original file line number Diff line number Diff line change
Expand Up @@ -449,7 +449,7 @@ fn module_initialization(
#[doc(hidden)]
#[export_name = #pyinit_symbol]
pub unsafe extern "C" fn __pyo3_init() -> *mut #pyo3_path::ffi::PyObject {
#pyo3_path::impl_::trampoline::module_init(|py| _PYO3_DEF.make_module(py))
unsafe { #pyo3_path::impl_::trampoline::module_init(|py| _PYO3_DEF.make_module(py)) }
}
});
}
Expand Down
5 changes: 3 additions & 2 deletions pyo3-macros-backend/src/params.rs
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ pub fn impl_arg_params(
.collect();
return (
quote! {
let _args = #pyo3_path::impl_::pymethods::BoundRef::ref_from_ptr(py, &_args);
let _args = unsafe { #pyo3_path::impl_::pymethods::BoundRef::ref_from_ptr(py, &_args) };
let _kwargs = #pyo3_path::impl_::pymethods::BoundRef::ref_from_ptr_or_opt(py, &_kwargs);
#from_py_with
},
Expand Down Expand Up @@ -301,9 +301,10 @@ pub(crate) fn impl_regular_arg_param(
}
} else {
let holder = holders.push_holder(arg.name.span());
let unwrap = quote! {unsafe { #pyo3_path::impl_::extract_argument::unwrap_required_argument(#arg_value) }};
quote_arg_span! {
#pyo3_path::impl_::extract_argument::extract_argument(
#pyo3_path::impl_::extract_argument::unwrap_required_argument(#arg_value),
#unwrap,
&mut #holder,
#name_str
)?
Expand Down
39 changes: 20 additions & 19 deletions pyo3-macros-backend/src/pymethod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1182,25 +1182,26 @@ fn extract_object(
let Ctx { pyo3_path, .. } = ctx;
let name = arg.name().unraw().to_string();

let extract =
if let Some(from_py_with) = arg.from_py_with().map(|from_py_with| &from_py_with.value) {
quote! {
#pyo3_path::impl_::extract_argument::from_py_with(
#pyo3_path::impl_::pymethods::BoundRef::ref_from_ptr(py, &#source_ptr).0,
#name,
#from_py_with as fn(_) -> _,
)
}
} else {
let holder = holders.push_holder(Span::call_site());
quote! {
#pyo3_path::impl_::extract_argument::extract_argument(
#pyo3_path::impl_::pymethods::BoundRef::ref_from_ptr(py, &#source_ptr).0,
&mut #holder,
#name
)
}
};
let extract = if let Some(from_py_with) =
arg.from_py_with().map(|from_py_with| &from_py_with.value)
{
quote! {
#pyo3_path::impl_::extract_argument::from_py_with(
unsafe { #pyo3_path::impl_::pymethods::BoundRef::ref_from_ptr(py, &#source_ptr).0 },
#name,
#from_py_with as fn(_) -> _,
)
}
} else {
let holder = holders.push_holder(Span::call_site());
quote! {
#pyo3_path::impl_::extract_argument::extract_argument(
unsafe { #pyo3_path::impl_::pymethods::BoundRef::ref_from_ptr(py, &#source_ptr).0 },
&mut #holder,
#name
)
}
};

let extracted = extract_error_mode.handle_error(extract, ctx);
quote!(#extracted)
Expand Down
1 change: 1 addition & 0 deletions tests/ui/forbid_unsafe.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
#![forbid(unsafe_code)]
#![forbid(unsafe_op_in_unsafe_fn)]

use pyo3::*;

Expand Down
Loading