From 4f9b2ef3b2202513efb47cc145676cc6d305610d Mon Sep 17 00:00:00 2001 From: Bas Schoenmaeckers Date: Mon, 13 Jul 2026 13:27:31 +0200 Subject: [PATCH 1/4] Add codecs support to c-apo --- crates/capi/src/codecs.rs | 308 ++++++++++++++++++++++++++++++++++++++ crates/capi/src/lib.rs | 1 + 2 files changed, 309 insertions(+) create mode 100644 crates/capi/src/codecs.rs diff --git a/crates/capi/src/codecs.rs b/crates/capi/src/codecs.rs new file mode 100644 index 00000000000..390e6108752 --- /dev/null +++ b/crates/capi/src/codecs.rs @@ -0,0 +1,308 @@ +use crate::{PyObject, pystate::with_vm}; +use core::ffi::{CStr, c_char, c_int}; +use rustpython_vm::AsObject; + +#[unsafe(no_mangle)] +pub unsafe extern "C" fn PyCodec_Register(search_function: *mut PyObject) -> c_int { + with_vm(|vm| { + let search_function = unsafe { &*search_function }.to_owned(); + vm.state.codec_registry.register(search_function, vm) + }) +} + +#[unsafe(no_mangle)] +pub unsafe extern "C" fn PyCodec_Unregister(search_function: *mut PyObject) -> c_int { + with_vm(|vm| { + let search_function = unsafe { &*search_function }.to_owned(); + vm.state.codec_registry.unregister(search_function); + }) +} + +#[unsafe(no_mangle)] +pub unsafe extern "C" fn PyCodec_KnownEncoding(encoding: *const c_char) -> c_int { + with_vm(|vm| { + let encoding = unsafe { CStr::from_ptr(encoding) } + .to_str() + .map_err(|_| vm.new_system_error("encoding must be valid UTF-8"))?; + match vm.state.codec_registry.lookup(encoding, vm) { + Ok(_) => Ok(true), + Err(err) if err.fast_isinstance(vm.ctx.exceptions.lookup_error) => Ok(false), + Err(err) => Err(err), + } + }) +} + +#[unsafe(no_mangle)] +pub unsafe extern "C" fn PyCodec_Encode( + object: *mut PyObject, + encoding: *const c_char, + errors: *const c_char, +) -> *mut PyObject { + with_vm(|vm| { + let object = unsafe { &*object }.to_owned(); + let encoding = if encoding.is_null() { + "utf-8" + } else { + unsafe { CStr::from_ptr(encoding) } + .to_str() + .map_err(|_| vm.new_system_error("encoding must be valid UTF-8"))? + }; + let errors = if errors.is_null() { + None + } else { + let errors = unsafe { CStr::from_ptr(errors) } + .to_str() + .map_err(|_| vm.new_system_error("errors must be valid UTF-8"))?; + Some(vm.ctx.new_utf8_str(errors)) + }; + vm.state.codec_registry.encode(object, encoding, errors, vm) + }) +} + +#[unsafe(no_mangle)] +pub unsafe extern "C" fn PyCodec_Decode( + object: *mut PyObject, + encoding: *const c_char, + errors: *const c_char, +) -> *mut PyObject { + with_vm(|vm| { + let object = unsafe { &*object }.to_owned(); + let encoding = if encoding.is_null() { + "utf-8" + } else { + unsafe { CStr::from_ptr(encoding) } + .to_str() + .map_err(|_| vm.new_system_error("encoding must be valid UTF-8"))? + }; + let errors = if errors.is_null() { + None + } else { + let errors = unsafe { CStr::from_ptr(errors) } + .to_str() + .map_err(|_| vm.new_system_error("errors must be valid UTF-8"))?; + Some(vm.ctx.new_utf8_str(errors)) + }; + vm.state.codec_registry.decode(object, encoding, errors, vm) + }) +} + +#[unsafe(no_mangle)] +pub unsafe extern "C" fn PyCodec_Encoder(encoding: *const c_char) -> *mut PyObject { + with_vm(|vm| { + let encoding = unsafe { CStr::from_ptr(encoding) } + .to_str() + .map_err(|_| vm.new_system_error("encoding must be valid UTF-8"))?; + vm.state + .codec_registry + .lookup(encoding, vm) + .map(|codec| codec.get_encode_func().to_owned()) + }) +} + +#[unsafe(no_mangle)] +pub unsafe extern "C" fn PyCodec_Decoder(encoding: *const c_char) -> *mut PyObject { + with_vm(|vm| { + let encoding = unsafe { CStr::from_ptr(encoding) } + .to_str() + .map_err(|_| vm.new_system_error("encoding must be valid UTF-8"))?; + vm.state + .codec_registry + .lookup(encoding, vm) + .map(|codec| codec.get_decode_func().to_owned()) + }) +} + +#[unsafe(no_mangle)] +pub unsafe extern "C" fn PyCodec_IncrementalEncoder( + encoding: *const c_char, + errors: *const c_char, +) -> *mut PyObject { + with_vm(|vm| { + let encoding = unsafe { CStr::from_ptr(encoding) } + .to_str() + .map_err(|_| vm.new_system_error("encoding must be valid UTF-8"))?; + let errors = if errors.is_null() { + None + } else { + let errors = unsafe { CStr::from_ptr(errors) } + .to_str() + .map_err(|_| vm.new_system_error("errors must be valid UTF-8"))?; + Some(vm.ctx.new_str(errors)) + }; + let codec = vm.state.codec_registry.lookup(encoding, vm)?; + codec.get_incremental_encoder(errors, vm) + }) +} + +#[unsafe(no_mangle)] +pub unsafe extern "C" fn PyCodec_IncrementalDecoder( + encoding: *const c_char, + errors: *const c_char, +) -> *mut PyObject { + with_vm(|vm| { + let encoding = unsafe { CStr::from_ptr(encoding) } + .to_str() + .map_err(|_| vm.new_system_error("encoding must be valid UTF-8"))?; + let errors = if errors.is_null() { + None + } else { + let errors = unsafe { CStr::from_ptr(errors) } + .to_str() + .map_err(|_| vm.new_system_error("errors must be valid UTF-8"))?; + Some(vm.ctx.new_str(errors)) + }; + let codec = vm.state.codec_registry.lookup(encoding, vm)?; + codec.get_incremental_decoder(errors, vm) + }) +} + +#[unsafe(no_mangle)] +pub unsafe extern "C" fn PyCodec_StreamReader( + encoding: *const c_char, + stream: *mut PyObject, + errors: *const c_char, +) -> *mut PyObject { + with_vm(|vm| { + let encoding = if encoding.is_null() { + "utf-8" + } else { + unsafe { CStr::from_ptr(encoding) } + .to_str() + .map_err(|_| vm.new_system_error("encoding must be valid UTF-8"))? + }; + let errors = if errors.is_null() { + None + } else { + let errors = unsafe { CStr::from_ptr(errors) } + .to_str() + .map_err(|_| vm.new_system_error("errors must be valid UTF-8"))?; + Some(vm.ctx.new_str(errors)) + }; + let stream = unsafe { &*stream }.to_owned(); + let codec = vm.state.codec_registry.lookup(encoding, vm)?; + let args = match errors { + Some(errors) => vec![stream, errors.into()], + None => vec![stream], + }; + vm.call_method(codec.as_tuple().as_object(), "streamreader", args) + }) +} + +#[unsafe(no_mangle)] +pub unsafe extern "C" fn PyCodec_StreamWriter( + encoding: *const c_char, + stream: *mut PyObject, + errors: *const c_char, +) -> *mut PyObject { + with_vm(|vm| { + let encoding = if encoding.is_null() { + "utf-8" + } else { + unsafe { CStr::from_ptr(encoding) } + .to_str() + .map_err(|_| vm.new_system_error("encoding must be valid UTF-8"))? + }; + let errors = if errors.is_null() { + None + } else { + let errors = unsafe { CStr::from_ptr(errors) } + .to_str() + .map_err(|_| vm.new_system_error("errors must be valid UTF-8"))?; + Some(vm.ctx.new_str(errors)) + }; + let stream = unsafe { &*stream }.to_owned(); + let codec = vm.state.codec_registry.lookup(encoding, vm)?; + let args = match errors { + Some(errors) => vec![stream, errors.into()], + None => vec![stream], + }; + vm.call_method(codec.as_tuple().as_object(), "streamwriter", args) + }) +} + +#[unsafe(no_mangle)] +pub unsafe extern "C" fn PyCodec_RegisterError(name: *const c_char, error: *mut PyObject) -> c_int { + with_vm(|vm| { + let name = unsafe { CStr::from_ptr(name) } + .to_str() + .map_err(|_| vm.new_system_error("name must be valid UTF-8"))?; + let error = unsafe { &*error }.to_owned(); + if !error.is_callable() { + return Err(vm.new_type_error("handler must be callable")); + } + vm.state + .codec_registry + .register_error(name.to_owned(), error); + Ok(()) + }) +} + +#[unsafe(no_mangle)] +pub unsafe extern "C" fn PyCodec_LookupError(name: *const c_char) -> *mut PyObject { + with_vm(|vm| { + let name = unsafe { CStr::from_ptr(name) } + .to_str() + .map_err(|_| vm.new_system_error("name must be valid UTF-8"))?; + vm.state.codec_registry.lookup_error(name, vm) + }) +} + +#[unsafe(no_mangle)] +pub unsafe extern "C" fn PyCodec_StrictErrors(exc: *mut PyObject) -> *mut PyObject { + with_vm(|vm| { + let err = vm.state.codec_registry.lookup_error("strict", vm)?; + let exc = unsafe { &*exc }.to_owned(); + err.call((exc,), vm) + }) +} + +#[unsafe(no_mangle)] +pub unsafe extern "C" fn PyCodec_IgnoreErrors(exc: *mut PyObject) -> *mut PyObject { + with_vm(|vm| { + let err = vm.state.codec_registry.lookup_error("ignore", vm)?; + let exc = unsafe { &*exc }.to_owned(); + err.call((exc,), vm) + }) +} + +#[unsafe(no_mangle)] +pub unsafe extern "C" fn PyCodec_ReplaceErrors(exc: *mut PyObject) -> *mut PyObject { + with_vm(|vm| { + let err = vm.state.codec_registry.lookup_error("replace", vm)?; + let exc = unsafe { &*exc }.to_owned(); + err.call((exc,), vm) + }) +} + +#[unsafe(no_mangle)] +pub unsafe extern "C" fn PyCodec_XMLCharRefReplaceErrors(exc: *mut PyObject) -> *mut PyObject { + with_vm(|vm| { + let err = vm + .state + .codec_registry + .lookup_error("xmlcharrefreplace", vm)?; + let exc = unsafe { &*exc }.to_owned(); + err.call((exc,), vm) + }) +} + +#[unsafe(no_mangle)] +pub unsafe extern "C" fn PyCodec_BackslashReplaceErrors(exc: *mut PyObject) -> *mut PyObject { + with_vm(|vm| { + let err = vm + .state + .codec_registry + .lookup_error("backslashreplace", vm)?; + let exc = unsafe { &*exc }.to_owned(); + err.call((exc,), vm) + }) +} + +#[unsafe(no_mangle)] +pub unsafe extern "C" fn PyCodec_NameReplaceErrors(exc: *mut PyObject) -> *mut PyObject { + with_vm(|vm| { + let err = vm.state.codec_registry.lookup_error("namereplace", vm)?; + let exc = unsafe { &*exc }.to_owned(); + err.call((exc,), vm) + }) +} diff --git a/crates/capi/src/lib.rs b/crates/capi/src/lib.rs index 08bb09bf3b5..374fd3301d6 100644 --- a/crates/capi/src/lib.rs +++ b/crates/capi/src/lib.rs @@ -13,6 +13,7 @@ pub mod boolobject; pub mod bytearrayobject; pub mod bytesobject; pub mod ceval; +pub mod codecs; pub mod complexobject; pub mod critical_section; pub mod descrobject; From a65d9c4cc6c1ae3beeade709044ad838f0150c91 Mon Sep 17 00:00:00 2001 From: Bas Schoenmaeckers Date: Wed, 15 Jul 2026 17:15:32 +0200 Subject: [PATCH 2/4] Reduce code duplication --- crates/capi/src/abstract_.rs | 7 +- crates/capi/src/abstract_/mapping.rs | 21 +-- crates/capi/src/codecs.rs | 208 +++++++-------------------- crates/capi/src/descrobject.rs | 20 +-- crates/capi/src/dictobject.rs | 19 +-- crates/capi/src/import.rs | 16 +-- crates/capi/src/methodobject.rs | 15 +- crates/capi/src/object.rs | 27 ++-- crates/capi/src/pycapsule.rs | 5 +- crates/capi/src/pyerrors.rs | 27 ++-- crates/capi/src/unicodeobject.rs | 37 +---- crates/capi/src/util.rs | 30 ++++ crates/capi/src/warnings.rs | 23 ++- crates/vm/src/sequence.rs | 2 +- 14 files changed, 150 insertions(+), 307 deletions(-) diff --git a/crates/capi/src/abstract_.rs b/crates/capi/src/abstract_.rs index 36d949a3022..08b4e540029 100644 --- a/crates/capi/src/abstract_.rs +++ b/crates/capi/src/abstract_.rs @@ -1,6 +1,7 @@ +use crate::util::CStrExt; use crate::{PyObject, pystate::with_vm}; use alloc::slice; -use core::ffi::{CStr, c_char, c_int}; +use core::ffi::{c_char, c_int}; pub use iter::*; pub use mapping::*; pub use number::*; @@ -208,9 +209,7 @@ pub unsafe extern "C" fn PyObject_DelItem(obj: *mut PyObject, key: *mut PyObject pub unsafe extern "C" fn PyObject_DelItemString(obj: *mut PyObject, key: *const c_char) -> c_int { with_vm(|vm| { let obj = unsafe { &*obj }; - let key = unsafe { CStr::from_ptr(key) } - .to_str() - .map_err(|_| vm.new_value_error("mapping key must be valid UTF-8"))?; + let key = unsafe { key.try_as_str(vm) }?; obj.del_item(key, vm) }) } diff --git a/crates/capi/src/abstract_/mapping.rs b/crates/capi/src/abstract_/mapping.rs index 6fec18bffd6..840a9aed69c 100644 --- a/crates/capi/src/abstract_/mapping.rs +++ b/crates/capi/src/abstract_/mapping.rs @@ -1,5 +1,6 @@ +use crate::util::CStrExt; use crate::{PyObject, pystate::with_vm}; -use core::ffi::{CStr, c_char, c_int}; +use core::ffi::{c_char, c_int}; use rustpython_vm::AsObject; #[unsafe(no_mangle)] @@ -60,9 +61,7 @@ pub unsafe extern "C" fn PyMapping_GetItemString( ) -> *mut PyObject { with_vm(|vm| { let obj = unsafe { &*obj }; - let key = unsafe { CStr::from_ptr(key) } - .to_str() - .map_err(|_| vm.new_value_error("mapping key must be valid UTF-8"))?; + let key = unsafe { key.try_as_str(vm) }?; obj.get_item(key, vm) }) } @@ -104,9 +103,7 @@ pub unsafe extern "C" fn PyMapping_GetOptionalItemString( *result = core::ptr::null_mut(); } let obj = unsafe { &*obj }; - let key = unsafe { CStr::from_ptr(key) } - .to_str() - .map_err(|_| vm.new_value_error("mapping key must be valid UTF-8"))?; + let key = unsafe { key.try_as_str(vm) }?; match obj.get_item(key, vm) { Ok(value) => { @@ -134,7 +131,7 @@ pub unsafe extern "C" fn PyMapping_HasKey(obj: *mut PyObject, key: *mut PyObject pub unsafe extern "C" fn PyMapping_HasKeyString(obj: *mut PyObject, key: *const c_char) -> c_int { with_vm(|vm| { let obj = unsafe { &*obj }; - if let Ok(key) = unsafe { CStr::from_ptr(key) }.to_str() { + if let Ok(key) = unsafe { key.try_as_str(vm) } { obj.get_item(key, vm).is_ok() } else { false @@ -166,9 +163,7 @@ pub unsafe extern "C" fn PyMapping_HasKeyStringWithError( ) -> c_int { with_vm(|vm| { let obj = unsafe { &*obj }; - let key = unsafe { CStr::from_ptr(key) } - .to_str() - .map_err(|_| vm.new_value_error("mapping key must be valid UTF-8"))?; + let key = unsafe { key.try_as_str(vm) }?; match obj.get_item(key, vm) { Ok(_) => Ok(true), @@ -186,9 +181,7 @@ pub unsafe extern "C" fn PyMapping_SetItemString( ) -> c_int { with_vm(|vm| { let obj = unsafe { &*obj }; - let key = unsafe { CStr::from_ptr(key) } - .to_str() - .map_err(|_| vm.new_value_error("mapping key must be valid UTF-8"))?; + let key = unsafe { key.try_as_str(vm) }?; let value = unsafe { &*value }.to_owned(); obj.set_item(key, value, vm) }) diff --git a/crates/capi/src/codecs.rs b/crates/capi/src/codecs.rs index 390e6108752..8433bf3baa4 100644 --- a/crates/capi/src/codecs.rs +++ b/crates/capi/src/codecs.rs @@ -1,6 +1,36 @@ +use crate::util::CStrExt; use crate::{PyObject, pystate::with_vm}; -use core::ffi::{CStr, c_char, c_int}; -use rustpython_vm::AsObject; +use core::ffi::{c_char, c_int}; +use rustpython_vm::{AsObject, VirtualMachine}; + +fn call_codec_error_handler( + vm: &VirtualMachine, + handler_name: &str, + exc: *mut PyObject, +) -> rustpython_vm::PyResult { + vm.state + .codec_registry + .lookup_error(handler_name, vm)? + .call((unsafe { &*exc }.to_owned(),), vm) +} + +fn codec_stream( + vm: &VirtualMachine, + encoding: *const c_char, + stream: *mut PyObject, + errors: *const c_char, + method: &str, +) -> rustpython_vm::PyResult { + let encoding = unsafe { encoding.try_as_str_opt(vm) }?.unwrap_or("utf-8"); + let errors = unsafe { errors.try_as_str_opt(vm) }?.map(|errors| vm.ctx.new_str(errors)); + let stream = unsafe { &*stream }.to_owned(); + let codec = vm.state.codec_registry.lookup(encoding, vm)?; + let args = match errors { + Some(errors) => vec![stream, errors.into()], + None => vec![stream], + }; + vm.call_method(codec.as_tuple().as_object(), method, args) +} #[unsafe(no_mangle)] pub unsafe extern "C" fn PyCodec_Register(search_function: *mut PyObject) -> c_int { @@ -21,9 +51,7 @@ pub unsafe extern "C" fn PyCodec_Unregister(search_function: *mut PyObject) -> c #[unsafe(no_mangle)] pub unsafe extern "C" fn PyCodec_KnownEncoding(encoding: *const c_char) -> c_int { with_vm(|vm| { - let encoding = unsafe { CStr::from_ptr(encoding) } - .to_str() - .map_err(|_| vm.new_system_error("encoding must be valid UTF-8"))?; + let encoding = unsafe { encoding.try_as_str(vm) }?; match vm.state.codec_registry.lookup(encoding, vm) { Ok(_) => Ok(true), Err(err) if err.fast_isinstance(vm.ctx.exceptions.lookup_error) => Ok(false), @@ -40,21 +68,9 @@ pub unsafe extern "C" fn PyCodec_Encode( ) -> *mut PyObject { with_vm(|vm| { let object = unsafe { &*object }.to_owned(); - let encoding = if encoding.is_null() { - "utf-8" - } else { - unsafe { CStr::from_ptr(encoding) } - .to_str() - .map_err(|_| vm.new_system_error("encoding must be valid UTF-8"))? - }; - let errors = if errors.is_null() { - None - } else { - let errors = unsafe { CStr::from_ptr(errors) } - .to_str() - .map_err(|_| vm.new_system_error("errors must be valid UTF-8"))?; - Some(vm.ctx.new_utf8_str(errors)) - }; + let encoding = unsafe { encoding.try_as_str_opt(vm) }?.unwrap_or("utf-8"); + let errors = + unsafe { errors.try_as_str_opt(vm) }?.map(|errors| vm.ctx.new_utf8_str(errors)); vm.state.codec_registry.encode(object, encoding, errors, vm) }) } @@ -67,21 +83,9 @@ pub unsafe extern "C" fn PyCodec_Decode( ) -> *mut PyObject { with_vm(|vm| { let object = unsafe { &*object }.to_owned(); - let encoding = if encoding.is_null() { - "utf-8" - } else { - unsafe { CStr::from_ptr(encoding) } - .to_str() - .map_err(|_| vm.new_system_error("encoding must be valid UTF-8"))? - }; - let errors = if errors.is_null() { - None - } else { - let errors = unsafe { CStr::from_ptr(errors) } - .to_str() - .map_err(|_| vm.new_system_error("errors must be valid UTF-8"))?; - Some(vm.ctx.new_utf8_str(errors)) - }; + let encoding = unsafe { encoding.try_as_str_opt(vm) }?.unwrap_or("utf-8"); + let errors = + unsafe { errors.try_as_str_opt(vm) }?.map(|errors| vm.ctx.new_utf8_str(errors)); vm.state.codec_registry.decode(object, encoding, errors, vm) }) } @@ -89,9 +93,7 @@ pub unsafe extern "C" fn PyCodec_Decode( #[unsafe(no_mangle)] pub unsafe extern "C" fn PyCodec_Encoder(encoding: *const c_char) -> *mut PyObject { with_vm(|vm| { - let encoding = unsafe { CStr::from_ptr(encoding) } - .to_str() - .map_err(|_| vm.new_system_error("encoding must be valid UTF-8"))?; + let encoding = unsafe { encoding.try_as_str(vm) }?; vm.state .codec_registry .lookup(encoding, vm) @@ -102,9 +104,7 @@ pub unsafe extern "C" fn PyCodec_Encoder(encoding: *const c_char) -> *mut PyObje #[unsafe(no_mangle)] pub unsafe extern "C" fn PyCodec_Decoder(encoding: *const c_char) -> *mut PyObject { with_vm(|vm| { - let encoding = unsafe { CStr::from_ptr(encoding) } - .to_str() - .map_err(|_| vm.new_system_error("encoding must be valid UTF-8"))?; + let encoding = unsafe { encoding.try_as_str(vm) }?; vm.state .codec_registry .lookup(encoding, vm) @@ -118,17 +118,8 @@ pub unsafe extern "C" fn PyCodec_IncrementalEncoder( errors: *const c_char, ) -> *mut PyObject { with_vm(|vm| { - let encoding = unsafe { CStr::from_ptr(encoding) } - .to_str() - .map_err(|_| vm.new_system_error("encoding must be valid UTF-8"))?; - let errors = if errors.is_null() { - None - } else { - let errors = unsafe { CStr::from_ptr(errors) } - .to_str() - .map_err(|_| vm.new_system_error("errors must be valid UTF-8"))?; - Some(vm.ctx.new_str(errors)) - }; + let encoding = unsafe { encoding.try_as_str(vm) }?; + let errors = unsafe { errors.try_as_str_opt(vm) }?.map(|s| vm.ctx.new_str(s)); let codec = vm.state.codec_registry.lookup(encoding, vm)?; codec.get_incremental_encoder(errors, vm) }) @@ -140,17 +131,8 @@ pub unsafe extern "C" fn PyCodec_IncrementalDecoder( errors: *const c_char, ) -> *mut PyObject { with_vm(|vm| { - let encoding = unsafe { CStr::from_ptr(encoding) } - .to_str() - .map_err(|_| vm.new_system_error("encoding must be valid UTF-8"))?; - let errors = if errors.is_null() { - None - } else { - let errors = unsafe { CStr::from_ptr(errors) } - .to_str() - .map_err(|_| vm.new_system_error("errors must be valid UTF-8"))?; - Some(vm.ctx.new_str(errors)) - }; + let encoding = unsafe { encoding.try_as_str(vm) }?; + let errors = unsafe { errors.try_as_str_opt(vm) }?.map(|s| vm.ctx.new_str(s)); let codec = vm.state.codec_registry.lookup(encoding, vm)?; codec.get_incremental_decoder(errors, vm) }) @@ -162,30 +144,7 @@ pub unsafe extern "C" fn PyCodec_StreamReader( stream: *mut PyObject, errors: *const c_char, ) -> *mut PyObject { - with_vm(|vm| { - let encoding = if encoding.is_null() { - "utf-8" - } else { - unsafe { CStr::from_ptr(encoding) } - .to_str() - .map_err(|_| vm.new_system_error("encoding must be valid UTF-8"))? - }; - let errors = if errors.is_null() { - None - } else { - let errors = unsafe { CStr::from_ptr(errors) } - .to_str() - .map_err(|_| vm.new_system_error("errors must be valid UTF-8"))?; - Some(vm.ctx.new_str(errors)) - }; - let stream = unsafe { &*stream }.to_owned(); - let codec = vm.state.codec_registry.lookup(encoding, vm)?; - let args = match errors { - Some(errors) => vec![stream, errors.into()], - None => vec![stream], - }; - vm.call_method(codec.as_tuple().as_object(), "streamreader", args) - }) + with_vm(|vm| codec_stream(vm, encoding, stream, errors, "streamreader")) } #[unsafe(no_mangle)] @@ -194,38 +153,13 @@ pub unsafe extern "C" fn PyCodec_StreamWriter( stream: *mut PyObject, errors: *const c_char, ) -> *mut PyObject { - with_vm(|vm| { - let encoding = if encoding.is_null() { - "utf-8" - } else { - unsafe { CStr::from_ptr(encoding) } - .to_str() - .map_err(|_| vm.new_system_error("encoding must be valid UTF-8"))? - }; - let errors = if errors.is_null() { - None - } else { - let errors = unsafe { CStr::from_ptr(errors) } - .to_str() - .map_err(|_| vm.new_system_error("errors must be valid UTF-8"))?; - Some(vm.ctx.new_str(errors)) - }; - let stream = unsafe { &*stream }.to_owned(); - let codec = vm.state.codec_registry.lookup(encoding, vm)?; - let args = match errors { - Some(errors) => vec![stream, errors.into()], - None => vec![stream], - }; - vm.call_method(codec.as_tuple().as_object(), "streamwriter", args) - }) + with_vm(|vm| codec_stream(vm, encoding, stream, errors, "streamwriter")) } #[unsafe(no_mangle)] pub unsafe extern "C" fn PyCodec_RegisterError(name: *const c_char, error: *mut PyObject) -> c_int { with_vm(|vm| { - let name = unsafe { CStr::from_ptr(name) } - .to_str() - .map_err(|_| vm.new_system_error("name must be valid UTF-8"))?; + let name = unsafe { name.try_as_str(vm) }?; let error = unsafe { &*error }.to_owned(); if !error.is_callable() { return Err(vm.new_type_error("handler must be callable")); @@ -240,69 +174,37 @@ pub unsafe extern "C" fn PyCodec_RegisterError(name: *const c_char, error: *mut #[unsafe(no_mangle)] pub unsafe extern "C" fn PyCodec_LookupError(name: *const c_char) -> *mut PyObject { with_vm(|vm| { - let name = unsafe { CStr::from_ptr(name) } - .to_str() - .map_err(|_| vm.new_system_error("name must be valid UTF-8"))?; + let name = unsafe { name.try_as_str(vm) }?; vm.state.codec_registry.lookup_error(name, vm) }) } #[unsafe(no_mangle)] pub unsafe extern "C" fn PyCodec_StrictErrors(exc: *mut PyObject) -> *mut PyObject { - with_vm(|vm| { - let err = vm.state.codec_registry.lookup_error("strict", vm)?; - let exc = unsafe { &*exc }.to_owned(); - err.call((exc,), vm) - }) + with_vm(|vm| call_codec_error_handler(vm, "strict", exc)) } #[unsafe(no_mangle)] pub unsafe extern "C" fn PyCodec_IgnoreErrors(exc: *mut PyObject) -> *mut PyObject { - with_vm(|vm| { - let err = vm.state.codec_registry.lookup_error("ignore", vm)?; - let exc = unsafe { &*exc }.to_owned(); - err.call((exc,), vm) - }) + with_vm(|vm| call_codec_error_handler(vm, "ignore", exc)) } #[unsafe(no_mangle)] pub unsafe extern "C" fn PyCodec_ReplaceErrors(exc: *mut PyObject) -> *mut PyObject { - with_vm(|vm| { - let err = vm.state.codec_registry.lookup_error("replace", vm)?; - let exc = unsafe { &*exc }.to_owned(); - err.call((exc,), vm) - }) + with_vm(|vm| call_codec_error_handler(vm, "replace", exc)) } #[unsafe(no_mangle)] pub unsafe extern "C" fn PyCodec_XMLCharRefReplaceErrors(exc: *mut PyObject) -> *mut PyObject { - with_vm(|vm| { - let err = vm - .state - .codec_registry - .lookup_error("xmlcharrefreplace", vm)?; - let exc = unsafe { &*exc }.to_owned(); - err.call((exc,), vm) - }) + with_vm(|vm| call_codec_error_handler(vm, "xmlcharrefreplace", exc)) } #[unsafe(no_mangle)] pub unsafe extern "C" fn PyCodec_BackslashReplaceErrors(exc: *mut PyObject) -> *mut PyObject { - with_vm(|vm| { - let err = vm - .state - .codec_registry - .lookup_error("backslashreplace", vm)?; - let exc = unsafe { &*exc }.to_owned(); - err.call((exc,), vm) - }) + with_vm(|vm| call_codec_error_handler(vm, "backslashreplace", exc)) } #[unsafe(no_mangle)] pub unsafe extern "C" fn PyCodec_NameReplaceErrors(exc: *mut PyObject) -> *mut PyObject { - with_vm(|vm| { - let err = vm.state.codec_registry.lookup_error("namereplace", vm)?; - let exc = unsafe { &*exc }.to_owned(); - err.call((exc,), vm) - }) + with_vm(|vm| call_codec_error_handler(vm, "namereplace", exc)) } diff --git a/crates/capi/src/descrobject.rs b/crates/capi/src/descrobject.rs index ecc0b53f82a..863f286e13a 100644 --- a/crates/capi/src/descrobject.rs +++ b/crates/capi/src/descrobject.rs @@ -2,7 +2,8 @@ use crate::PyObject; use crate::methodobject::{PyMethodDef, build_method_def}; use crate::object::PyTypeObject; use crate::pystate::with_vm; -use core::ffi::{CStr, c_char, c_int, c_void}; +use crate::util::CStrExt; +use core::ffi::{c_char, c_int, c_void}; use core::ptr::NonNull; use rustpython_vm::builtins::{ DescriptorMemberDef, MemberGetter, MemberKind, MemberSetter, PyDescriptorOwned, PyGetSet, @@ -34,9 +35,7 @@ impl PyGetSetDef { ty: &'static Py, vm: &VirtualMachine, ) -> PyResult> { - let name = unsafe { CStr::from_ptr(self.name) } - .to_str() - .map_err(|_| vm.new_system_error("PyGetSetDef name was not valid UTF-8"))?; + let name = unsafe { self.name.try_as_str(vm) }?; let closure = self.closure as usize; let descriptor = match (self.get, self.set) { @@ -142,9 +141,7 @@ impl PyMemberDef { ty: &Py, vm: &VirtualMachine, ) -> PyResult> { - let name = unsafe { CStr::from_ptr(self.name) } - .to_str() - .map_err(|_| vm.new_system_error("PyMemberDef name was not valid UTF-8"))?; + let name = unsafe { self.name.try_as_str(vm) }?; let kind = match self.type_code { 6 => MemberKind::Object, 16 => MemberKind::ObjectEx, @@ -165,14 +162,7 @@ impl PyMemberDef { ); } - let doc = NonNull::new(self.doc.cast_mut()) - .map(|doc| { - unsafe { CStr::from_ptr(doc.as_ptr()) } - .to_str() - .map(|s| s.to_owned()) - .map_err(|_| vm.new_system_error("PyMemberDef doc was not valid UTF-8")) - }) - .transpose()?; + let doc = unsafe { self.doc.try_as_str_opt(vm) }?.map(str::to_owned); let descriptor = PyMemberDescriptor { common: PyDescriptorOwned { diff --git a/crates/capi/src/dictobject.rs b/crates/capi/src/dictobject.rs index 6cea9ea343c..ed29c693463 100644 --- a/crates/capi/src/dictobject.rs +++ b/crates/capi/src/dictobject.rs @@ -1,7 +1,8 @@ use crate::PyObject; use crate::object::define_py_check; use crate::pystate::with_vm; -use core::ffi::{CStr, c_char, c_int}; +use crate::util::CStrExt; +use core::ffi::{c_char, c_int}; use core::ptr::NonNull; use rustpython_vm::AsObject; use rustpython_vm::PyPayload; @@ -49,9 +50,7 @@ pub unsafe extern "C" fn PyDict_SetItemString( ) -> c_int { with_vm(|vm| { let dict = unsafe { &*dict }.try_downcast_ref::(vm)?; - let key = unsafe { CStr::from_ptr(key) } - .to_str() - .map_err(|_| vm.new_value_error("dictionary key must be valid UTF-8"))?; + let key = unsafe { key.try_as_str(vm) }?; let value = unsafe { &*val }.to_owned(); dict.inner_setitem(key, value, vm) }) @@ -94,9 +93,7 @@ pub unsafe extern "C" fn PyDict_GetItemString( ) -> *mut PyObject { with_vm(|vm| { let dict = unsafe { &*dict }.try_downcast_ref::(vm)?; - let key = unsafe { CStr::from_ptr(key) } - .to_str() - .map_err(|_| vm.new_unicode_decode_error("dictionary key must be valid UTF-8"))?; + let key = unsafe { key.try_as_str(vm) }?; match dict.inner_getitem_opt(key, vm)? { Some(value) => Ok(value.as_object().as_raw().cast_mut()), @@ -116,9 +113,7 @@ pub unsafe extern "C" fn PyDict_GetItemStringRef( *result = core::ptr::null_mut(); } let dict = unsafe { &*dict }.try_downcast_ref::(vm)?; - let key = unsafe { CStr::from_ptr(key) } - .to_str() - .map_err(|_| vm.new_value_error("dictionary key must be valid UTF-8"))?; + let key = unsafe { key.try_as_str(vm) }?; if let Some(value) = dict.inner_getitem_opt(key, vm)? { unsafe { @@ -231,9 +226,7 @@ pub unsafe extern "C" fn PyDict_DelItem(dict: *mut PyObject, key: *mut PyObject) pub unsafe extern "C" fn PyDict_DelItemString(dict: *mut PyObject, key: *const c_char) -> c_int { with_vm(|vm| { let dict = unsafe { &*dict }.try_downcast_ref::(vm)?; - let key = unsafe { CStr::from_ptr(key) } - .to_str() - .map_err(|_| vm.new_value_error("dictionary key must be valid UTF-8"))?; + let key = unsafe { key.try_as_str(vm) }?; dict.del_item(key, vm) }) } diff --git a/crates/capi/src/import.rs b/crates/capi/src/import.rs index c6d5ce85ed6..3a8dae651c9 100644 --- a/crates/capi/src/import.rs +++ b/crates/capi/src/import.rs @@ -1,5 +1,6 @@ +use crate::util::CStrExt; use crate::{PyObject, pystate::with_vm}; -use core::ffi::{CStr, c_char}; +use core::ffi::c_char; use rustpython_vm::builtins::{PyCode, PyDict, PyModule, PyStr}; use rustpython_vm::import::import_code_obj; @@ -14,9 +15,7 @@ pub unsafe extern "C" fn PyImport_Import(name: *mut PyObject) -> *mut PyObject { #[unsafe(no_mangle)] pub unsafe extern "C" fn PyImport_AddModuleRef(name: *const c_char) -> *mut PyObject { with_vm(|vm| { - let name = unsafe { CStr::from_ptr(name) } - .to_str() - .map_err(|_| vm.new_system_error("PyImport_AddModuleRef called with non utf8 name"))?; + let name = unsafe { name.try_as_str(vm) }?; let sys_modules = vm .sys_module @@ -46,16 +45,11 @@ pub unsafe extern "C" fn PyImport_ExecCodeModuleEx( pathname: *const c_char, ) -> *mut PyObject { with_vm(|vm| { - let name = unsafe { CStr::from_ptr(name) }.to_str().map_err(|_| { - vm.new_system_error("PyImport_ExecCodeModuleEx called with non utf8 name") - })?; + let name = unsafe { name.try_as_str(vm) }?; let code = unsafe { &*co }.try_downcast_ref::(vm)?; let module = import_code_obj(vm, name, code.to_owned(), false)?; - if !pathname.is_null() { - let pathname = unsafe { CStr::from_ptr(pathname) }.to_str().map_err(|_| { - vm.new_system_error("PyImport_ExecCodeModuleEx called with non utf8 pathname") - })?; + if let Some(pathname) = unsafe { pathname.try_as_str_opt(vm) }? { module.set_attr("__file__", vm.ctx.new_str(pathname), vm)?; } diff --git a/crates/capi/src/methodobject.rs b/crates/capi/src/methodobject.rs index b234ba76a9c..cc3676ef51a 100644 --- a/crates/capi/src/methodobject.rs +++ b/crates/capi/src/methodobject.rs @@ -2,7 +2,8 @@ use crate::PyObject; use crate::object::PyTypeObject; use crate::object::define_py_check; use crate::pystate::with_vm; -use core::ffi::{CStr, c_char, c_int}; +use crate::util::CStrExt; +use core::ffi::{c_char, c_int}; use core::ptr::NonNull; use rustpython_vm::function::{FuncArgs, HeapMethodDef, PosArgs, PyMethodFlags}; use rustpython_vm::{AsObject, PyObjectRef, PyRef, PyResult, VirtualMachine}; @@ -46,17 +47,9 @@ pub(crate) fn build_method_def( ml: &PyMethodDef, has_self: bool, ) -> PyResult> { - let name = unsafe { CStr::from_ptr(ml.ml_name) } - .to_str() - .map_err(|_| vm.new_system_error("Method name was not valid UTF-8"))?; + let name = unsafe { ml.ml_name.try_as_str(vm) }?; - let doc = NonNull::new(ml.ml_doc.cast_mut()) - .map(|doc| { - unsafe { CStr::from_ptr(doc.as_ptr()) } - .to_str() - .map_err(|_| vm.new_system_error("Method doc was not valid UTF-8")) - }) - .transpose()?; + let doc = unsafe { ml.ml_doc.try_as_str_opt(vm) }?; let flags = PyMethodFlags::from_bits(ml.ml_flags as u32) .ok_or_else(|| vm.new_system_error("PyMethodDef contains unknown flags"))?; diff --git a/crates/capi/src/object.rs b/crates/capi/src/object.rs index 27417a6ad33..eabfbef23a1 100644 --- a/crates/capi/src/object.rs +++ b/crates/capi/src/object.rs @@ -1,6 +1,7 @@ use crate::PyObject; use crate::pystate::with_vm; -use core::ffi::{CStr, c_char, c_int, c_uint, c_void}; +use crate::util::CStrExt; +use core::ffi::{c_char, c_int, c_uint, c_void}; use core::ptr::NonNull; pub use pytype::*; use rustpython_vm::builtins::{PyStr, object_generic_set_dict, object_get_dict}; @@ -81,11 +82,7 @@ pub unsafe extern "C" fn PyObject_GetAttrString( ) -> *mut PyObject { with_vm(|vm| { let obj = unsafe { &*obj }; - let name = unsafe { - CStr::from_ptr(attr_name) - .to_str() - .map_err(|_| vm.new_value_error("attribute name must be valid UTF-8"))? - }; + let name = unsafe { attr_name.try_as_str(vm) }?; obj.get_attr(name, vm) }) } @@ -134,9 +131,7 @@ pub unsafe extern "C" fn PyObject_GetOptionalAttrString( *result = core::ptr::null_mut(); } let obj = unsafe { &*obj }; - let name = unsafe { CStr::from_ptr(attr_name) } - .to_str() - .map_err(|_| vm.new_value_error("attribute name must be valid UTF-8"))?; + let name = unsafe { attr_name.try_as_str(vm) }?; if let Some(attr) = vm.get_attribute_opt(obj.to_owned(), name)? { unsafe { *result = attr.into_raw().as_ptr(); @@ -156,9 +151,7 @@ pub unsafe extern "C" fn PyObject_SetAttrString( ) -> c_int { with_vm(|vm| { let obj = unsafe { &*obj }; - let name = unsafe { CStr::from_ptr(attr_name) } - .to_str() - .map_err(|_| vm.new_value_error("attribute name must be valid UTF-8"))?; + let name = unsafe { attr_name.try_as_str(vm) }?; let value = unsafe { &*value }.to_owned(); obj.set_attr(name, value, vm) }) @@ -194,9 +187,7 @@ pub unsafe extern "C" fn PyObject_DelAttrString( ) -> c_int { with_vm(|vm| { let obj = unsafe { &*obj }; - let name = unsafe { CStr::from_ptr(attr_name) } - .to_str() - .map_err(|_| vm.new_value_error("attribute name must be valid UTF-8"))?; + let name = unsafe { attr_name.try_as_str(vm) }?; obj.del_attr(name, vm) }) } @@ -259,7 +250,7 @@ pub unsafe extern "C" fn PyObject_HasAttrString( ) -> c_int { with_vm(|vm| { let obj = unsafe { &*obj }; - let Ok(name) = unsafe { CStr::from_ptr(attr_name) }.to_str() else { + let Ok(name) = (unsafe { attr_name.try_as_str(vm) }) else { return false; }; @@ -280,9 +271,7 @@ pub unsafe extern "C" fn PyObject_HasAttrStringWithError( ) -> c_int { with_vm(|vm| { let obj = unsafe { &*obj }; - let name = unsafe { CStr::from_ptr(attr_name) } - .to_str() - .map_err(|_| vm.new_value_error("attribute name must be valid UTF-8"))?; + let name = unsafe { attr_name.try_as_str(vm) }?; obj.has_attr(name, vm) }) } diff --git a/crates/capi/src/pycapsule.rs b/crates/capi/src/pycapsule.rs index a1b5effd88c..b36dea3d946 100644 --- a/crates/capi/src/pycapsule.rs +++ b/crates/capi/src/pycapsule.rs @@ -1,5 +1,6 @@ use crate::PyObject; use crate::pystate::with_vm; +use crate::util::CStrExt; use core::ffi::{CStr, c_char, c_int, c_void}; use core::ptr::NonNull; use rustpython_vm::builtins::PyCapsule; @@ -93,9 +94,7 @@ pub unsafe extern "C" fn PyCapsule_IsValid(capsule: *mut PyObject, name: *const #[unsafe(no_mangle)] pub unsafe extern "C" fn PyCapsule_Import(name: *const c_char, _no_block: c_int) -> *mut c_void { with_vm(|vm| { - let capsule_name = unsafe { CStr::from_ptr(name) } - .to_str() - .map_err(|_| vm.new_system_error("capsule name is not valid UTF-8"))?; + let capsule_name = unsafe { name.try_as_str(vm) }?; let (module_name, attrs_path) = capsule_name.split_once('.').ok_or_else(|| { vm.new_import_error( "capsule name is missing attribute path", diff --git a/crates/capi/src/pyerrors.rs b/crates/capi/src/pyerrors.rs index d7efd1a0d6f..55428ee7604 100644 --- a/crates/capi/src/pyerrors.rs +++ b/crates/capi/src/pyerrors.rs @@ -1,7 +1,8 @@ use crate::object::define_py_check; +use crate::util::CStrExt; use crate::{PyObject, pystate::with_vm}; use core::convert::Infallible; -use core::ffi::{CStr, c_char, c_int}; +use core::ffi::{c_char, c_int}; use core::ptr::NonNull; use core::slice; use rustpython_vm::builtins::{PyBaseException, PyTuple, PyType}; @@ -144,10 +145,7 @@ pub unsafe extern "C" fn PyErr_SetObject(exception: *mut PyObject, value: *mut P pub unsafe extern "C" fn PyErr_SetString(exception: *mut PyObject, message: *const c_char) { with_vm::, _>(|vm| { let exc_type = unsafe { &*exception }.try_downcast_ref::(vm)?; - - let Ok(message) = unsafe { CStr::from_ptr(message) }.to_str() else { - return Err(vm.new_type_error("Exception message is not valid UTF-8")); - }; + let message = unsafe { message.try_as_str(vm) }?; let exc = vm.invoke_exception( exc_type.to_owned(), @@ -210,13 +208,10 @@ pub unsafe extern "C" fn PyErr_NewException( dict: *mut PyObject, ) -> *mut PyObject { with_vm(|vm| { - let (module, name) = unsafe { - CStr::from_ptr(name) - .to_str() - .expect("Exception name is not valid UTF-8") - .rsplit_once('.') - .expect("Exception name must be of the form 'module.ExceptionName'") - }; + let (module, name) = unsafe { name.try_as_str(vm) } + .expect("Exception name is not valid UTF-8") + .rsplit_once('.') + .expect("Exception name must be of the form 'module.ExceptionName'"); let bases = unsafe { base.as_ref() }.map(|bases| { if let Some(ty) = bases.downcast_ref::() { @@ -332,12 +327,8 @@ pub unsafe extern "C" fn PyUnicodeDecodeError_Create( reason: *const c_char, ) -> *mut PyObject { with_vm(|vm| { - let encoding = unsafe { CStr::from_ptr(encoding) } - .to_str() - .map_err(|_| vm.new_system_error("encoding must be valid UTF-8"))?; - let reason = unsafe { CStr::from_ptr(reason) } - .to_str() - .map_err(|_| vm.new_system_error("reason must be valid UTF-8"))?; + let encoding = unsafe { encoding.try_as_str(vm) }?; + let reason = unsafe { reason.try_as_str(vm) }?; let length: usize = length .try_into() .map_err(|_| vm.new_system_error("length must be non-negative"))?; diff --git a/crates/capi/src/unicodeobject.rs b/crates/capi/src/unicodeobject.rs index 787e31ea571..1a5e43c0e9d 100644 --- a/crates/capi/src/unicodeobject.rs +++ b/crates/capi/src/unicodeobject.rs @@ -1,4 +1,5 @@ use crate::object::define_py_check; +use crate::util::CStrExt; use crate::{PyObject, pystate::with_vm}; use core::ffi::{CStr, c_char, c_int}; use core::ptr::NonNull; @@ -70,21 +71,9 @@ pub unsafe extern "C" fn PyUnicode_AsEncodedString( let unicode = unsafe { &*unicode } .try_downcast_ref::(vm)? .to_owned(); - let encoding = if encoding.is_null() { - "utf-8" - } else { - unsafe { CStr::from_ptr(encoding) } - .to_str() - .expect("encoding must be valid UTF-8") - }; - let errors = if errors.is_null() { - None - } else { - let errors = unsafe { CStr::from_ptr(errors) } - .to_str() - .expect("errors must be valid UTF-8"); - Some(vm.ctx.new_utf8_str(errors)) - }; + let encoding = unsafe { encoding.try_as_str_opt(vm) }?.unwrap_or("utf-8"); + let errors = + unsafe { errors.try_as_str_opt(vm) }?.map(|errors| vm.ctx.new_utf8_str(errors)); vm.state .codec_registry .encode_text(unicode, encoding, errors, vm) @@ -177,21 +166,9 @@ pub unsafe extern "C" fn PyUnicode_FromEncodedObject( return Err(vm.new_type_error("decoding str is not supported")); } - let encoding = if encoding.is_null() { - "utf-8" - } else { - unsafe { CStr::from_ptr(encoding) } - .to_str() - .map_err(|_| vm.new_system_error("encoding must be valid UTF-8"))? - }; - let errors = if errors.is_null() { - None - } else { - let errors = unsafe { CStr::from_ptr(errors) } - .to_str() - .map_err(|_| vm.new_system_error("errors must be valid UTF-8"))?; - Some(vm.ctx.new_utf8_str(errors)) - }; + let encoding = unsafe { encoding.try_as_str_opt(vm) }?.unwrap_or("utf-8"); + let errors = + unsafe { errors.try_as_str_opt(vm) }?.map(|errors| vm.ctx.new_utf8_str(errors)); obj.try_bytes_like(vm, |b| { vm.state.codec_registry.decode_text( diff --git a/crates/capi/src/util.rs b/crates/capi/src/util.rs index 6bbda7654fe..32ff775676b 100644 --- a/crates/capi/src/util.rs +++ b/crates/capi/src/util.rs @@ -1,6 +1,7 @@ use crate::PyObject; use core::convert::Infallible; use core::ffi::{CStr, c_char, c_double, c_int, c_long, c_ulong, c_void}; +use core::ptr::NonNull; use rustpython_vm::{Py, PyObjectRef, PyRef, PyResult, VirtualMachine}; pub(crate) trait FfiResult { @@ -222,6 +223,35 @@ where } } +pub(crate) trait CStrExt<'a> { + unsafe fn try_as_str(self, vm: &VirtualMachine) -> PyResult<&'a str>; + unsafe fn try_as_str_opt(self, vm: &VirtualMachine) -> PyResult>; +} + +impl<'a> CStrExt<'a> for *mut c_char { + unsafe fn try_as_str(self, vm: &VirtualMachine) -> PyResult<&'a str> { + unsafe { self.try_as_str_opt(vm) }? + .ok_or_else(|| vm.new_system_error("argument must not be null")) + } + + unsafe fn try_as_str_opt(self, vm: &VirtualMachine) -> PyResult> { + NonNull::new(self) + .map(|ptr| unsafe { CStr::from_ptr(ptr.as_ptr()) }.to_str()) + .transpose() + .map_err(|_| vm.new_system_error("argument must be valid UTF-8")) + } +} + +impl<'a> CStrExt<'a> for *const c_char { + unsafe fn try_as_str(self, vm: &VirtualMachine) -> PyResult<&'a str> { + unsafe { self.cast_mut().try_as_str(vm) } + } + + unsafe fn try_as_str_opt(self, vm: &VirtualMachine) -> PyResult> { + unsafe { self.cast_mut().try_as_str_opt(vm) } + } +} + #[cfg(test)] mod tests { use super::*; diff --git a/crates/capi/src/warnings.rs b/crates/capi/src/warnings.rs index 4966cd60d6d..f9ed82b9fa9 100644 --- a/crates/capi/src/warnings.rs +++ b/crates/capi/src/warnings.rs @@ -1,5 +1,6 @@ +use crate::util::CStrExt; use crate::{PyObject, pystate::with_vm}; -use core::ffi::{CStr, c_char, c_int}; +use core::ffi::{c_char, c_int}; use rustpython_vm::builtins::{PyType, PyTypeRef}; use rustpython_vm::warn::{warn, warn_explicit}; use rustpython_vm::{AsObject, PyResult}; @@ -32,9 +33,7 @@ pub unsafe extern "C" fn PyErr_WarnEx( stack_level: isize, ) -> c_int { with_vm(|vm| { - let message = unsafe { CStr::from_ptr(message) } - .to_str() - .map_err(|_| vm.new_system_error("warning message is not valid UTF-8"))?; + let message = unsafe { message.try_as_str(vm) }?; let category = resolve_warning_category(vm, category)?; @@ -58,17 +57,11 @@ pub unsafe extern "C" fn PyErr_WarnExplicit( registry: *mut PyObject, ) -> c_int { with_vm(|vm| { - let message = unsafe { CStr::from_ptr(message) } - .to_str() - .map_err(|_| vm.new_system_error("warning message is not valid UTF-8"))?; - let filename = unsafe { CStr::from_ptr(filename) } - .to_str() - .map_err(|_| vm.new_system_error("filename is not valid UTF-8"))?; - - let module = unsafe { module.as_ref().map(|ptr| CStr::from_ptr(ptr).to_str()) } - .transpose() - .map_err(|_| vm.new_system_error("module is not valid UTF-8"))? - .map(|module| vm.ctx.new_str(module).into()); + let message = unsafe { message.try_as_str(vm) }?; + let filename = unsafe { filename.try_as_str(vm) }?; + + let module = + unsafe { module.try_as_str_opt(vm) }?.map(|module| vm.ctx.new_str(module).into()); let category = resolve_warning_category(vm, category)?; diff --git a/crates/vm/src/sequence.rs b/crates/vm/src/sequence.rs index 0bc35181b38..4e6ed97f21c 100644 --- a/crates/vm/src/sequence.rs +++ b/crates/vm/src/sequence.rs @@ -124,7 +124,7 @@ where let n = vm.check_repeat_or_overflow_error(self.as_ref().len(), n)?; if n > 1 && core::mem::size_of_val(self.as_ref()) >= MAX_MEMORY_SIZE / n { - // TODO: make a global static NoMemory shared exc object and return its reference. + // TODO: make a global static NoMemory shared exc object and return its reference. return Err(vm.new_memory_error("")); } From c710ae88af0d661bff6627b5545b5408082ff60a Mon Sep 17 00:00:00 2001 From: Bas Schoenmaeckers Date: Thu, 16 Jul 2026 14:01:14 +0200 Subject: [PATCH 3/4] Add `FfiPtrExt` for uniform pointer dereferences --- crates/capi/src/abstract_.rs | 59 ++++---- crates/capi/src/abstract_/iter.rs | 20 +-- crates/capi/src/abstract_/mapping.rs | 35 ++--- crates/capi/src/abstract_/number.rs | 187 +++++++++++++++++++++----- crates/capi/src/abstract_/sequence.rs | 49 +++---- crates/capi/src/boolobject.rs | 11 +- crates/capi/src/bytearrayobject.rs | 9 +- crates/capi/src/bytesobject.rs | 5 +- crates/capi/src/ceval.rs | 14 +- crates/capi/src/codecs.rs | 15 ++- crates/capi/src/complexobject.rs | 5 +- crates/capi/src/descrobject.rs | 18 +-- crates/capi/src/dictobject.rs | 70 +++++----- crates/capi/src/floatobject.rs | 10 +- crates/capi/src/genericaliasobject.rs | 5 +- crates/capi/src/import.rs | 6 +- crates/capi/src/listobject.rs | 34 ++--- crates/capi/src/longobject.rs | 35 +++-- crates/capi/src/memoryobject.rs | 3 +- crates/capi/src/methodobject.rs | 40 ++---- crates/capi/src/moduleobject.rs | 7 +- crates/capi/src/object.rs | 129 +++++++++--------- crates/capi/src/object/pytype.rs | 33 ++--- crates/capi/src/objimpl.rs | 9 +- crates/capi/src/osmodule.rs | 3 +- crates/capi/src/pycapsule.rs | 14 +- crates/capi/src/pyerrors.rs | 55 ++++---- crates/capi/src/pyframe.rs | 5 +- crates/capi/src/refcount.rs | 11 +- crates/capi/src/setobject.rs | 25 ++-- crates/capi/src/sliceobject.rs | 22 +-- crates/capi/src/traceback.rs | 5 +- crates/capi/src/tupleobject.rs | 7 +- crates/capi/src/unicodeobject.rs | 23 ++-- crates/capi/src/util.rs | 92 ++++++++++++- crates/capi/src/warnings.rs | 8 +- crates/capi/src/weakrefobject.rs | 11 +- crates/vm/src/object/core.rs | 7 +- 38 files changed, 640 insertions(+), 456 deletions(-) diff --git a/crates/capi/src/abstract_.rs b/crates/capi/src/abstract_.rs index 08b4e540029..2bee46fdae4 100644 --- a/crates/capi/src/abstract_.rs +++ b/crates/capi/src/abstract_.rs @@ -1,4 +1,5 @@ use crate::util::CStrExt; +use crate::util::FfiPtrExt; use crate::{PyObject, pystate::with_vm}; use alloc::slice; use core::ffi::{c_char, c_int}; @@ -42,10 +43,10 @@ pub unsafe extern "C" fn PyObject_Call( kwargs: *mut PyObject, ) -> *mut PyObject { with_vm(|vm| { - let callable = unsafe { &*callable }; - let args = tuple_to_args(unsafe { &*args }.try_downcast_ref::(vm)?); + let callable = unsafe { callable.assume_borrowed() }; + let args = tuple_to_args(unsafe { args.assume_borrowed_and_cast::(vm) }?); - let kwargs: Option = unsafe { kwargs.as_ref() } + let kwargs: Option = unsafe { kwargs.assume_borrowed_or_opt() } .map(|kwargs| dict_to_kwargs(vm, kwargs.try_downcast_ref::(vm)?)) .transpose()?; @@ -55,7 +56,7 @@ pub unsafe extern "C" fn PyObject_Call( #[unsafe(no_mangle)] pub unsafe extern "C" fn PyObject_CallNoArgs(callable: *mut PyObject) -> *mut PyObject { - with_vm(|vm| unsafe { &*callable }.call((), vm)) + with_vm(|vm| unsafe { callable.assume_borrowed() }.call((), vm)) } #[unsafe(no_mangle)] @@ -64,8 +65,8 @@ pub unsafe extern "C" fn PyObject_CallObject( args: *mut PyObject, ) -> *mut PyObject { with_vm(|vm| { - let callable = unsafe { &*callable }; - if let Some(args) = unsafe { args.as_ref() } { + let callable = unsafe { callable.assume_borrowed() }; + if let Some(args) = unsafe { args.assume_borrowed_or_opt() } { callable.call(tuple_to_args(args.try_downcast_ref::(vm)?), vm) } else { callable.call((), vm) @@ -85,7 +86,7 @@ pub unsafe extern "C" fn PyObject_Vectorcall( let kwnames: Option<&[PyObjectRef]> = unsafe { kwnames - .as_ref() + .assume_borrowed_or_opt() .map(|tuple| Ok(&***tuple.try_downcast_ref::(vm)?)) .transpose()? }; @@ -100,7 +101,7 @@ pub unsafe extern "C" fn PyObject_Vectorcall( .collect::>() }; - let callable = unsafe { &*callable }; + let callable = unsafe { callable.assume_borrowed() }; callable.vectorcall(args, num_positional_args, kwnames, vm) }) } @@ -123,8 +124,8 @@ pub unsafe extern "C" fn PyObject_VectorcallMethod( .split_first() .expect("args_len > 0 should guarantee a receiver"); - let method_name = unsafe { (&*name).try_downcast_ref::(vm)? }; - let callable = unsafe { (&**receiver).get_attr(method_name, vm)? }; + let method_name = unsafe { name.assume_borrowed_and_cast::(vm)? }; + let callable = unsafe { receiver.assume_borrowed().get_attr(method_name, vm)? }; Ok(unsafe { PyObject_Vectorcall( @@ -144,14 +145,14 @@ pub unsafe extern "C" fn PyVectorcall_Call( kwargs: *mut PyObject, ) -> *mut PyObject { with_vm(|vm| { - let callable = unsafe { &*callable }; - let tuple = unsafe { &*tuple }.try_downcast_ref::(vm)?; + let callable = unsafe { callable.assume_borrowed() }; + let tuple = unsafe { tuple.assume_borrowed_and_cast::(vm) }?; let mut args = tuple.iter().cloned().collect::>(); let num_positional_args = args.len(); let mut kwnames = Vec::new(); - if let Some(kwargs) = unsafe { kwargs.as_ref() } { + if let Some(kwargs) = unsafe { kwargs.assume_borrowed_or_opt() } { let kwargs = kwargs.try_downcast_ref::(vm)?; for (key, value) in kwargs.items_vec() { let key = key @@ -176,8 +177,8 @@ pub unsafe extern "C" fn PyVectorcall_Call( #[unsafe(no_mangle)] pub unsafe extern "C" fn PyObject_GetItem(obj: *mut PyObject, key: *mut PyObject) -> *mut PyObject { with_vm(|vm| { - let obj = unsafe { &*obj }; - let key = unsafe { &*key }; + let obj = unsafe { obj.assume_borrowed() }; + let key = unsafe { key.assume_borrowed() }; obj.get_item(key, vm) }) } @@ -189,9 +190,9 @@ pub unsafe extern "C" fn PyObject_SetItem( value: *mut PyObject, ) -> c_int { with_vm(|vm| { - let obj = unsafe { &*obj }; - let key = unsafe { &*key }; - let value = unsafe { &*value }.to_owned(); + let obj = unsafe { obj.assume_borrowed() }; + let key = unsafe { key.assume_borrowed() }; + let value = unsafe { value.assume_borrowed() }.to_owned(); obj.set_item(key, value, vm) }) } @@ -199,8 +200,8 @@ pub unsafe extern "C" fn PyObject_SetItem( #[unsafe(no_mangle)] pub unsafe extern "C" fn PyObject_DelItem(obj: *mut PyObject, key: *mut PyObject) -> c_int { with_vm(|vm| { - let obj = unsafe { &*obj }; - let key = unsafe { &*key }; + let obj = unsafe { obj.assume_borrowed() }; + let key = unsafe { key.assume_borrowed() }; obj.del_item(key, vm) }) } @@ -208,7 +209,7 @@ pub unsafe extern "C" fn PyObject_DelItem(obj: *mut PyObject, key: *mut PyObject #[unsafe(no_mangle)] pub unsafe extern "C" fn PyObject_DelItemString(obj: *mut PyObject, key: *const c_char) -> c_int { with_vm(|vm| { - let obj = unsafe { &*obj }; + let obj = unsafe { obj.assume_borrowed() }; let key = unsafe { key.try_as_str(vm) }?; obj.del_item(key, vm) }) @@ -220,8 +221,8 @@ pub unsafe extern "C" fn PyObject_Format( format_spec: *mut PyObject, ) -> *mut PyObject { with_vm(|vm| { - let obj = unsafe { &*obj }; - let spec = unsafe { format_spec.as_ref() } + let obj = unsafe { obj.assume_borrowed() }; + let spec = unsafe { format_spec.assume_borrowed_or_opt() } .map(|spec| spec.try_downcast_ref::(vm)) .transpose()? .unwrap_or_else(|| vm.ctx.empty_str); @@ -232,8 +233,8 @@ pub unsafe extern "C" fn PyObject_Format( #[unsafe(no_mangle)] pub unsafe extern "C" fn PyObject_IsSubclass(derived: *mut PyObject, cls: *mut PyObject) -> c_int { with_vm(|vm| { - let derived = unsafe { &*derived }; - let cls = unsafe { &*cls }; + let derived = unsafe { derived.assume_borrowed() }; + let cls = unsafe { cls.assume_borrowed() }; derived.is_subclass(cls, vm) }) } @@ -241,8 +242,8 @@ pub unsafe extern "C" fn PyObject_IsSubclass(derived: *mut PyObject, cls: *mut P #[unsafe(no_mangle)] pub unsafe extern "C" fn PyObject_IsInstance(inst: *mut PyObject, cls: *mut PyObject) -> c_int { with_vm(|vm| { - let inst = unsafe { &*inst }; - let cls = unsafe { &*cls }; + let inst = unsafe { inst.assume_borrowed() }; + let cls = unsafe { cls.assume_borrowed() }; inst.is_instance(cls, vm) }) } @@ -250,7 +251,7 @@ pub unsafe extern "C" fn PyObject_IsInstance(inst: *mut PyObject, cls: *mut PyOb #[unsafe(no_mangle)] pub unsafe extern "C" fn PyObject_Size(obj: *mut PyObject) -> isize { with_vm(|vm| { - let obj = unsafe { &*obj }; + let obj = unsafe { obj.assume_borrowed() }; obj.length(vm) }) } @@ -262,7 +263,7 @@ pub unsafe extern "C" fn PyObject_Length(obj: *mut PyObject) -> isize { #[unsafe(no_mangle)] pub unsafe extern "C" fn PyObject_Type(obj: *mut PyObject) -> *mut PyObject { - with_vm(|_vm| unsafe { &*obj }.obj_type()) + with_vm(|_vm| unsafe { obj.assume_borrowed() }.obj_type()) } #[cfg(test)] diff --git a/crates/capi/src/abstract_/iter.rs b/crates/capi/src/abstract_/iter.rs index a0827f62537..75834b22657 100644 --- a/crates/capi/src/abstract_/iter.rs +++ b/crates/capi/src/abstract_/iter.rs @@ -1,3 +1,4 @@ +use crate::util::FfiPtrExt; use crate::{PyObject, pystate::with_vm}; use core::ffi::c_int; use rustpython_vm::PyObjectRef; @@ -6,13 +7,13 @@ use rustpython_vm::protocol::{PyIter, PyIterReturn}; #[unsafe(no_mangle)] pub unsafe extern "C" fn PyIter_Check(obj: *mut PyObject) -> c_int { - with_vm(|_vm| Ok(PyIter::check(unsafe { &*obj }))) + with_vm(|_vm| Ok(PyIter::check(unsafe { obj.assume_borrowed() }))) } #[unsafe(no_mangle)] pub unsafe extern "C" fn PyAIter_Check(obj: *mut PyObject) -> c_int { with_vm(|vm| { - Ok(unsafe { &*obj } + Ok(unsafe { obj.assume_borrowed() } .class() .has_attr(rustpython_vm::identifier!(vm, __anext__))) }) @@ -21,14 +22,14 @@ pub unsafe extern "C" fn PyAIter_Check(obj: *mut PyObject) -> c_int { #[unsafe(no_mangle)] pub unsafe extern "C" fn PyObject_GetIter(obj: *mut PyObject) -> *mut PyObject { with_vm(|vm| { - let obj = unsafe { &*obj }; + let obj = unsafe { obj.assume_borrowed() }; obj.get_iter(vm).map(PyObjectRef::from) }) } #[unsafe(no_mangle)] pub unsafe extern "C" fn PyObject_GetAIter(obj: *mut PyObject) -> *mut PyObject { - with_vm(|vm| unsafe { &*obj }.get_aiter(vm)) + with_vm(|vm| unsafe { obj.assume_borrowed() }.get_aiter(vm)) } #[unsafe(no_mangle)] @@ -38,7 +39,7 @@ pub unsafe extern "C" fn PyIter_NextItem(iter: *mut PyObject, item: *mut *mut Py *item = core::ptr::null_mut(); } - let iter = PyIter::new(unsafe { &*iter }); + let iter = PyIter::new(unsafe { iter.assume_borrowed() }); match iter.next(vm)? { PyIterReturn::Return(next_item) => { unsafe { @@ -54,7 +55,7 @@ pub unsafe extern "C" fn PyIter_NextItem(iter: *mut PyObject, item: *mut *mut Py #[unsafe(no_mangle)] pub unsafe extern "C" fn PyIter_Next(iter: *mut PyObject) -> *mut PyObject { with_vm(|vm| { - let iter = PyIter::new(unsafe { &*iter }); + let iter = PyIter::new(unsafe { iter.assume_borrowed() }); match iter.next(vm)? { PyIterReturn::Return(next_item) => Ok(next_item.into_raw().as_ptr()), PyIterReturn::StopIteration(_) => Ok(core::ptr::null_mut()), @@ -73,14 +74,13 @@ pub unsafe extern "C" fn PyIter_Send( *presult = core::ptr::null_mut(); } - let iter_obj = unsafe { &*iter }; - let arg_obj = unsafe { &*arg }; + let iter_obj = unsafe { iter.assume_borrowed() }; + let arg_obj = unsafe { arg.assume_borrowed() }; let ret = if vm.is_none(arg_obj) { PyIter::new(iter_obj).next(vm)? } else { - iter_obj - .try_downcast_ref::(vm)? + unsafe { iter.assume_borrowed_and_cast::(vm) }? .as_coro() .send(iter_obj, arg_obj.to_owned(), vm)? }; diff --git a/crates/capi/src/abstract_/mapping.rs b/crates/capi/src/abstract_/mapping.rs index 840a9aed69c..e19f2d5f8b3 100644 --- a/crates/capi/src/abstract_/mapping.rs +++ b/crates/capi/src/abstract_/mapping.rs @@ -1,4 +1,5 @@ use crate::util::CStrExt; +use crate::util::FfiPtrExt; use crate::{PyObject, pystate::with_vm}; use core::ffi::{c_char, c_int}; use rustpython_vm::AsObject; @@ -6,7 +7,7 @@ use rustpython_vm::AsObject; #[unsafe(no_mangle)] pub unsafe extern "C" fn PyMapping_Check(obj: *mut PyObject) -> c_int { with_vm(|_vm| { - let obj = unsafe { &*obj }; + let obj = unsafe { obj.assume_borrowed() }; Ok(obj.mapping_unchecked().check()) }) } @@ -14,7 +15,7 @@ pub unsafe extern "C" fn PyMapping_Check(obj: *mut PyObject) -> c_int { #[unsafe(no_mangle)] pub unsafe extern "C" fn PyMapping_Size(obj: *mut PyObject) -> isize { with_vm(|vm| { - let obj = unsafe { &*obj }; + let obj = unsafe { obj.assume_borrowed() }; obj.try_mapping(vm)?.length(vm) }) } @@ -27,7 +28,7 @@ pub unsafe extern "C" fn PyMapping_Length(obj: *mut PyObject) -> isize { #[unsafe(no_mangle)] pub unsafe extern "C" fn PyMapping_Keys(obj: *mut PyObject) -> *mut PyObject { with_vm(|vm| { - let obj = unsafe { &*obj }; + let obj = unsafe { obj.assume_borrowed() }; let keys = obj.try_mapping(vm)?.keys(vm)?; let iter = keys.get_iter(vm)?; Ok(vm.ctx.new_list(iter.try_to_value(vm)?)) @@ -37,7 +38,7 @@ pub unsafe extern "C" fn PyMapping_Keys(obj: *mut PyObject) -> *mut PyObject { #[unsafe(no_mangle)] pub unsafe extern "C" fn PyMapping_Values(obj: *mut PyObject) -> *mut PyObject { with_vm(|vm| { - let obj = unsafe { &*obj }; + let obj = unsafe { obj.assume_borrowed() }; let values = obj.try_mapping(vm)?.values(vm)?; let iter = values.get_iter(vm)?; Ok(vm.ctx.new_list(iter.try_to_value(vm)?)) @@ -47,7 +48,7 @@ pub unsafe extern "C" fn PyMapping_Values(obj: *mut PyObject) -> *mut PyObject { #[unsafe(no_mangle)] pub unsafe extern "C" fn PyMapping_Items(obj: *mut PyObject) -> *mut PyObject { with_vm(|vm| { - let obj = unsafe { &*obj }; + let obj = unsafe { obj.assume_borrowed() }; let items = obj.try_mapping(vm)?.items(vm)?; let iter = items.get_iter(vm)?; Ok(vm.ctx.new_list(iter.try_to_value(vm)?)) @@ -60,7 +61,7 @@ pub unsafe extern "C" fn PyMapping_GetItemString( key: *const c_char, ) -> *mut PyObject { with_vm(|vm| { - let obj = unsafe { &*obj }; + let obj = unsafe { obj.assume_borrowed() }; let key = unsafe { key.try_as_str(vm) }?; obj.get_item(key, vm) }) @@ -76,8 +77,8 @@ pub unsafe extern "C" fn PyMapping_GetOptionalItem( unsafe { *result = core::ptr::null_mut(); } - let obj = unsafe { &*obj }; - let key = unsafe { &*key }; + let obj = unsafe { obj.assume_borrowed() }; + let key = unsafe { key.assume_borrowed() }; match obj.get_item(key, vm) { Ok(value) => { @@ -102,7 +103,7 @@ pub unsafe extern "C" fn PyMapping_GetOptionalItemString( unsafe { *result = core::ptr::null_mut(); } - let obj = unsafe { &*obj }; + let obj = unsafe { obj.assume_borrowed() }; let key = unsafe { key.try_as_str(vm) }?; match obj.get_item(key, vm) { @@ -121,8 +122,8 @@ pub unsafe extern "C" fn PyMapping_GetOptionalItemString( #[unsafe(no_mangle)] pub unsafe extern "C" fn PyMapping_HasKey(obj: *mut PyObject, key: *mut PyObject) -> c_int { with_vm(|vm| { - let obj = unsafe { &*obj }; - let key = unsafe { &*key }; + let obj = unsafe { obj.assume_borrowed() }; + let key = unsafe { key.assume_borrowed() }; obj.get_item(key, vm).is_ok() }) } @@ -130,7 +131,7 @@ pub unsafe extern "C" fn PyMapping_HasKey(obj: *mut PyObject, key: *mut PyObject #[unsafe(no_mangle)] pub unsafe extern "C" fn PyMapping_HasKeyString(obj: *mut PyObject, key: *const c_char) -> c_int { with_vm(|vm| { - let obj = unsafe { &*obj }; + let obj = unsafe { obj.assume_borrowed() }; if let Ok(key) = unsafe { key.try_as_str(vm) } { obj.get_item(key, vm).is_ok() } else { @@ -145,8 +146,8 @@ pub unsafe extern "C" fn PyMapping_HasKeyWithError( key: *mut PyObject, ) -> c_int { with_vm(|vm| { - let obj = unsafe { &*obj }; - let key = unsafe { &*key }; + let obj = unsafe { obj.assume_borrowed() }; + let key = unsafe { key.assume_borrowed() }; match obj.get_item(key, vm) { Ok(_) => Ok(true), @@ -162,7 +163,7 @@ pub unsafe extern "C" fn PyMapping_HasKeyStringWithError( key: *const c_char, ) -> c_int { with_vm(|vm| { - let obj = unsafe { &*obj }; + let obj = unsafe { obj.assume_borrowed() }; let key = unsafe { key.try_as_str(vm) }?; match obj.get_item(key, vm) { @@ -180,9 +181,9 @@ pub unsafe extern "C" fn PyMapping_SetItemString( value: *mut PyObject, ) -> c_int { with_vm(|vm| { - let obj = unsafe { &*obj }; + let obj = unsafe { obj.assume_borrowed() }; let key = unsafe { key.try_as_str(vm) }?; - let value = unsafe { &*value }.to_owned(); + let value = unsafe { value.assume_borrowed() }.to_owned(); obj.set_item(key, value, vm) }) } diff --git a/crates/capi/src/abstract_/number.rs b/crates/capi/src/abstract_/number.rs index ffc78ea4e24..1af88a79cb9 100644 --- a/crates/capi/src/abstract_/number.rs +++ b/crates/capi/src/abstract_/number.rs @@ -1,40 +1,55 @@ +use crate::util::FfiPtrExt; use crate::{PyObject, pystate::with_vm}; use core::ffi::c_int; use rustpython_vm::protocol::PyNumber; #[unsafe(no_mangle)] pub unsafe extern "C" fn PyNumber_Add(o1: *mut PyObject, o2: *mut PyObject) -> *mut PyObject { - with_vm(|vm| vm._add(unsafe { &*o1 }, unsafe { &*o2 })) + with_vm(|vm| { + vm._add(unsafe { o1.assume_borrowed() }, unsafe { + o2.assume_borrowed() + }) + }) } #[unsafe(no_mangle)] pub unsafe extern "C" fn PyIndex_Check(obj: *mut PyObject) -> c_int { - with_vm(|_vm| unsafe { obj.as_ref() }.is_some_and(|obj| obj.number().is_index())) + with_vm(|_vm| { + unsafe { obj.assume_borrowed_or_opt() }.is_some_and(|obj| obj.number().is_index()) + }) } #[unsafe(no_mangle)] pub unsafe extern "C" fn PyNumber_Absolute(o: *mut PyObject) -> *mut PyObject { - with_vm(|vm| vm._abs(unsafe { &*o })) + with_vm(|vm| vm._abs(unsafe { o.assume_borrowed() })) } #[unsafe(no_mangle)] pub unsafe extern "C" fn PyNumber_And(o1: *mut PyObject, o2: *mut PyObject) -> *mut PyObject { - with_vm(|vm| vm._and(unsafe { &*o1 }, unsafe { &*o2 })) + with_vm(|vm| { + vm._and(unsafe { o1.assume_borrowed() }, unsafe { + o2.assume_borrowed() + }) + }) } #[unsafe(no_mangle)] pub unsafe extern "C" fn PyNumber_Check(o: *mut PyObject) -> c_int { - with_vm(|_vm| unsafe { o.as_ref() }.is_some_and(PyNumber::check)) + with_vm(|_vm| unsafe { o.assume_borrowed_or_opt() }.is_some_and(PyNumber::check)) } #[unsafe(no_mangle)] pub unsafe extern "C" fn PyNumber_Divmod(o1: *mut PyObject, o2: *mut PyObject) -> *mut PyObject { - with_vm(|vm| vm._divmod(unsafe { &*o1 }, unsafe { &*o2 })) + with_vm(|vm| { + vm._divmod(unsafe { o1.assume_borrowed() }, unsafe { + o2.assume_borrowed() + }) + }) } #[unsafe(no_mangle)] pub unsafe extern "C" fn PyNumber_Float(o: *mut PyObject) -> *mut PyObject { - with_vm(|vm| unsafe { &*o }.try_float(vm)) + with_vm(|vm| unsafe { o.assume_borrowed() }.try_float(vm)) } #[unsafe(no_mangle)] @@ -42,7 +57,11 @@ pub unsafe extern "C" fn PyNumber_FloorDivide( o1: *mut PyObject, o2: *mut PyObject, ) -> *mut PyObject { - with_vm(|vm| vm._floordiv(unsafe { &*o1 }, unsafe { &*o2 })) + with_vm(|vm| { + vm._floordiv(unsafe { o1.assume_borrowed() }, unsafe { + o2.assume_borrowed() + }) + }) } #[unsafe(no_mangle)] @@ -50,7 +69,11 @@ pub unsafe extern "C" fn PyNumber_InPlaceAdd( o1: *mut PyObject, o2: *mut PyObject, ) -> *mut PyObject { - with_vm(|vm| vm._iadd(unsafe { &*o1 }, unsafe { &*o2 })) + with_vm(|vm| { + vm._iadd(unsafe { o1.assume_borrowed() }, unsafe { + o2.assume_borrowed() + }) + }) } #[unsafe(no_mangle)] @@ -58,7 +81,11 @@ pub unsafe extern "C" fn PyNumber_InPlaceAnd( o1: *mut PyObject, o2: *mut PyObject, ) -> *mut PyObject { - with_vm(|vm| vm._iand(unsafe { &*o1 }, unsafe { &*o2 })) + with_vm(|vm| { + vm._iand(unsafe { o1.assume_borrowed() }, unsafe { + o2.assume_borrowed() + }) + }) } #[unsafe(no_mangle)] @@ -66,7 +93,11 @@ pub unsafe extern "C" fn PyNumber_InPlaceFloorDivide( o1: *mut PyObject, o2: *mut PyObject, ) -> *mut PyObject { - with_vm(|vm| vm._ifloordiv(unsafe { &*o1 }, unsafe { &*o2 })) + with_vm(|vm| { + vm._ifloordiv(unsafe { o1.assume_borrowed() }, unsafe { + o2.assume_borrowed() + }) + }) } #[unsafe(no_mangle)] @@ -74,7 +105,11 @@ pub unsafe extern "C" fn PyNumber_InPlaceLshift( o1: *mut PyObject, o2: *mut PyObject, ) -> *mut PyObject { - with_vm(|vm| vm._ilshift(unsafe { &*o1 }, unsafe { &*o2 })) + with_vm(|vm| { + vm._ilshift(unsafe { o1.assume_borrowed() }, unsafe { + o2.assume_borrowed() + }) + }) } #[unsafe(no_mangle)] @@ -82,7 +117,11 @@ pub unsafe extern "C" fn PyNumber_InPlaceMatrixMultiply( o1: *mut PyObject, o2: *mut PyObject, ) -> *mut PyObject { - with_vm(|vm| vm._imatmul(unsafe { &*o1 }, unsafe { &*o2 })) + with_vm(|vm| { + vm._imatmul(unsafe { o1.assume_borrowed() }, unsafe { + o2.assume_borrowed() + }) + }) } #[unsafe(no_mangle)] @@ -90,12 +129,20 @@ pub unsafe extern "C" fn PyNumber_InPlaceMultiply( o1: *mut PyObject, o2: *mut PyObject, ) -> *mut PyObject { - with_vm(|vm| vm._imul(unsafe { &*o1 }, unsafe { &*o2 })) + with_vm(|vm| { + vm._imul(unsafe { o1.assume_borrowed() }, unsafe { + o2.assume_borrowed() + }) + }) } #[unsafe(no_mangle)] pub unsafe extern "C" fn PyNumber_InPlaceOr(o1: *mut PyObject, o2: *mut PyObject) -> *mut PyObject { - with_vm(|vm| vm._ior(unsafe { &*o1 }, unsafe { &*o2 })) + with_vm(|vm| { + vm._ior(unsafe { o1.assume_borrowed() }, unsafe { + o2.assume_borrowed() + }) + }) } #[unsafe(no_mangle)] @@ -104,7 +151,13 @@ pub unsafe extern "C" fn PyNumber_InPlacePower( o2: *mut PyObject, o3: *mut PyObject, ) -> *mut PyObject { - with_vm(|vm| vm._ipow(unsafe { &*o1 }, unsafe { &*o2 }, unsafe { &*o3 })) + with_vm(|vm| { + vm._ipow( + unsafe { o1.assume_borrowed() }, + unsafe { o2.assume_borrowed() }, + unsafe { o3.assume_borrowed() }, + ) + }) } #[unsafe(no_mangle)] @@ -112,7 +165,11 @@ pub unsafe extern "C" fn PyNumber_InPlaceRemainder( o1: *mut PyObject, o2: *mut PyObject, ) -> *mut PyObject { - with_vm(|vm| vm._imod(unsafe { &*o1 }, unsafe { &*o2 })) + with_vm(|vm| { + vm._imod(unsafe { o1.assume_borrowed() }, unsafe { + o2.assume_borrowed() + }) + }) } #[unsafe(no_mangle)] @@ -120,7 +177,11 @@ pub unsafe extern "C" fn PyNumber_InPlaceRshift( o1: *mut PyObject, o2: *mut PyObject, ) -> *mut PyObject { - with_vm(|vm| vm._irshift(unsafe { &*o1 }, unsafe { &*o2 })) + with_vm(|vm| { + vm._irshift(unsafe { o1.assume_borrowed() }, unsafe { + o2.assume_borrowed() + }) + }) } #[unsafe(no_mangle)] @@ -128,7 +189,11 @@ pub unsafe extern "C" fn PyNumber_InPlaceSubtract( o1: *mut PyObject, o2: *mut PyObject, ) -> *mut PyObject { - with_vm(|vm| vm._isub(unsafe { &*o1 }, unsafe { &*o2 })) + with_vm(|vm| { + vm._isub(unsafe { o1.assume_borrowed() }, unsafe { + o2.assume_borrowed() + }) + }) } #[unsafe(no_mangle)] @@ -136,7 +201,11 @@ pub unsafe extern "C" fn PyNumber_InPlaceTrueDivide( o1: *mut PyObject, o2: *mut PyObject, ) -> *mut PyObject { - with_vm(|vm| vm._itruediv(unsafe { &*o1 }, unsafe { &*o2 })) + with_vm(|vm| { + vm._itruediv(unsafe { o1.assume_borrowed() }, unsafe { + o2.assume_borrowed() + }) + }) } #[unsafe(no_mangle)] @@ -144,17 +213,21 @@ pub unsafe extern "C" fn PyNumber_InPlaceXor( o1: *mut PyObject, o2: *mut PyObject, ) -> *mut PyObject { - with_vm(|vm| vm._ixor(unsafe { &*o1 }, unsafe { &*o2 })) + with_vm(|vm| { + vm._ixor(unsafe { o1.assume_borrowed() }, unsafe { + o2.assume_borrowed() + }) + }) } #[unsafe(no_mangle)] pub unsafe extern "C" fn PyNumber_Invert(o: *mut PyObject) -> *mut PyObject { - with_vm(|vm| vm._invert(unsafe { &*o })) + with_vm(|vm| vm._invert(unsafe { o.assume_borrowed() })) } #[unsafe(no_mangle)] pub unsafe extern "C" fn PyNumber_Index(obj: *mut PyObject) -> *mut PyObject { - with_vm(|vm| unsafe { &*obj }.try_index(vm)) + with_vm(|vm| unsafe { obj.assume_borrowed() }.try_index(vm)) } #[unsafe(no_mangle)] @@ -162,22 +235,30 @@ pub unsafe extern "C" fn PyNumber_MatrixMultiply( o1: *mut PyObject, o2: *mut PyObject, ) -> *mut PyObject { - with_vm(|vm| vm._matmul(unsafe { &*o1 }, unsafe { &*o2 })) + with_vm(|vm| { + vm._matmul(unsafe { o1.assume_borrowed() }, unsafe { + o2.assume_borrowed() + }) + }) } #[unsafe(no_mangle)] pub unsafe extern "C" fn PyNumber_Multiply(o1: *mut PyObject, o2: *mut PyObject) -> *mut PyObject { - with_vm(|vm| vm._mul(unsafe { &*o1 }, unsafe { &*o2 })) + with_vm(|vm| { + vm._mul(unsafe { o1.assume_borrowed() }, unsafe { + o2.assume_borrowed() + }) + }) } #[unsafe(no_mangle)] pub unsafe extern "C" fn PyNumber_Negative(o: *mut PyObject) -> *mut PyObject { - with_vm(|vm| vm._neg(unsafe { &*o })) + with_vm(|vm| vm._neg(unsafe { o.assume_borrowed() })) } #[unsafe(no_mangle)] pub unsafe extern "C" fn PyNumber_Positive(o: *mut PyObject) -> *mut PyObject { - with_vm(|vm| vm._pos(unsafe { &*o })) + with_vm(|vm| vm._pos(unsafe { o.assume_borrowed() })) } #[unsafe(no_mangle)] @@ -186,12 +267,22 @@ pub unsafe extern "C" fn PyNumber_Power( o2: *mut PyObject, o3: *mut PyObject, ) -> *mut PyObject { - with_vm(|vm| vm._pow(unsafe { &*o1 }, unsafe { &*o2 }, unsafe { &*o3 })) + with_vm(|vm| { + vm._pow( + unsafe { o1.assume_borrowed() }, + unsafe { o2.assume_borrowed() }, + unsafe { o3.assume_borrowed() }, + ) + }) } #[unsafe(no_mangle)] pub unsafe extern "C" fn PyNumber_Remainder(o1: *mut PyObject, o2: *mut PyObject) -> *mut PyObject { - with_vm(|vm| vm._mod(unsafe { &*o1 }, unsafe { &*o2 })) + with_vm(|vm| { + vm._mod(unsafe { o1.assume_borrowed() }, unsafe { + o2.assume_borrowed() + }) + }) } #[unsafe(no_mangle)] @@ -199,37 +290,61 @@ pub unsafe extern "C" fn PyNumber_TrueDivide( o1: *mut PyObject, o2: *mut PyObject, ) -> *mut PyObject { - with_vm(|vm| vm._truediv(unsafe { &*o1 }, unsafe { &*o2 })) + with_vm(|vm| { + vm._truediv(unsafe { o1.assume_borrowed() }, unsafe { + o2.assume_borrowed() + }) + }) } #[unsafe(no_mangle)] pub unsafe extern "C" fn PyNumber_Xor(o1: *mut PyObject, o2: *mut PyObject) -> *mut PyObject { - with_vm(|vm| vm._xor(unsafe { &*o1 }, unsafe { &*o2 })) + with_vm(|vm| { + vm._xor(unsafe { o1.assume_borrowed() }, unsafe { + o2.assume_borrowed() + }) + }) } #[unsafe(no_mangle)] pub unsafe extern "C" fn PyNumber_Long(obj: *mut PyObject) -> *mut PyObject { - with_vm(|vm| unsafe { &*obj }.try_int(vm)) + with_vm(|vm| unsafe { obj.assume_borrowed() }.try_int(vm)) } #[unsafe(no_mangle)] pub unsafe extern "C" fn PyNumber_Lshift(o1: *mut PyObject, o2: *mut PyObject) -> *mut PyObject { - with_vm(|vm| vm._lshift(unsafe { &*o1 }, unsafe { &*o2 })) + with_vm(|vm| { + vm._lshift(unsafe { o1.assume_borrowed() }, unsafe { + o2.assume_borrowed() + }) + }) } #[unsafe(no_mangle)] pub unsafe extern "C" fn PyNumber_Or(o1: *mut PyObject, o2: *mut PyObject) -> *mut PyObject { - with_vm(|vm| vm._or(unsafe { &*o1 }, unsafe { &*o2 })) + with_vm(|vm| { + vm._or(unsafe { o1.assume_borrowed() }, unsafe { + o2.assume_borrowed() + }) + }) } #[unsafe(no_mangle)] pub unsafe extern "C" fn PyNumber_Rshift(o1: *mut PyObject, o2: *mut PyObject) -> *mut PyObject { - with_vm(|vm| vm._rshift(unsafe { &*o1 }, unsafe { &*o2 })) + with_vm(|vm| { + vm._rshift(unsafe { o1.assume_borrowed() }, unsafe { + o2.assume_borrowed() + }) + }) } #[unsafe(no_mangle)] pub unsafe extern "C" fn PyNumber_Subtract(o1: *mut PyObject, o2: *mut PyObject) -> *mut PyObject { - with_vm(|vm| vm._sub(unsafe { &*o1 }, unsafe { &*o2 })) + with_vm(|vm| { + vm._sub(unsafe { o1.assume_borrowed() }, unsafe { + o2.assume_borrowed() + }) + }) } #[cfg(test)] diff --git a/crates/capi/src/abstract_/sequence.rs b/crates/capi/src/abstract_/sequence.rs index d011dfdb8eb..6fa8baadc3b 100644 --- a/crates/capi/src/abstract_/sequence.rs +++ b/crates/capi/src/abstract_/sequence.rs @@ -1,10 +1,11 @@ +use crate::util::FfiPtrExt; use crate::{PyObject, pystate::with_vm}; use core::ffi::c_int; #[unsafe(no_mangle)] pub unsafe extern "C" fn PySequence_Check(obj: *mut PyObject) -> c_int { with_vm(|_vm| { - let obj = unsafe { &*obj }; + let obj = unsafe { obj.assume_borrowed() }; Ok(obj.sequence_unchecked().check()) }) } @@ -15,8 +16,8 @@ pub unsafe extern "C" fn PySequence_Concat( obj2: *mut PyObject, ) -> *mut PyObject { with_vm(|vm| { - let obj1 = unsafe { &*obj1 }; - let obj2 = unsafe { &*obj2 }; + let obj1 = unsafe { obj1.assume_borrowed() }; + let obj2 = unsafe { obj2.assume_borrowed() }; obj1.try_sequence(vm)?.concat(obj2, vm) }) } @@ -24,8 +25,8 @@ pub unsafe extern "C" fn PySequence_Concat( #[unsafe(no_mangle)] pub unsafe extern "C" fn PySequence_Count(obj: *mut PyObject, value: *mut PyObject) -> isize { with_vm(|vm| { - let obj = unsafe { &*obj }; - let value = unsafe { &*value }; + let obj = unsafe { obj.assume_borrowed() }; + let value = unsafe { value.assume_borrowed() }; obj.try_sequence(vm)?.count(value, vm) }) } @@ -33,7 +34,7 @@ pub unsafe extern "C" fn PySequence_Count(obj: *mut PyObject, value: *mut PyObje #[unsafe(no_mangle)] pub unsafe extern "C" fn PySequence_DelItem(obj: *mut PyObject, index: isize) -> c_int { with_vm(|vm| { - let obj = unsafe { &*obj }; + let obj = unsafe { obj.assume_borrowed() }; obj.try_sequence(vm)?.del_item(index, vm) }) } @@ -41,7 +42,7 @@ pub unsafe extern "C" fn PySequence_DelItem(obj: *mut PyObject, index: isize) -> #[unsafe(no_mangle)] pub unsafe extern "C" fn PySequence_DelSlice(obj: *mut PyObject, low: isize, high: isize) -> c_int { with_vm(|vm| { - let obj = unsafe { &*obj }; + let obj = unsafe { obj.assume_borrowed() }; obj.try_sequence(vm)?.del_slice(low, high, vm) }) } @@ -49,7 +50,7 @@ pub unsafe extern "C" fn PySequence_DelSlice(obj: *mut PyObject, low: isize, hig #[unsafe(no_mangle)] pub unsafe extern "C" fn PySequence_GetItem(obj: *mut PyObject, index: isize) -> *mut PyObject { with_vm(|vm| { - let obj = unsafe { &*obj }; + let obj = unsafe { obj.assume_borrowed() }; obj.try_sequence(vm)?.get_item(index, vm) }) } @@ -61,7 +62,7 @@ pub unsafe extern "C" fn PySequence_GetSlice( high: isize, ) -> *mut PyObject { with_vm(|vm| { - let obj = unsafe { &*obj }; + let obj = unsafe { obj.assume_borrowed() }; obj.try_sequence(vm)?.get_slice(low, high, vm) }) } @@ -72,8 +73,8 @@ pub unsafe extern "C" fn PySequence_InPlaceConcat( obj2: *mut PyObject, ) -> *mut PyObject { with_vm(|vm| { - let obj1 = unsafe { &*obj1 }; - let obj2 = unsafe { &*obj2 }; + let obj1 = unsafe { obj1.assume_borrowed() }; + let obj2 = unsafe { obj2.assume_borrowed() }; obj1.try_sequence(vm)?.inplace_concat(obj2, vm) }) } @@ -84,7 +85,7 @@ pub unsafe extern "C" fn PySequence_InPlaceRepeat( count: isize, ) -> *mut PyObject { with_vm(|vm| { - let obj = unsafe { &*obj }; + let obj = unsafe { obj.assume_borrowed() }; obj.try_sequence(vm)?.inplace_repeat(count, vm) }) } @@ -92,8 +93,8 @@ pub unsafe extern "C" fn PySequence_InPlaceRepeat( #[unsafe(no_mangle)] pub unsafe extern "C" fn PySequence_Index(obj: *mut PyObject, value: *mut PyObject) -> isize { with_vm(|vm| { - let obj = unsafe { &*obj }; - let value = unsafe { &*value }; + let obj = unsafe { obj.assume_borrowed() }; + let value = unsafe { value.assume_borrowed() }; obj.try_sequence(vm)?.index(value, vm) }) } @@ -101,7 +102,7 @@ pub unsafe extern "C" fn PySequence_Index(obj: *mut PyObject, value: *mut PyObje #[unsafe(no_mangle)] pub unsafe extern "C" fn PySequence_List(obj: *mut PyObject) -> *mut PyObject { with_vm(|vm| { - let obj = unsafe { &*obj }; + let obj = unsafe { obj.assume_borrowed() }; Ok(obj.try_sequence(vm)?.list(vm)) }) } @@ -109,7 +110,7 @@ pub unsafe extern "C" fn PySequence_List(obj: *mut PyObject) -> *mut PyObject { #[unsafe(no_mangle)] pub unsafe extern "C" fn PySequence_Repeat(obj: *mut PyObject, count: isize) -> *mut PyObject { with_vm(|vm| { - let obj = unsafe { &*obj }; + let obj = unsafe { obj.assume_borrowed() }; obj.try_sequence(vm)?.repeat(count, vm) }) } @@ -121,8 +122,8 @@ pub unsafe extern "C" fn PySequence_SetItem( value: *mut PyObject, ) -> c_int { with_vm(|vm| { - let obj = unsafe { &*obj }; - let value = unsafe { &*value }; + let obj = unsafe { obj.assume_borrowed() }; + let value = unsafe { value.assume_borrowed() }; obj.try_sequence(vm)?.set_item(index, value.to_owned(), vm) }) } @@ -135,8 +136,8 @@ pub unsafe extern "C" fn PySequence_SetSlice( value: *mut PyObject, ) -> c_int { with_vm(|vm| { - let obj = unsafe { &*obj }; - let value = unsafe { &*value }; + let obj = unsafe { obj.assume_borrowed() }; + let value = unsafe { value.assume_borrowed() }; obj.try_sequence(vm)? .set_slice(low, high, value.to_owned(), vm) }) @@ -145,7 +146,7 @@ pub unsafe extern "C" fn PySequence_SetSlice( #[unsafe(no_mangle)] pub unsafe extern "C" fn PySequence_Size(obj: *mut PyObject) -> isize { with_vm(|vm| { - let obj = unsafe { &*obj }; + let obj = unsafe { obj.assume_borrowed() }; obj.try_sequence(vm)?.length(vm) }) } @@ -158,7 +159,7 @@ pub unsafe extern "C" fn PySequence_Length(obj: *mut PyObject) -> isize { #[unsafe(no_mangle)] pub unsafe extern "C" fn PySequence_Tuple(obj: *mut PyObject) -> *mut PyObject { with_vm(|vm| { - let obj = unsafe { &*obj }; + let obj = unsafe { obj.assume_borrowed() }; Ok(obj.try_sequence(vm)?.tuple(vm)) }) } @@ -166,8 +167,8 @@ pub unsafe extern "C" fn PySequence_Tuple(obj: *mut PyObject) -> *mut PyObject { #[unsafe(no_mangle)] pub unsafe extern "C" fn PySequence_Contains(obj: *mut PyObject, value: *mut PyObject) -> c_int { with_vm(|vm| { - let obj = unsafe { &*obj }; - let value = unsafe { &*value }; + let obj = unsafe { obj.assume_borrowed() }; + let value = unsafe { value.assume_borrowed() }; obj.sequence_unchecked().contains(value, vm) }) } diff --git a/crates/capi/src/boolobject.rs b/crates/capi/src/boolobject.rs index 464d0ec0b8a..88e796d885f 100644 --- a/crates/capi/src/boolobject.rs +++ b/crates/capi/src/boolobject.rs @@ -1,4 +1,5 @@ use crate::object::define_py_check; +use crate::util::FfiPtrExt; use crate::{PyObject, pystate::with_vm}; use core::ffi::{c_int, c_long}; use rustpython_vm::AsObject; @@ -7,12 +8,18 @@ define_py_check!(fn PyBool_Check, types.bool_type); #[unsafe(no_mangle)] pub unsafe extern "C" fn Py_IsTrue(obj: *mut PyObject) -> c_int { - with_vm(|vm| unsafe { obj.as_ref().is_some_and(|obj| obj.is(&vm.ctx.true_value)) }) + with_vm(|vm| unsafe { + obj.assume_borrowed_or_opt() + .is_some_and(|obj| obj.is(&vm.ctx.true_value)) + }) } #[unsafe(no_mangle)] pub unsafe extern "C" fn Py_IsFalse(obj: *mut PyObject) -> c_int { - with_vm(|vm| unsafe { obj.as_ref().is_some_and(|obj| obj.is(&vm.ctx.false_value)) }) + with_vm(|vm| unsafe { + obj.assume_borrowed_or_opt() + .is_some_and(|obj| obj.is(&vm.ctx.false_value)) + }) } #[unsafe(no_mangle)] diff --git a/crates/capi/src/bytearrayobject.rs b/crates/capi/src/bytearrayobject.rs index cc9db5dd50e..6c8a3e6bf43 100644 --- a/crates/capi/src/bytearrayobject.rs +++ b/crates/capi/src/bytearrayobject.rs @@ -1,6 +1,7 @@ use crate::PyObject; use crate::object::define_py_check; use crate::pystate::with_vm; +use crate::util::FfiPtrExt; use core::ffi::c_char; use rustpython_vm::builtins::PyByteArray; use rustpython_vm::byte::bytes_from_object; @@ -40,7 +41,7 @@ pub unsafe extern "C" fn PyByteArray_FromStringAndSize( #[unsafe(no_mangle)] pub unsafe extern "C" fn PyByteArray_FromObject(obj: *mut PyObject) -> *mut PyObject { with_vm(|vm| { - let obj = unsafe { &*obj }; + let obj = unsafe { obj.assume_borrowed() }; let data = bytes_from_object(vm, obj)?; Ok(vm.ctx.new_bytearray(data)) }) @@ -49,7 +50,7 @@ pub unsafe extern "C" fn PyByteArray_FromObject(obj: *mut PyObject) -> *mut PyOb #[unsafe(no_mangle)] pub unsafe extern "C" fn PyByteArray_Size(bytearray: *mut PyObject) -> isize { with_vm(|vm| { - let bytearray = unsafe { &*bytearray }.try_downcast_ref::(vm)?; + let bytearray = unsafe { bytearray.assume_borrowed_and_cast::(vm) }?; Ok(bytearray.borrow_buf().len()) }) } @@ -57,7 +58,7 @@ pub unsafe extern "C" fn PyByteArray_Size(bytearray: *mut PyObject) -> isize { #[unsafe(no_mangle)] pub unsafe extern "C" fn PyByteArray_AsString(bytearray: *mut PyObject) -> *mut c_char { with_vm(|vm| { - let bytearray = unsafe { &*bytearray }.try_downcast_ref::(vm)?; + let bytearray = unsafe { bytearray.assume_borrowed_and_cast::(vm) }?; Ok(bytearray.borrow_buf_mut().as_mut_ptr()) }) } @@ -65,7 +66,7 @@ pub unsafe extern "C" fn PyByteArray_AsString(bytearray: *mut PyObject) -> *mut #[unsafe(no_mangle)] pub unsafe extern "C" fn PyByteArray_Resize(bytearray: *mut PyObject, len: isize) -> i32 { with_vm(|vm| { - let bytearray = unsafe { &*bytearray }.try_downcast_ref::(vm)?; + let bytearray = unsafe { bytearray.assume_borrowed_and_cast::(vm) }?; bytearray.resize(len, vm)?; Ok(()) }) diff --git a/crates/capi/src/bytesobject.rs b/crates/capi/src/bytesobject.rs index f4db16af6b3..07f5d37a47d 100644 --- a/crates/capi/src/bytesobject.rs +++ b/crates/capi/src/bytesobject.rs @@ -1,4 +1,5 @@ use crate::object::define_py_check; +use crate::util::FfiPtrExt; use crate::{PyObject, pystate::with_vm}; use core::ffi::c_char; use rustpython_vm::builtins::PyBytes; @@ -32,7 +33,7 @@ pub unsafe extern "C" fn PyBytes_FromStringAndSize( #[unsafe(no_mangle)] pub unsafe extern "C" fn PyBytes_Size(bytes: *mut PyObject) -> isize { with_vm(|vm| { - let bytes = unsafe { &*bytes }.try_downcast_ref::(vm)?; + let bytes = unsafe { bytes.assume_borrowed_and_cast::(vm) }?; Ok(bytes.as_bytes().len()) }) } @@ -40,7 +41,7 @@ pub unsafe extern "C" fn PyBytes_Size(bytes: *mut PyObject) -> isize { #[unsafe(no_mangle)] pub unsafe extern "C" fn PyBytes_AsString(bytes: *mut PyObject) -> *mut c_char { with_vm(|vm| { - let bytes = unsafe { &*bytes }.try_downcast_ref::(vm)?; + let bytes = unsafe { bytes.assume_borrowed_and_cast::(vm) }?; Ok(bytes.as_bytes().as_ptr()) }) } diff --git a/crates/capi/src/ceval.rs b/crates/capi/src/ceval.rs index 366cb0071bb..0f10f1a70a7 100644 --- a/crates/capi/src/ceval.rs +++ b/crates/capi/src/ceval.rs @@ -1,8 +1,8 @@ use crate::pyframe::PyFrameObject; use crate::pystate::with_vm; use crate::unicodeobject::decode_fsdefault_and_size; +use crate::util::FfiPtrExt; use core::ffi::{CStr, c_char, c_int}; -use core::ptr::NonNull; use rustpython_vm::builtins::{PyCode, PyDict}; use rustpython_vm::function::ArgMapping; use rustpython_vm::scope::Scope; @@ -31,10 +31,10 @@ pub unsafe extern "C" fn PyEval_EvalCode( locals: *mut PyObject, ) -> *mut PyObject { with_vm(|vm| { - let code = unsafe { &*co }.try_downcast_ref::(vm)?; - let globals = unsafe { &*globals }.try_downcast_ref::(vm)?; - let locals = NonNull::new(locals) - .map(|ptr| ArgMapping::try_from_object(vm, unsafe { ptr.as_ref() }.to_owned())) + let code = unsafe { co.assume_borrowed_and_cast::(vm) }?; + let globals = unsafe { globals.assume_borrowed_and_cast::(vm) }?; + let locals = unsafe { locals.assume_borrowed_or_opt() } + .map(|obj| ArgMapping::try_from_object(vm, obj.to_owned())) .transpose()?; let scope = Scope::with_builtins(locals, globals.to_owned(), vm); @@ -50,7 +50,7 @@ pub unsafe extern "C" fn PyEval_EvalFrame(f: *mut PyFrameObject) -> *mut PyObjec #[unsafe(no_mangle)] pub unsafe extern "C" fn PyEval_EvalFrameEx(f: *mut PyFrameObject, _exc: c_int) -> *mut PyObject { - with_vm(|vm| vm.run_frame(unsafe { &*f }.to_owned())) + with_vm(|vm| vm.run_frame(unsafe { f.assume_borrowed() }.to_owned())) } #[unsafe(no_mangle)] @@ -126,7 +126,7 @@ pub extern "C" fn PyEval_GetLocals() -> *mut PyObject { #[unsafe(no_mangle)] pub unsafe extern "C" fn PyEval_GetFuncDesc(func: *mut PyObject) -> *const c_char { with_vm(|vm| { - let func = unsafe { &*func }; + let func = unsafe { func.assume_borrowed() }; let cls = func.class(); if cls.is(vm.ctx.types.bound_method_type) || cls.is(vm.ctx.types.function_type) diff --git a/crates/capi/src/codecs.rs b/crates/capi/src/codecs.rs index 8433bf3baa4..24f3004ac2b 100644 --- a/crates/capi/src/codecs.rs +++ b/crates/capi/src/codecs.rs @@ -1,4 +1,5 @@ use crate::util::CStrExt; +use crate::util::FfiPtrExt; use crate::{PyObject, pystate::with_vm}; use core::ffi::{c_char, c_int}; use rustpython_vm::{AsObject, VirtualMachine}; @@ -11,7 +12,7 @@ fn call_codec_error_handler( vm.state .codec_registry .lookup_error(handler_name, vm)? - .call((unsafe { &*exc }.to_owned(),), vm) + .call((unsafe { exc.assume_borrowed() }.to_owned(),), vm) } fn codec_stream( @@ -23,7 +24,7 @@ fn codec_stream( ) -> rustpython_vm::PyResult { let encoding = unsafe { encoding.try_as_str_opt(vm) }?.unwrap_or("utf-8"); let errors = unsafe { errors.try_as_str_opt(vm) }?.map(|errors| vm.ctx.new_str(errors)); - let stream = unsafe { &*stream }.to_owned(); + let stream = unsafe { stream.assume_borrowed() }.to_owned(); let codec = vm.state.codec_registry.lookup(encoding, vm)?; let args = match errors { Some(errors) => vec![stream, errors.into()], @@ -35,7 +36,7 @@ fn codec_stream( #[unsafe(no_mangle)] pub unsafe extern "C" fn PyCodec_Register(search_function: *mut PyObject) -> c_int { with_vm(|vm| { - let search_function = unsafe { &*search_function }.to_owned(); + let search_function = unsafe { search_function.assume_borrowed() }.to_owned(); vm.state.codec_registry.register(search_function, vm) }) } @@ -43,7 +44,7 @@ pub unsafe extern "C" fn PyCodec_Register(search_function: *mut PyObject) -> c_i #[unsafe(no_mangle)] pub unsafe extern "C" fn PyCodec_Unregister(search_function: *mut PyObject) -> c_int { with_vm(|vm| { - let search_function = unsafe { &*search_function }.to_owned(); + let search_function = unsafe { search_function.assume_borrowed() }.to_owned(); vm.state.codec_registry.unregister(search_function); }) } @@ -67,7 +68,7 @@ pub unsafe extern "C" fn PyCodec_Encode( errors: *const c_char, ) -> *mut PyObject { with_vm(|vm| { - let object = unsafe { &*object }.to_owned(); + let object = unsafe { object.assume_borrowed() }.to_owned(); let encoding = unsafe { encoding.try_as_str_opt(vm) }?.unwrap_or("utf-8"); let errors = unsafe { errors.try_as_str_opt(vm) }?.map(|errors| vm.ctx.new_utf8_str(errors)); @@ -82,7 +83,7 @@ pub unsafe extern "C" fn PyCodec_Decode( errors: *const c_char, ) -> *mut PyObject { with_vm(|vm| { - let object = unsafe { &*object }.to_owned(); + let object = unsafe { object.assume_borrowed() }.to_owned(); let encoding = unsafe { encoding.try_as_str_opt(vm) }?.unwrap_or("utf-8"); let errors = unsafe { errors.try_as_str_opt(vm) }?.map(|errors| vm.ctx.new_utf8_str(errors)); @@ -160,7 +161,7 @@ pub unsafe extern "C" fn PyCodec_StreamWriter( pub unsafe extern "C" fn PyCodec_RegisterError(name: *const c_char, error: *mut PyObject) -> c_int { with_vm(|vm| { let name = unsafe { name.try_as_str(vm) }?; - let error = unsafe { &*error }.to_owned(); + let error = unsafe { error.assume_borrowed() }.to_owned(); if !error.is_callable() { return Err(vm.new_type_error("handler must be callable")); } diff --git a/crates/capi/src/complexobject.rs b/crates/capi/src/complexobject.rs index 79f1804d1bd..1c53df08ef6 100644 --- a/crates/capi/src/complexobject.rs +++ b/crates/capi/src/complexobject.rs @@ -1,4 +1,5 @@ use crate::object::define_py_check; +use crate::util::FfiPtrExt; use crate::{PyObject, pystate::with_vm}; use core::ffi::c_double; use num_complex::{Complex, Complex64}; @@ -28,12 +29,12 @@ fn try_to_complex(vm: &VirtualMachine, obj: &PyObject) -> PyResult { #[unsafe(no_mangle)] pub unsafe extern "C" fn PyComplex_RealAsDouble(obj: *mut PyObject) -> c_double { - with_vm(|vm| try_to_complex(vm, unsafe { &*obj }).map(|complex| complex.re)) + with_vm(|vm| try_to_complex(vm, unsafe { obj.assume_borrowed() }).map(|complex| complex.re)) } #[unsafe(no_mangle)] pub unsafe extern "C" fn PyComplex_ImagAsDouble(obj: *mut PyObject) -> c_double { - with_vm(|vm| try_to_complex(vm, unsafe { &*obj }).map(|complex| complex.im)) + with_vm(|vm| try_to_complex(vm, unsafe { obj.assume_borrowed() }).map(|complex| complex.im)) } #[cfg(test)] diff --git a/crates/capi/src/descrobject.rs b/crates/capi/src/descrobject.rs index 863f286e13a..c89d0b02db1 100644 --- a/crates/capi/src/descrobject.rs +++ b/crates/capi/src/descrobject.rs @@ -2,7 +2,7 @@ use crate::PyObject; use crate::methodobject::{PyMethodDef, build_method_def}; use crate::object::PyTypeObject; use crate::pystate::with_vm; -use crate::util::CStrExt; +use crate::util::{CStrExt, FfiPtrExt}; use core::ffi::{c_char, c_int, c_void}; use core::ptr::NonNull; use rustpython_vm::builtins::{ @@ -53,7 +53,7 @@ impl PyGetSetDef { ) }) })?; - Ok(PyObjectRef::from_raw(ret_ptr)) + Ok(ret_ptr.as_ptr().assume_owned()) } }, move |obj: PyObjectRef, value: PySetterValue, vm: &VirtualMachine| unsafe { @@ -85,7 +85,7 @@ impl PyGetSetDef { ) }) })?; - Ok(PyObjectRef::from_raw(ret_ptr)) + Ok(ret_ptr.as_ptr().assume_owned()) } }, ), @@ -190,7 +190,7 @@ impl PyMemberDef { #[unsafe(no_mangle)] pub unsafe extern "C" fn PyDictProxy_New(mapping: *mut PyObject) -> *mut PyObject { with_vm(|vm| { - let mapping = unsafe { &*mapping }.to_owned(); + let mapping = unsafe { mapping.assume_borrowed() }.to_owned(); Ok(PyMappingProxy::from_object(mapping, vm)?.into_ref(&vm.ctx)) }) } @@ -202,7 +202,7 @@ pub unsafe extern "C" fn PyDescr_NewMethod( ) -> *mut PyObject { with_vm(|vm| { let method = build_method_def(vm, unsafe { &*method }, true)?; - Ok(method.build_method(unsafe { &*typ }, vm)) + Ok(method.build_method(unsafe { typ.assume_borrowed() }, vm)) }) } @@ -213,7 +213,7 @@ pub unsafe extern "C" fn PyDescr_NewClassMethod( ) -> *mut PyObject { with_vm(|vm| { let method = build_method_def(vm, unsafe { &*method }, true)?; - Ok(method.build_method(unsafe { &*typ }, vm)) + Ok(method.build_method(unsafe { typ.assume_borrowed() }, vm)) }) } @@ -230,14 +230,14 @@ pub unsafe extern "C" fn PyDescr_NewMember( typ: *mut PyTypeObject, member: *mut PyMemberDef, ) -> *mut PyObject { - with_vm(|vm| Ok(unsafe { &*member }.build(unsafe { &*typ }, vm))) + with_vm(|vm| Ok(unsafe { &*member }.build(unsafe { typ.assume_borrowed() }, vm))) } #[unsafe(no_mangle)] pub unsafe extern "C" fn PyWrapper_New(descr: *mut PyObject, obj: *mut PyObject) -> *mut PyObject { with_vm(|vm| { - let descr = unsafe { &*descr }; - let obj = unsafe { &*obj }; + let descr = unsafe { descr.assume_borrowed() }; + let obj = unsafe { obj.assume_borrowed() }; vm.call_special_method( descr, vm.ctx.names.__get__, diff --git a/crates/capi/src/dictobject.rs b/crates/capi/src/dictobject.rs index ed29c693463..1afd3292a79 100644 --- a/crates/capi/src/dictobject.rs +++ b/crates/capi/src/dictobject.rs @@ -1,7 +1,7 @@ use crate::PyObject; use crate::object::define_py_check; use crate::pystate::with_vm; -use crate::util::CStrExt; +use crate::util::{CStrExt, FfiPtrExt}; use core::ffi::{c_char, c_int}; use core::ptr::NonNull; use rustpython_vm::AsObject; @@ -22,7 +22,7 @@ pub extern "C" fn PyDict_New() -> *mut PyObject { #[unsafe(no_mangle)] pub unsafe extern "C" fn PyDict_Clear(dict: *mut PyObject) { with_vm(|vm| { - let dict = unsafe { &*dict }.try_downcast_ref::(vm)?; + let dict = unsafe { dict.assume_borrowed_and_cast::(vm) }?; dict.clear(); Ok(()) }) @@ -35,9 +35,9 @@ pub unsafe extern "C" fn PyDict_SetItem( val: *mut PyObject, ) -> c_int { with_vm(|vm| { - let dict = unsafe { &*dict }.try_downcast_ref::(vm)?; - let key = unsafe { &*key }; - let value = unsafe { &*val }.to_owned(); + let dict = unsafe { dict.assume_borrowed_and_cast::(vm) }?; + let key = unsafe { key.assume_borrowed() }; + let value = unsafe { val.assume_borrowed() }.to_owned(); dict.inner_setitem(key, value, vm) }) } @@ -49,9 +49,9 @@ pub unsafe extern "C" fn PyDict_SetItemString( val: *mut PyObject, ) -> c_int { with_vm(|vm| { - let dict = unsafe { &*dict }.try_downcast_ref::(vm)?; + let dict = unsafe { dict.assume_borrowed_and_cast::(vm) }?; let key = unsafe { key.try_as_str(vm) }?; - let value = unsafe { &*val }.to_owned(); + let value = unsafe { val.assume_borrowed() }.to_owned(); dict.inner_setitem(key, value, vm) }) } @@ -59,8 +59,8 @@ pub unsafe extern "C" fn PyDict_SetItemString( #[unsafe(no_mangle)] pub unsafe extern "C" fn PyDict_GetItem(dict: *mut PyObject, key: *mut PyObject) -> *mut PyObject { with_vm(|vm| { - let dict = unsafe { &*dict }.try_downcast_ref::(vm)?; - let key = unsafe { &*key }; + let dict = unsafe { dict.assume_borrowed_and_cast::(vm) }?; + let key = unsafe { key.assume_borrowed() }; match dict.inner_getitem_opt(key, vm) { Ok(Some(value)) => Ok(value.as_object().as_raw().cast_mut()), @@ -75,8 +75,8 @@ pub unsafe extern "C" fn PyDict_GetItemWithError( key: *mut PyObject, ) -> *mut PyObject { with_vm(|vm| { - let dict = unsafe { &*dict }.try_downcast_ref::(vm)?; - let key = unsafe { &*key }; + let dict = unsafe { dict.assume_borrowed_and_cast::(vm) }?; + let key = unsafe { key.assume_borrowed() }; if let Some(value) = dict.inner_getitem_opt(key, vm)? { Ok(value.as_object().as_raw().cast_mut()) @@ -92,7 +92,7 @@ pub unsafe extern "C" fn PyDict_GetItemString( key: *const c_char, ) -> *mut PyObject { with_vm(|vm| { - let dict = unsafe { &*dict }.try_downcast_ref::(vm)?; + let dict = unsafe { dict.assume_borrowed_and_cast::(vm) }?; let key = unsafe { key.try_as_str(vm) }?; match dict.inner_getitem_opt(key, vm)? { @@ -112,7 +112,7 @@ pub unsafe extern "C" fn PyDict_GetItemStringRef( unsafe { *result = core::ptr::null_mut(); } - let dict = unsafe { &*dict }.try_downcast_ref::(vm)?; + let dict = unsafe { dict.assume_borrowed_and_cast::(vm) }?; let key = unsafe { key.try_as_str(vm) }?; if let Some(value) = dict.inner_getitem_opt(key, vm)? { @@ -134,8 +134,8 @@ pub unsafe extern "C" fn PyDict_GetItemRef( ) -> c_int { with_vm(|vm| { unsafe { *result = core::ptr::null_mut() }; - let dict = unsafe { &*dict }.try_downcast_ref::(vm)?; - let key = unsafe { &*key }; + let dict = unsafe { dict.assume_borrowed_and_cast::(vm) }?; + let key = unsafe { key.assume_borrowed() }; if let Some(value) = dict.inner_getitem_opt(key, vm)? { unsafe { @@ -165,8 +165,8 @@ pub unsafe extern "C" fn PyDict_SetDefaultRef( result.write(core::ptr::null_mut()); } } - let dict = unsafe { &*dict }.try_downcast_ref::(vm)?; - let key = unsafe { &*key }; + let dict = unsafe { dict.assume_borrowed_and_cast::(vm) }?; + let key = unsafe { key.assume_borrowed() }; if let Some(value) = dict.inner_getitem_opt(key, vm)? { if let Some(result) = result { @@ -176,7 +176,7 @@ pub unsafe extern "C" fn PyDict_SetDefaultRef( } Ok(true) } else { - let value = unsafe { &*default_value }.to_owned(); + let value = unsafe { default_value.assume_borrowed() }.to_owned(); dict.inner_setitem(key, value.clone(), vm)?; if let Some(result) = result { unsafe { @@ -191,7 +191,7 @@ pub unsafe extern "C" fn PyDict_SetDefaultRef( #[unsafe(no_mangle)] pub unsafe extern "C" fn PyDict_Size(dict: *mut PyObject) -> isize { with_vm(|vm| { - let dict = unsafe { &*dict }.try_downcast_ref::(vm)?; + let dict = unsafe { dict.assume_borrowed_and_cast::(vm) }?; Ok(dict.__len__()) }) } @@ -199,8 +199,8 @@ pub unsafe extern "C" fn PyDict_Size(dict: *mut PyObject) -> isize { #[unsafe(no_mangle)] pub unsafe extern "C" fn PyDict_Contains(dict: *mut PyObject, key: *mut PyObject) -> c_int { with_vm(|vm| { - let dict = unsafe { &*dict }.try_downcast_ref::(vm)?; - let key = unsafe { &*key }; + let dict = unsafe { dict.assume_borrowed_and_cast::(vm) }?; + let key = unsafe { key.assume_borrowed() }; Ok(dict.inner_getitem_opt(key, vm)?.is_some()) }) } @@ -208,7 +208,7 @@ pub unsafe extern "C" fn PyDict_Contains(dict: *mut PyObject, key: *mut PyObject #[unsafe(no_mangle)] pub unsafe extern "C" fn PyDict_Copy(dict: *mut PyObject) -> *mut PyObject { with_vm(|vm| { - let dict = unsafe { &*dict }.try_downcast_ref::(vm)?; + let dict = unsafe { dict.assume_borrowed_and_cast::(vm) }?; Ok(dict.copy().into_ref(&vm.ctx)) }) } @@ -216,8 +216,8 @@ pub unsafe extern "C" fn PyDict_Copy(dict: *mut PyObject) -> *mut PyObject { #[unsafe(no_mangle)] pub unsafe extern "C" fn PyDict_DelItem(dict: *mut PyObject, key: *mut PyObject) -> c_int { with_vm(|vm| { - let dict = unsafe { &*dict }.try_downcast_ref::(vm)?; - let key = unsafe { &*key }; + let dict = unsafe { dict.assume_borrowed_and_cast::(vm) }?; + let key = unsafe { key.assume_borrowed() }; dict.del_item(key, vm) }) } @@ -225,7 +225,7 @@ pub unsafe extern "C" fn PyDict_DelItem(dict: *mut PyObject, key: *mut PyObject) #[unsafe(no_mangle)] pub unsafe extern "C" fn PyDict_DelItemString(dict: *mut PyObject, key: *const c_char) -> c_int { with_vm(|vm| { - let dict = unsafe { &*dict }.try_downcast_ref::(vm)?; + let dict = unsafe { dict.assume_borrowed_and_cast::(vm) }?; let key = unsafe { key.try_as_str(vm) }?; dict.del_item(key, vm) }) @@ -234,7 +234,7 @@ pub unsafe extern "C" fn PyDict_DelItemString(dict: *mut PyObject, key: *const c #[unsafe(no_mangle)] pub unsafe extern "C" fn PyDict_Items(dict: *mut PyObject) -> *mut PyObject { with_vm(|vm| { - let dict = unsafe { &*dict }.try_downcast_ref::(vm)?; + let dict = unsafe { dict.assume_borrowed_and_cast::(vm) }?; let items = dict .items_vec() .into_iter() @@ -247,7 +247,7 @@ pub unsafe extern "C" fn PyDict_Items(dict: *mut PyObject) -> *mut PyObject { #[unsafe(no_mangle)] pub unsafe extern "C" fn PyDict_Keys(dict: *mut PyObject) -> *mut PyObject { with_vm(|vm| { - let dict = unsafe { &*dict }.try_downcast_ref::(vm)?; + let dict = unsafe { dict.assume_borrowed_and_cast::(vm) }?; Ok(vm.ctx.new_list(dict.keys_vec())) }) } @@ -255,7 +255,7 @@ pub unsafe extern "C" fn PyDict_Keys(dict: *mut PyObject) -> *mut PyObject { #[unsafe(no_mangle)] pub unsafe extern "C" fn PyDict_Values(dict: *mut PyObject) -> *mut PyObject { with_vm(|vm| { - let dict = unsafe { &*dict }.try_downcast_ref::(vm)?; + let dict = unsafe { dict.assume_borrowed_and_cast::(vm) }?; Ok(vm.ctx.new_list(dict.values_vec())) }) } @@ -267,8 +267,8 @@ pub unsafe extern "C" fn PyDict_Merge( override_: c_int, ) -> c_int { with_vm(|vm| { - let dict = unsafe { &*dict }.try_downcast_ref::(vm)?; - let other = unsafe { &*other }.to_owned(); + let dict = unsafe { dict.assume_borrowed_and_cast::(vm) }?; + let other = unsafe { other.assume_borrowed() }.to_owned(); if override_ != 0 { dict.merge_object(other, vm) } else { @@ -280,8 +280,8 @@ pub unsafe extern "C" fn PyDict_Merge( #[unsafe(no_mangle)] pub unsafe extern "C" fn PyDict_Update(dict: *mut PyObject, other: *mut PyObject) -> c_int { with_vm(|vm| { - let dict = unsafe { &*dict }.try_downcast_ref::(vm)?; - let other = unsafe { &*other }.to_owned(); + let dict = unsafe { dict.assume_borrowed_and_cast::(vm) }?; + let other = unsafe { other.assume_borrowed() }.to_owned(); dict.merge_object(other, vm) }) } @@ -293,8 +293,8 @@ pub unsafe extern "C" fn PyDict_MergeFromSeq2( override_: c_int, ) -> c_int { with_vm(|vm| { - let dict = unsafe { &*dict }.try_downcast_ref::(vm)?; - let seq2 = unsafe { &*seq2 }.to_owned(); + let dict = unsafe { dict.assume_borrowed_and_cast::(vm) }?; + let seq2 = unsafe { seq2.assume_borrowed() }.to_owned(); dict.merge_from_seq2(seq2, override_ != 0, vm) }) } @@ -307,7 +307,7 @@ pub unsafe extern "C" fn PyDict_Next( value: *mut *mut PyObject, ) -> c_int { with_vm(|vm| { - let dict = unsafe { &*dict }.try_downcast_ref::(vm)?; + let dict = unsafe { dict.assume_borrowed_and_cast::(vm) }?; let index = unsafe { *pos } as usize; if let Some((next_pos, k, v)) = dict.next_entry(index) { diff --git a/crates/capi/src/floatobject.rs b/crates/capi/src/floatobject.rs index ead09c219bb..b942a9eee54 100644 --- a/crates/capi/src/floatobject.rs +++ b/crates/capi/src/floatobject.rs @@ -1,7 +1,7 @@ use crate::object::define_py_check; +use crate::util::FfiPtrExt; use crate::{PyObject, pystate::with_vm}; use core::ffi::c_double; -use core::ptr::NonNull; use rustpython_vm::AsObject; use rustpython_vm::builtins::PyFloat; @@ -16,7 +16,7 @@ pub extern "C" fn PyFloat_FromDouble(value: c_double) -> *mut PyObject { #[unsafe(no_mangle)] pub unsafe extern "C" fn PyFloat_AsDouble(obj: *mut PyObject) -> c_double { with_vm(|vm| { - let obj_ref = unsafe { &*obj }; + let obj_ref = unsafe { obj.assume_borrowed() }; let float_obj = obj_ref .to_owned() .try_downcast::(vm) @@ -49,9 +49,9 @@ pub extern "C" fn PyFloat_GetInfo() -> *mut PyObject { #[unsafe(no_mangle)] pub unsafe extern "C" fn PyFloat_FromString(obj: *mut PyObject) -> *mut PyObject { with_vm(|vm| { - let obj = NonNull::new(obj) - .ok_or_else(|| vm.new_type_error("float() argument must be a string or a number"))?; - let obj = unsafe { obj.as_ref() }.to_owned(); + let obj = unsafe { obj.assume_borrowed_or_opt() } + .ok_or_else(|| vm.new_type_error("float() argument must be a string or a number"))? + .to_owned(); let float = rustpython_vm::builtins::parse_float_from_string(obj, vm)?; Ok(vm.ctx.new_float(float)) }) diff --git a/crates/capi/src/genericaliasobject.rs b/crates/capi/src/genericaliasobject.rs index bcd31308679..e96c2fb7905 100644 --- a/crates/capi/src/genericaliasobject.rs +++ b/crates/capi/src/genericaliasobject.rs @@ -1,3 +1,4 @@ +use crate::util::FfiPtrExt; use crate::{PyObject, pystate::with_vm}; use rustpython_vm::PyPayload; use rustpython_vm::builtins::PyGenericAlias; @@ -8,8 +9,8 @@ pub unsafe extern "C" fn Py_GenericAlias( args: *mut PyObject, ) -> *mut PyObject { with_vm(|vm| { - let origin = unsafe { &*origin }.to_owned(); - let args = unsafe { &*args }.to_owned(); + let origin = unsafe { origin.assume_borrowed() }.to_owned(); + let args = unsafe { args.assume_borrowed() }.to_owned(); PyGenericAlias::from_args(origin, args, vm).into_pyobject(vm) }) } diff --git a/crates/capi/src/import.rs b/crates/capi/src/import.rs index 3a8dae651c9..1a423e1a111 100644 --- a/crates/capi/src/import.rs +++ b/crates/capi/src/import.rs @@ -1,4 +1,4 @@ -use crate::util::CStrExt; +use crate::util::{CStrExt, FfiPtrExt}; use crate::{PyObject, pystate::with_vm}; use core::ffi::c_char; use rustpython_vm::builtins::{PyCode, PyDict, PyModule, PyStr}; @@ -7,7 +7,7 @@ use rustpython_vm::import::import_code_obj; #[unsafe(no_mangle)] pub unsafe extern "C" fn PyImport_Import(name: *mut PyObject) -> *mut PyObject { with_vm(|vm| { - let name = unsafe { (&*name).try_downcast_ref::(vm)? }; + let name = unsafe { name.assume_borrowed_and_cast::(vm) }?; vm.import(name, 0) }) } @@ -46,7 +46,7 @@ pub unsafe extern "C" fn PyImport_ExecCodeModuleEx( ) -> *mut PyObject { with_vm(|vm| { let name = unsafe { name.try_as_str(vm) }?; - let code = unsafe { &*co }.try_downcast_ref::(vm)?; + let code = unsafe { co.assume_borrowed_and_cast::(vm) }?; let module = import_code_obj(vm, name, code.to_owned(), false)?; if let Some(pathname) = unsafe { pathname.try_as_str_opt(vm) }? { diff --git a/crates/capi/src/listobject.rs b/crates/capi/src/listobject.rs index 03069b0495b..208f2026bc4 100644 --- a/crates/capi/src/listobject.rs +++ b/crates/capi/src/listobject.rs @@ -1,8 +1,8 @@ use crate::PyObject; use crate::object::define_py_check; use crate::pystate::with_vm; +use crate::util::FfiPtrExt; use core::ffi::c_int; -use core::ptr::NonNull; use rustpython_vm::AsObject; use rustpython_vm::PyObjectRef; use rustpython_vm::builtins::PyList; @@ -24,7 +24,7 @@ pub extern "C" fn PyList_New(size: isize) -> *mut PyObject { #[unsafe(no_mangle)] pub unsafe extern "C" fn PyList_Size(obj: *mut PyObject) -> isize { with_vm(|vm| { - let list = unsafe { &*obj }.try_downcast_ref::(vm)?; + let list = unsafe { obj.assume_borrowed_and_cast::(vm) }?; Ok(list.__len__()) }) } @@ -32,7 +32,7 @@ pub unsafe extern "C" fn PyList_Size(obj: *mut PyObject) -> isize { #[unsafe(no_mangle)] pub unsafe extern "C" fn PyList_GetItemRef(obj: *mut PyObject, index: isize) -> *mut PyObject { with_vm(|vm| { - let list = unsafe { &*obj }.try_downcast_ref::(vm)?; + let list = unsafe { obj.assume_borrowed_and_cast::(vm) }?; index .try_into() .ok() @@ -48,8 +48,8 @@ pub unsafe extern "C" fn PyList_SetItem( item: *mut PyObject, ) -> c_int { with_vm(|vm| { - let list = unsafe { &*list }.try_downcast_ref::(vm)?; - let item = unsafe { PyObjectRef::from_raw(NonNull::new_unchecked(item)) }; + let list = unsafe { list.assume_borrowed_and_cast::(vm) }?; + let item = unsafe { item.assume_owned() }; let index_error = || vm.new_index_error(format!("list assignment index out of range: {index}")); if index < 0 { @@ -75,8 +75,8 @@ pub unsafe extern "C" fn PyList_SetItem( #[unsafe(no_mangle)] pub unsafe extern "C" fn PyList_Append(list: *mut PyObject, item: *mut PyObject) -> c_int { with_vm(|vm| { - let list = unsafe { &*list }.try_downcast_ref::(vm)?; - let item = unsafe { &*item }.to_owned(); + let list = unsafe { list.assume_borrowed_and_cast::(vm) }?; + let item = unsafe { item.assume_borrowed() }.to_owned(); list.borrow_vec_mut().push(item); Ok(()) }) @@ -89,8 +89,8 @@ pub unsafe extern "C" fn PyList_Insert( item: *mut PyObject, ) -> c_int { with_vm(|vm| { - let list = unsafe { &*list }.try_downcast_ref::(vm)?; - let item = unsafe { &*item }.to_owned(); + let list = unsafe { list.assume_borrowed_and_cast::(vm) }?; + let item = unsafe { item.assume_borrowed() }.to_owned(); let mut vec = list.borrow_vec_mut(); let index = if index < 0 { index + vec.len() as isize @@ -106,7 +106,7 @@ pub unsafe extern "C" fn PyList_Insert( #[unsafe(no_mangle)] pub unsafe extern "C" fn PyList_Reverse(list: *mut PyObject) -> c_int { with_vm(|vm| { - let list = unsafe { &*list }.try_downcast_ref::(vm)?; + let list = unsafe { list.assume_borrowed_and_cast::(vm) }?; list.borrow_vec_mut().reverse(); Ok(()) }) @@ -115,7 +115,7 @@ pub unsafe extern "C" fn PyList_Reverse(list: *mut PyObject) -> c_int { #[unsafe(no_mangle)] pub unsafe extern "C" fn PyList_AsTuple(list: *mut PyObject) -> *mut PyObject { with_vm(|vm| { - let list = unsafe { &*list }.try_downcast_ref::(vm)?; + let list = unsafe { list.assume_borrowed_and_cast::(vm) }?; Ok(vm.ctx.new_tuple(list.borrow_vec().to_vec())) }) } @@ -127,7 +127,7 @@ pub unsafe extern "C" fn PyList_GetSlice( high: isize, ) -> *mut PyObject { with_vm(|vm| { - let list = unsafe { &*list }.try_downcast_ref::(vm)?; + let list = unsafe { list.assume_borrowed_and_cast::(vm) }?; let vec = list.borrow_vec(); let sliced = vec.getitem_by_slice(vm, SaturatedSlice::from_parts(low, high, 1))?; Ok(vm.ctx.new_list(sliced)) @@ -142,16 +142,16 @@ pub unsafe extern "C" fn PyList_SetSlice( itemlist: *mut PyObject, ) -> c_int { with_vm(|vm| { - let list = unsafe { &*list }.try_downcast_ref::(vm)?; + let list = unsafe { list.assume_borrowed_and_cast::(vm) }?; let slice = SaturatedSlice::from_parts(low, high, 1); let mut vec = list.borrow_vec_mut(); - if itemlist.is_null() { + let Some(itemlist) = (unsafe { itemlist.assume_borrowed_or_opt() }) else { vec.delitem_by_slice(vm, slice)?; return Ok(()); - } + }; - let items: Vec = unsafe { &*itemlist }.try_to_value(vm)?; + let items: Vec = itemlist.try_to_value(vm)?; vec.setitem_by_slice(vm, slice, &items) }) } @@ -159,7 +159,7 @@ pub unsafe extern "C" fn PyList_SetSlice( #[unsafe(no_mangle)] pub unsafe extern "C" fn PyList_Sort(list: *mut PyObject) -> c_int { with_vm(|vm| { - let list = unsafe { &*list }.try_downcast_ref::(vm)?; + let list = unsafe { list.assume_borrowed_and_cast::(vm) }?; vm.call_method(list.as_object(), "sort", ())?; Ok(()) }) diff --git a/crates/capi/src/longobject.rs b/crates/capi/src/longobject.rs index d88523a7ddc..c369963a2d9 100644 --- a/crates/capi/src/longobject.rs +++ b/crates/capi/src/longobject.rs @@ -1,4 +1,5 @@ use crate::object::define_py_check; +use crate::util::FfiPtrExt; use crate::{PyObject, pystate::with_vm}; use bitflags::bitflags; use core::ffi::{CStr, c_char, c_double, c_int, c_long, c_longlong, c_ulong, c_ulonglong, c_void}; @@ -188,7 +189,7 @@ pub unsafe extern "C" fn PyLong_FromString( #[unsafe(no_mangle)] pub unsafe extern "C" fn PyLong_AsLong(obj: *mut PyObject) -> c_long { with_vm::, _>(|vm| { - unsafe { &*obj } + unsafe { obj.assume_borrowed() } .to_owned() .try_index(vm)? .as_bigint() @@ -200,7 +201,7 @@ pub unsafe extern "C" fn PyLong_AsLong(obj: *mut PyObject) -> c_long { #[unsafe(no_mangle)] pub unsafe extern "C" fn PyLong_AsDouble(obj: *mut PyObject) -> c_double { with_vm::, _>(|vm| { - let int = unsafe { &*obj }.try_downcast_ref::(vm)?; + let int = unsafe { obj.assume_borrowed_and_cast::(vm) }?; try_bigint_to_f64(int.as_bigint(), vm) }) } @@ -208,7 +209,7 @@ pub unsafe extern "C" fn PyLong_AsDouble(obj: *mut PyObject) -> c_double { #[unsafe(no_mangle)] pub unsafe extern "C" fn PyLong_AsInt(obj: *mut PyObject) -> c_int { with_vm::, _>(|vm| { - unsafe { &*obj } + unsafe { obj.assume_borrowed() } .to_owned() .try_index(vm)? .as_bigint() @@ -220,7 +221,7 @@ pub unsafe extern "C" fn PyLong_AsInt(obj: *mut PyObject) -> c_int { #[unsafe(no_mangle)] pub unsafe extern "C" fn PyLong_AsInt32(obj: *mut PyObject, out: *mut i32) -> c_int { with_vm(|vm| { - let value: i32 = unsafe { &*obj } + let value: i32 = unsafe { obj.assume_borrowed() } .to_owned() .try_index(vm)? .as_bigint() @@ -234,7 +235,7 @@ pub unsafe extern "C" fn PyLong_AsInt32(obj: *mut PyObject, out: *mut i32) -> c_ #[unsafe(no_mangle)] pub unsafe extern "C" fn PyLong_AsInt64(obj: *mut PyObject, out: *mut i64) -> c_int { with_vm(|vm| { - let value: i64 = unsafe { &*obj } + let value: i64 = unsafe { obj.assume_borrowed() } .to_owned() .try_index(vm)? .as_bigint() @@ -248,7 +249,7 @@ pub unsafe extern "C" fn PyLong_AsInt64(obj: *mut PyObject, out: *mut i64) -> c_ #[unsafe(no_mangle)] pub unsafe extern "C" fn PyLong_AsLongLong(obj: *mut PyObject) -> c_longlong { with_vm::, _>(|vm| { - unsafe { &*obj } + unsafe { obj.assume_borrowed() } .to_owned() .try_index(vm)? .as_bigint() @@ -260,8 +261,7 @@ pub unsafe extern "C" fn PyLong_AsLongLong(obj: *mut PyObject) -> c_longlong { #[unsafe(no_mangle)] pub unsafe extern "C" fn PyLong_AsSize_t(obj: *mut PyObject) -> usize { with_vm::, _>(|vm| { - let value: usize = unsafe { &*obj } - .try_downcast_ref::(vm)? + let value: usize = unsafe { obj.assume_borrowed_and_cast::(vm) }? .as_bigint() .try_into() .map_err(|_| vm.new_overflow_error("Python int too large to convert to C size_t"))?; @@ -272,8 +272,7 @@ pub unsafe extern "C" fn PyLong_AsSize_t(obj: *mut PyObject) -> usize { #[unsafe(no_mangle)] pub unsafe extern "C" fn PyLong_AsSsize_t(obj: *mut PyObject) -> isize { with_vm::, _>(|vm| { - unsafe { &*obj } - .try_downcast_ref::(vm)? + unsafe { obj.assume_borrowed_and_cast::(vm) }? .as_bigint() .try_into() .map_err(|_| vm.new_overflow_error("Python int too large to convert to C ssize_t")) @@ -283,7 +282,7 @@ pub unsafe extern "C" fn PyLong_AsSsize_t(obj: *mut PyObject) -> isize { #[unsafe(no_mangle)] pub unsafe extern "C" fn PyLong_AsUInt32(obj: *mut PyObject, out: *mut u32) -> c_int { with_vm(|vm| { - let value: u32 = unsafe { &*obj } + let value: u32 = unsafe { obj.assume_borrowed() } .to_owned() .try_index(vm)? .as_bigint() @@ -297,7 +296,7 @@ pub unsafe extern "C" fn PyLong_AsUInt32(obj: *mut PyObject, out: *mut u32) -> c #[unsafe(no_mangle)] pub unsafe extern "C" fn PyLong_AsUInt64(obj: *mut PyObject, out: *mut u64) -> c_int { with_vm(|vm| { - let value: u64 = unsafe { &*obj } + let value: u64 = unsafe { obj.assume_borrowed() } .to_owned() .try_index(vm)? .as_bigint() @@ -311,8 +310,7 @@ pub unsafe extern "C" fn PyLong_AsUInt64(obj: *mut PyObject, out: *mut u64) -> c #[unsafe(no_mangle)] pub unsafe extern "C" fn PyLong_AsUnsignedLong(obj: *mut PyObject) -> c_ulong { with_vm::, _>(|vm| { - unsafe { &*obj } - .try_downcast_ref::(vm)? + unsafe { obj.assume_borrowed_and_cast::(vm) }? .as_bigint() .try_into() .map_err(|_| { @@ -324,7 +322,7 @@ pub unsafe extern "C" fn PyLong_AsUnsignedLong(obj: *mut PyObject) -> c_ulong { #[unsafe(no_mangle)] pub unsafe extern "C" fn PyLong_AsUnsignedLongMask(obj: *mut PyObject) -> c_ulong { with_vm::, _>(|vm| { - let int = unsafe { &*obj }.to_owned().try_index(vm)?; + let int = unsafe { obj.assume_borrowed() }.to_owned().try_index(vm)?; if const { c_ulong::BITS == 32 } { Ok(c_ulong::from(int.as_u32_mask())) } else { @@ -336,7 +334,7 @@ pub unsafe extern "C" fn PyLong_AsUnsignedLongMask(obj: *mut PyObject) -> c_ulon #[unsafe(no_mangle)] pub unsafe extern "C" fn PyLong_AsUnsignedLongLongMask(obj: *mut PyObject) -> c_ulonglong { with_vm::, _>(|vm| { - let int = unsafe { &*obj }.to_owned().try_index(vm)?; + let int = unsafe { obj.assume_borrowed() }.to_owned().try_index(vm)?; Ok(int.as_u64_mask()) }) } @@ -344,7 +342,7 @@ pub unsafe extern "C" fn PyLong_AsUnsignedLongLongMask(obj: *mut PyObject) -> c_ #[unsafe(no_mangle)] pub unsafe extern "C" fn PyLong_AsVoidPtr(obj: *mut PyObject) -> *mut c_void { with_vm(|vm| { - let value = unsafe { &*obj }.try_downcast_ref::(vm)?; + let value = unsafe { obj.assume_borrowed_and_cast::(vm) }?; let unsigned: Result = value.as_bigint().try_into(); if let Ok(v) = unsigned { @@ -362,8 +360,7 @@ pub unsafe extern "C" fn PyLong_AsVoidPtr(obj: *mut PyObject) -> *mut c_void { #[unsafe(no_mangle)] pub unsafe extern "C" fn PyLong_AsUnsignedLongLong(obj: *mut PyObject) -> c_ulonglong { with_vm::, _>(|vm| { - unsafe { &*obj } - .try_downcast_ref::(vm)? + unsafe { obj.assume_borrowed_and_cast::(vm) }? .as_bigint() .try_into() .map_err(|_| { diff --git a/crates/capi/src/memoryobject.rs b/crates/capi/src/memoryobject.rs index 11019524e6c..3165ca59614 100644 --- a/crates/capi/src/memoryobject.rs +++ b/crates/capi/src/memoryobject.rs @@ -1,4 +1,5 @@ use crate::object::define_py_check; +use crate::util::FfiPtrExt; use crate::{PyObject, pystate::with_vm}; use rustpython_vm::PyPayload; use rustpython_vm::builtins::PyMemoryView; @@ -8,7 +9,7 @@ define_py_check!(fn PyMemoryView_Check, types.memoryview_type); #[unsafe(no_mangle)] pub unsafe extern "C" fn PyMemoryView_FromObject(obj: *mut PyObject) -> *mut PyObject { with_vm(|vm| { - let obj = unsafe { &*obj }; + let obj = unsafe { obj.assume_borrowed() }; Ok(PyMemoryView::from_object(obj, vm)?.into_ref(&vm.ctx)) }) } diff --git a/crates/capi/src/methodobject.rs b/crates/capi/src/methodobject.rs index cc3676ef51a..c9f7a484ef4 100644 --- a/crates/capi/src/methodobject.rs +++ b/crates/capi/src/methodobject.rs @@ -2,9 +2,8 @@ use crate::PyObject; use crate::object::PyTypeObject; use crate::object::define_py_check; use crate::pystate::with_vm; -use crate::util::CStrExt; +use crate::util::{CStrExt, FfiPtrExt}; use core::ffi::{c_char, c_int}; -use core::ptr::NonNull; use rustpython_vm::function::{FuncArgs, HeapMethodDef, PosArgs, PyMethodFlags}; use rustpython_vm::{AsObject, PyObjectRef, PyRef, PyResult, VirtualMachine}; @@ -72,15 +71,13 @@ pub(crate) fn build_method_def( if has_self { let callable = move |zelf: PyObjectRef, vm: &VirtualMachine| unsafe { let f = method.PyCFunction; - let ret_ptr = f(zelf.as_raw().cast_mut(), core::ptr::null_mut()); - ret_ptr_to_pyresult(vm, ret_ptr) + f(zelf.as_raw().cast_mut(), core::ptr::null_mut()).assume_owned_or_err(vm) }; Ok(vm.ctx.new_method_def(name, callable, flags, doc)) } else { let callable = move |vm: &VirtualMachine| unsafe { let f = method.PyCFunction; - let ret_ptr = f(core::ptr::null_mut(), core::ptr::null_mut()); - ret_ptr_to_pyresult(vm, ret_ptr) + f(core::ptr::null_mut(), core::ptr::null_mut()).assume_owned_or_err(vm) }; Ok(vm.ctx.new_method_def(name, callable, flags, doc)) } @@ -113,14 +110,12 @@ pub(crate) fn build_method_def( let f = unsafe { method.PyCFunction }; if has_self { let callable = move |zelf: PyObjectRef, arg: PyObjectRef, vm: &VirtualMachine| -> PyResult { - let ret_ptr = unsafe { f(zelf.as_raw().cast_mut(), arg.as_raw().cast_mut()) }; - ret_ptr_to_pyresult(vm, ret_ptr) + unsafe { f(zelf.as_raw().cast_mut(), arg.as_raw().cast_mut()).assume_owned_or_err(vm) } }; Ok(vm.ctx.new_method_def(name, callable, flags, doc)) } else { let callable = move |arg: PyObjectRef, vm: &VirtualMachine| -> PyResult { - let ret_ptr = unsafe { f(core::ptr::null_mut(), arg.as_raw().cast_mut()) }; - ret_ptr_to_pyresult(vm, ret_ptr) + unsafe { f(core::ptr::null_mut(), arg.as_raw().cast_mut()).assume_owned_or_err(vm) } }; Ok(vm.ctx.new_method_def(name, callable, flags, doc)) } @@ -158,8 +153,7 @@ unsafe fn call_function>( .map(|tuple| tuple.as_object().as_raw().cast_mut()) .unwrap_or_default(); - let ret_ptr = unsafe { f(slf_ptr, arg_ptr) }; - ret_ptr_to_pyresult(vm, ret_ptr) + unsafe { f(slf_ptr, arg_ptr).assume_owned_or_err(vm) } } unsafe fn call_function_with_keywords( @@ -179,14 +173,14 @@ unsafe fn call_function_with_keywords( for (k, v) in args.kwargs { kwargs.set_item(&*k, v, vm)?; } - let ret_ptr = unsafe { + unsafe { f( slf_ptr, arg_tuple.as_object().as_raw().cast_mut(), kwargs.as_object().as_raw().cast_mut(), ) - }; - ret_ptr_to_pyresult(vm, ret_ptr) + .assume_owned_or_err(vm) + } } unsafe fn call_fast_function_with_keywords( @@ -221,8 +215,7 @@ unsafe fn call_fast_function_with_keywords( // Vec has a layout-compatible contiguous backing buffer. The // vector is kept alive for the duration of the call. let fastcall_arg_ptrs = fastcall_args.as_ptr().cast::<*mut PyObject>(); - let ret_ptr = unsafe { f(slf_ptr, fastcall_arg_ptrs, nargs as isize, kwnames_ptr) }; - ret_ptr_to_pyresult(vm, ret_ptr) + unsafe { f(slf_ptr, fastcall_arg_ptrs, nargs as isize, kwnames_ptr).assume_owned_or_err(vm) } } unsafe fn call_fast_function( @@ -242,16 +235,7 @@ unsafe fn call_fast_function( // Vec has a layout-compatible contiguous backing buffer. The // vector is kept alive for the duration of the call. let fastcall_arg_ptrs = args.args.as_mut_ptr().cast::<*mut PyObject>(); - let ret_ptr = unsafe { f(slf_ptr, fastcall_arg_ptrs, args.args.len() as isize) }; - ret_ptr_to_pyresult(vm, ret_ptr) -} - -fn ret_ptr_to_pyresult(vm: &VirtualMachine, ret_ptr: *mut PyObject) -> PyResult { - let ret_ptr = NonNull::new(ret_ptr).ok_or_else(|| { - vm.take_raised_exception() - .expect("Native function returned NULL, but there was no exception set") - })?; - Ok(unsafe { PyObjectRef::from_raw(ret_ptr) }) + unsafe { f(slf_ptr, fastcall_arg_ptrs, args.args.len() as isize).assume_owned_or_err(vm) } } fn take_self_arg(args: &mut FuncArgs, flags: PyMethodFlags) -> Option { @@ -275,7 +259,7 @@ pub unsafe extern "C" fn PyCMethod_New( "PyCMethod_New does not support METH_METHOD on abi3" ); let ml = unsafe { &*ml }; - let zelf = unsafe { slf.as_ref().map(|obj| obj.to_owned()) }; + let zelf = unsafe { slf.assume_borrowed_or_opt() }.map(ToOwned::to_owned); Ok(build_method_def(vm, ml, zelf.is_some())? .build_function(vm, zelf) .into()) diff --git a/crates/capi/src/moduleobject.rs b/crates/capi/src/moduleobject.rs index dd753455406..d6a0b72fc80 100644 --- a/crates/capi/src/moduleobject.rs +++ b/crates/capi/src/moduleobject.rs @@ -1,6 +1,7 @@ use crate::PyObject; use crate::object::define_py_check; use crate::pystate::with_vm; +use crate::util::FfiPtrExt; use rustpython_vm::builtins::{PyModule, PyStr}; define_py_check!(fn PyModule_Check, types.module_type); @@ -9,7 +10,7 @@ define_py_check!(exact fn PyModule_CheckExact, types.module_type); #[unsafe(no_mangle)] pub unsafe extern "C" fn PyModule_GetNameObject(module: *mut PyObject) -> *mut PyObject { with_vm(|vm| { - let module = unsafe { &*module }.try_downcast_ref::(vm)?; + let module = unsafe { module.assume_borrowed_and_cast::(vm) }?; let dict = module.dict(); let name = dict .get_item_opt(rustpython_vm::identifier!(vm, __name__), vm)? @@ -21,7 +22,7 @@ pub unsafe extern "C" fn PyModule_GetNameObject(module: *mut PyObject) -> *mut P #[unsafe(no_mangle)] pub unsafe extern "C" fn PyModule_GetFilenameObject(module: *mut PyObject) -> *mut PyObject { with_vm(|vm| { - let module = unsafe { &*module }.try_downcast_ref::(vm)?; + let module = unsafe { module.assume_borrowed_and_cast::(vm) }?; let dict = module.dict(); let filename = dict .get_item_opt(rustpython_vm::identifier!(vm, __file__), vm)? @@ -33,7 +34,7 @@ pub unsafe extern "C" fn PyModule_GetFilenameObject(module: *mut PyObject) -> *m #[unsafe(no_mangle)] pub unsafe extern "C" fn PyModule_NewObject(name: *mut PyObject) -> *mut PyObject { with_vm(|vm| -> rustpython_vm::PyResult<_> { - let name = unsafe { &*name }.try_downcast_ref::(vm)?; + let name = unsafe { name.assume_borrowed_and_cast::(vm) }?; let name = name .to_str() .ok_or_else(|| vm.new_system_error("module name must be valid UTF-8"))?; diff --git a/crates/capi/src/object.rs b/crates/capi/src/object.rs index eabfbef23a1..dec4e9251e8 100644 --- a/crates/capi/src/object.rs +++ b/crates/capi/src/object.rs @@ -1,8 +1,7 @@ use crate::PyObject; use crate::pystate::with_vm; -use crate::util::CStrExt; +use crate::util::{CStrExt, FfiPtrExt}; use core::ffi::{c_char, c_int, c_uint, c_void}; -use core::ptr::NonNull; pub use pytype::*; use rustpython_vm::builtins::{PyStr, object_generic_set_dict, object_get_dict}; use rustpython_vm::bytecode::ComparisonOperator; @@ -17,10 +16,9 @@ macro_rules! define_py_check { #[unsafe(no_mangle)] pub unsafe extern "C" fn $name(obj: *mut crate::PyObject) -> core::ffi::c_int { crate::pystate::with_vm(|vm| unsafe { - obj - .as_ref() - .map(|obj| obj.class().is_subtype(vm.ctx.$($ctx_path).+)) - .unwrap_or_default() + crate::util::FfiPtrExt::assume_borrowed_or_opt(obj) + .map(|obj| obj.class().is_subtype(vm.ctx.$($ctx_path).+)) + .unwrap_or_default() }) } }; @@ -29,10 +27,9 @@ macro_rules! define_py_check { pub unsafe extern "C" fn $name(obj: *mut crate::PyObject) -> core::ffi::c_int { use rustpython_vm::AsObject; crate::pystate::with_vm(|vm| unsafe { - obj - .as_ref() - .map(|obj| obj.class().is(vm.ctx.$($ctx_path).+)) - .unwrap_or_default() + crate::util::FfiPtrExt::assume_borrowed_or_opt(obj) + .map(|obj| obj.class().is(vm.ctx.$($ctx_path).+)) + .unwrap_or_default() }) } }; @@ -69,8 +66,8 @@ pub unsafe extern "C" fn PyObject_GetAttr( name: *mut PyObject, ) -> *mut PyObject { with_vm(|vm| { - let obj = unsafe { &*obj }; - let name = unsafe { &*name }.try_downcast_ref::(vm)?; + let obj = unsafe { obj.assume_borrowed() }; + let name = unsafe { name.assume_borrowed_and_cast::(vm) }?; obj.get_attr(name, vm) }) } @@ -81,7 +78,7 @@ pub unsafe extern "C" fn PyObject_GetAttrString( attr_name: *const c_char, ) -> *mut PyObject { with_vm(|vm| { - let obj = unsafe { &*obj }; + let obj = unsafe { obj.assume_borrowed() }; let name = unsafe { attr_name.try_as_str(vm) }?; obj.get_attr(name, vm) }) @@ -89,12 +86,12 @@ pub unsafe extern "C" fn PyObject_GetAttrString( #[unsafe(no_mangle)] pub unsafe extern "C" fn PyObject_ASCII(obj: *mut PyObject) -> *mut PyObject { - with_vm(|vm| unsafe { &*obj }.ascii(vm)) + with_vm(|vm| unsafe { obj.assume_borrowed() }.ascii(vm)) } #[unsafe(no_mangle)] pub unsafe extern "C" fn PyObject_Bytes(obj: *mut PyObject) -> *mut PyObject { - with_vm(|vm| unsafe { &*obj }.to_owned().bytes(vm)) + with_vm(|vm| unsafe { obj.assume_borrowed() }.to_owned().bytes(vm)) } #[unsafe(no_mangle)] @@ -107,8 +104,8 @@ pub unsafe extern "C" fn PyObject_GetOptionalAttr( unsafe { *result = core::ptr::null_mut(); } - let obj = unsafe { &*obj }; - let name = unsafe { &*name }.try_downcast_ref::(vm)?; + let obj = unsafe { obj.assume_borrowed() }; + let name = unsafe { name.assume_borrowed_and_cast::(vm) }?; if let Some(attr) = vm.get_attribute_opt(obj.to_owned(), name)? { unsafe { *result = attr.into_raw().as_ptr(); @@ -130,7 +127,7 @@ pub unsafe extern "C" fn PyObject_GetOptionalAttrString( unsafe { *result = core::ptr::null_mut(); } - let obj = unsafe { &*obj }; + let obj = unsafe { obj.assume_borrowed() }; let name = unsafe { attr_name.try_as_str(vm) }?; if let Some(attr) = vm.get_attribute_opt(obj.to_owned(), name)? { unsafe { @@ -150,9 +147,9 @@ pub unsafe extern "C" fn PyObject_SetAttrString( value: *mut PyObject, ) -> c_int { with_vm(|vm| { - let obj = unsafe { &*obj }; + let obj = unsafe { obj.assume_borrowed() }; let name = unsafe { attr_name.try_as_str(vm) }?; - let value = unsafe { &*value }.to_owned(); + let value = unsafe { value.assume_borrowed() }.to_owned(); obj.set_attr(name, value, vm) }) } @@ -164,9 +161,9 @@ pub unsafe extern "C" fn PyObject_SetAttr( value: *mut PyObject, ) -> c_int { with_vm(|vm| { - let obj = unsafe { &*obj }; - let name = unsafe { &*name }.try_downcast_ref::(vm)?; - let value = unsafe { &*value }.to_owned(); + let obj = unsafe { obj.assume_borrowed() }; + let name = unsafe { name.assume_borrowed_and_cast::(vm) }?; + let value = unsafe { value.assume_borrowed() }.to_owned(); obj.set_attr(name, value, vm) }) } @@ -174,8 +171,8 @@ pub unsafe extern "C" fn PyObject_SetAttr( #[unsafe(no_mangle)] pub unsafe extern "C" fn PyObject_DelAttr(obj: *mut PyObject, name: *mut PyObject) -> c_int { with_vm(|vm| { - let obj = unsafe { &*obj }; - let name = unsafe { &*name }.try_downcast_ref::(vm)?; + let obj = unsafe { obj.assume_borrowed() }; + let name = unsafe { name.assume_borrowed_and_cast::(vm) }?; obj.del_attr(name, vm) }) } @@ -186,7 +183,7 @@ pub unsafe extern "C" fn PyObject_DelAttrString( attr_name: *const c_char, ) -> c_int { with_vm(|vm| { - let obj = unsafe { &*obj }; + let obj = unsafe { obj.assume_borrowed() }; let name = unsafe { attr_name.try_as_str(vm) }?; obj.del_attr(name, vm) }) @@ -199,10 +196,10 @@ pub unsafe extern "C" fn PyObject_GenericSetAttr( value: *mut PyObject, ) -> c_int { with_vm(|vm| { - let obj = unsafe { &*obj }; - let name = unsafe { &*name }.try_downcast_ref::(vm)?; - let value = match NonNull::new(value) { - Some(value) => PySetterValue::Assign(unsafe { value.as_ref() }.to_owned()), + let obj = unsafe { obj.assume_borrowed() }; + let name = unsafe { name.assume_borrowed_and_cast::(vm) }?; + let value = match unsafe { value.assume_borrowed_or_opt() } { + Some(value) => PySetterValue::Assign(value.to_owned()), None => PySetterValue::Delete, }; obj.generic_setattr(name, value, vm) @@ -215,8 +212,8 @@ pub unsafe extern "C" fn PyObject_HasAttrWithError( attr_name: *mut PyObject, ) -> c_int { with_vm(|vm| { - let obj = unsafe { &*obj }; - let name = unsafe { &*attr_name }.try_downcast_ref::(vm)?; + let obj = unsafe { obj.assume_borrowed() }; + let name = unsafe { attr_name.assume_borrowed_and_cast::(vm) }?; obj.has_attr(name, vm) }) } @@ -224,8 +221,8 @@ pub unsafe extern "C" fn PyObject_HasAttrWithError( #[unsafe(no_mangle)] pub unsafe extern "C" fn PyObject_HasAttr(obj: *mut PyObject, attr_name: *mut PyObject) -> c_int { with_vm(|vm| { - let obj = unsafe { &*obj }; - let name = match unsafe { &*attr_name }.try_downcast_ref::(vm) { + let obj = unsafe { obj.assume_borrowed() }; + let name = match unsafe { attr_name.assume_borrowed_and_cast::(vm) } { Ok(name) => name, Err(err) => { vm.run_unraisable(err, None, obj.to_owned()); @@ -249,7 +246,7 @@ pub unsafe extern "C" fn PyObject_HasAttrString( attr_name: *const c_char, ) -> c_int { with_vm(|vm| { - let obj = unsafe { &*obj }; + let obj = unsafe { obj.assume_borrowed() }; let Ok(name) = (unsafe { attr_name.try_as_str(vm) }) else { return false; }; @@ -270,7 +267,7 @@ pub unsafe extern "C" fn PyObject_HasAttrStringWithError( attr_name: *const c_char, ) -> c_int { with_vm(|vm| { - let obj = unsafe { &*obj }; + let obj = unsafe { obj.assume_borrowed() }; let name = unsafe { attr_name.try_as_str(vm) }?; obj.has_attr(name, vm) }) @@ -282,31 +279,25 @@ pub unsafe extern "C" fn PyObject_GenericGetAttr( name: *mut PyObject, ) -> *mut PyObject { with_vm(|vm| { - let obj = unsafe { &*obj }; - let name = unsafe { &*name }.try_downcast_ref::(vm)?; + let obj = unsafe { obj.assume_borrowed() }; + let name = unsafe { name.assume_borrowed_and_cast::(vm) }?; obj.generic_getattr(name, vm) }) } #[unsafe(no_mangle)] -pub extern "C" fn PyObject_Repr(obj: *mut PyObject) -> *mut PyObject { +pub unsafe extern "C" fn PyObject_Repr(obj: *mut PyObject) -> *mut PyObject { with_vm(|vm| { - let Some(obj) = NonNull::new(obj) else { - return Ok(vm.ctx.new_str("")); - }; - - unsafe { obj.as_ref() }.repr(vm) + unsafe { obj.assume_borrowed_or_opt() } + .map_or_else(|| Ok(vm.ctx.new_str("")), |obj| obj.repr(vm)) }) } #[unsafe(no_mangle)] -pub extern "C" fn PyObject_Str(obj: *mut PyObject) -> *mut PyObject { +pub unsafe extern "C" fn PyObject_Str(obj: *mut PyObject) -> *mut PyObject { with_vm(|vm| { - let Some(obj) = NonNull::new(obj) else { - return Ok(vm.ctx.new_str("")); - }; - - unsafe { obj.as_ref() }.str(vm) + unsafe { obj.assume_borrowed_or_opt() } + .map_or_else(|| Ok(vm.ctx.new_str("")), |obj| obj.str(vm)) }) } @@ -331,8 +322,8 @@ pub unsafe extern "C" fn PyObject_RichCompare( op: c_int, ) -> *mut PyObject { with_vm(|vm| { - let left = unsafe { &*left }; - let right = unsafe { &*right }; + let left = unsafe { left.assume_borrowed() }; + let right = unsafe { right.assume_borrowed() }; left.to_owned() .rich_compare(right.to_owned(), parse_richcompare_op(vm, op)?, vm) }) @@ -345,26 +336,26 @@ pub unsafe extern "C" fn PyObject_RichCompareBool( op: c_int, ) -> c_int { with_vm(|vm| { - let left = unsafe { &*left }; - let right = unsafe { &*right }; + let left = unsafe { left.assume_borrowed() }; + let right = unsafe { right.assume_borrowed() }; left.rich_compare_bool(right, parse_richcompare_op(vm, op)?, vm) }) } #[unsafe(no_mangle)] pub unsafe extern "C" fn PyCallable_Check(obj: *mut PyObject) -> c_int { - with_vm(|_vm| unsafe { obj.as_ref().is_some_and(PyObject::is_callable) }) + with_vm(|_vm| unsafe { obj.assume_borrowed_or_opt() }.is_some_and(PyObject::is_callable)) } #[unsafe(no_mangle)] pub unsafe extern "C" fn PyObject_ClearWeakRefs(obj: *mut PyObject) { - with_vm(|_vm| unsafe { &*obj }.clear_weak_refs()) + with_vm(|_vm| unsafe { obj.assume_borrowed() }.clear_weak_refs()) } #[unsafe(no_mangle)] pub unsafe extern "C" fn PyObject_Dir(obj: *mut PyObject) -> *mut PyObject { with_vm(|vm| { - unsafe { obj.as_ref() } + unsafe { obj.assume_borrowed_or_opt() } .map_or_else(|| vm.dir(None), |obj| obj.to_owned().dir(vm)) .map(|list| list.into_ref(&vm.ctx)) }) @@ -373,7 +364,7 @@ pub unsafe extern "C" fn PyObject_Dir(obj: *mut PyObject) -> *mut PyObject { #[unsafe(no_mangle)] pub unsafe extern "C" fn PyObject_IsTrue(obj: *mut PyObject) -> c_int { with_vm(|vm| { - let obj = unsafe { &*obj }; + let obj = unsafe { obj.assume_borrowed() }; obj.to_owned().is_true(vm) }) } @@ -381,7 +372,7 @@ pub unsafe extern "C" fn PyObject_IsTrue(obj: *mut PyObject) -> c_int { #[unsafe(no_mangle)] pub unsafe extern "C" fn PyObject_Not(obj: *mut PyObject) -> c_int { with_vm(|vm| { - let obj = unsafe { &*obj }; + let obj = unsafe { obj.assume_borrowed() }; obj.to_owned().not(vm) }) } @@ -389,7 +380,7 @@ pub unsafe extern "C" fn PyObject_Not(obj: *mut PyObject) -> c_int { #[unsafe(no_mangle)] pub unsafe extern "C" fn PyObject_Hash(obj: *mut PyObject) -> isize { with_vm(|vm| { - let obj = unsafe { &*obj }; + let obj = unsafe { obj.assume_borrowed() }; obj.hash(vm).map(|hash| hash as isize) }) } @@ -397,14 +388,14 @@ pub unsafe extern "C" fn PyObject_Hash(obj: *mut PyObject) -> isize { #[unsafe(no_mangle)] pub unsafe extern "C" fn PyObject_HashNotImplemented(obj: *mut PyObject) -> isize { with_vm(|vm| { - let obj = unsafe { &*obj }; + let obj = unsafe { obj.assume_borrowed() }; hash_not_implemented(obj, vm).map(|hash| hash as isize) }) } #[unsafe(no_mangle)] pub unsafe extern "C" fn PyObject_SelfIter(obj: *mut PyObject) -> *mut PyObject { - with_vm(|_vm| unsafe { (&*obj).to_owned() }) + with_vm(|_vm| unsafe { obj.assume_borrowed() }.to_owned()) } #[unsafe(no_mangle)] @@ -414,13 +405,13 @@ pub unsafe extern "C" fn Py_Is(x: *mut PyObject, y: *mut PyObject) -> c_int { #[unsafe(no_mangle)] pub unsafe extern "C" fn Py_IsNone(x: *mut PyObject) -> c_int { - with_vm(|vm| vm.is_none(unsafe { &*x })) + with_vm(|vm| vm.is_none(unsafe { x.assume_borrowed() })) } #[unsafe(no_mangle)] pub unsafe extern "C" fn Py_ReprEnter(obj: *mut PyObject) -> c_int { with_vm(|vm| { - let obj = unsafe { &*obj }; + let obj = unsafe { obj.assume_borrowed() }; let id = obj.get_id(); let mut guards = vm.repr_guards.borrow_mut(); if guards.contains(&id) { @@ -437,7 +428,7 @@ pub unsafe extern "C" fn Py_ReprLeave(obj: *mut PyObject) { with_vm(|vm| { vm.repr_guards .borrow_mut() - .remove(&unsafe { &*obj }.get_id()); + .remove(&unsafe { obj.assume_borrowed() }.get_id()); }) } @@ -447,7 +438,7 @@ pub unsafe extern "C" fn PyObject_GenericGetDict( _context: *mut c_void, ) -> *mut PyObject { with_vm(|vm| { - let obj = unsafe { &*obj }; + let obj = unsafe { obj.assume_borrowed() }; object_get_dict(obj.to_owned(), vm) }) } @@ -459,9 +450,9 @@ pub unsafe extern "C" fn PyObject_GenericSetDict( _context: *mut c_void, ) -> c_int { with_vm(|vm| { - let obj = unsafe { &*obj }; - let value = match NonNull::new(value) { - Some(value) => PySetterValue::Assign(unsafe { value.as_ref() }.to_owned()), + let obj = unsafe { obj.assume_borrowed() }; + let value = match unsafe { value.assume_borrowed_or_opt() } { + Some(value) => PySetterValue::Assign(value.to_owned()), None => PySetterValue::Delete, }; object_generic_set_dict(obj.to_owned(), value, vm) diff --git a/crates/capi/src/object/pytype.rs b/crates/capi/src/object/pytype.rs index daad7b3133b..15e83634da0 100644 --- a/crates/capi/src/object/pytype.rs +++ b/crates/capi/src/object/pytype.rs @@ -1,5 +1,6 @@ use crate::object::define_py_check; use crate::pystate::with_vm; +use crate::util::FfiPtrExt; use core::ffi::{c_int, c_ulong}; use rustpython_vm::builtins::{PyStr, PyType}; use rustpython_vm::{AsObject, Py, PyObject}; @@ -11,52 +12,52 @@ define_py_check!(exact fn PyType_CheckExact, types.type_type); #[unsafe(no_mangle)] pub unsafe extern "C" fn Py_TYPE(op: *mut PyObject) -> *const PyTypeObject { - unsafe { (*op).class() } + unsafe { op.assume_borrowed() }.class() } #[unsafe(no_mangle)] pub unsafe extern "C" fn Py_IS_TYPE(op: *mut PyObject, ty: *mut PyTypeObject) -> c_int { with_vm(|_vm| { - let obj = unsafe { &*op }; - let ty = unsafe { &*ty }; + let obj = unsafe { op.assume_borrowed() }; + let ty = unsafe { ty.assume_borrowed() }; obj.class().is(ty) }) } #[unsafe(no_mangle)] -pub unsafe extern "C" fn PyType_GetFlags(ptr: *const PyTypeObject) -> c_ulong { - let ty = unsafe { &*ptr }; +pub unsafe extern "C" fn PyType_GetFlags(ptr: *mut PyTypeObject) -> c_ulong { + let ty = unsafe { ptr.assume_borrowed() }; ty.slots.flags.bits() as u32 as c_ulong } #[unsafe(no_mangle)] -pub unsafe extern "C" fn PyType_IsSubtype(a: *const PyTypeObject, b: *const PyTypeObject) -> c_int { +pub unsafe extern "C" fn PyType_IsSubtype(a: *mut PyTypeObject, b: *mut PyTypeObject) -> c_int { with_vm(move |_vm| { - let a = unsafe { &*a }; - let b = unsafe { &*b }; + let a = unsafe { a.assume_borrowed() }; + let b = unsafe { b.assume_borrowed() }; Ok(a.is_subtype(b)) }) } #[unsafe(no_mangle)] -pub unsafe extern "C" fn PyType_GetName(ptr: *const PyTypeObject) -> *mut PyObject { - with_vm(|vm| unsafe { &*ptr }.__name__(vm)) +pub unsafe extern "C" fn PyType_GetName(ptr: *mut PyTypeObject) -> *mut PyObject { + with_vm(|vm| unsafe { ptr.assume_borrowed() }.__name__(vm)) } #[unsafe(no_mangle)] -pub unsafe extern "C" fn PyType_GetQualName(ptr: *const PyTypeObject) -> *mut PyObject { - with_vm(|vm| unsafe { &*ptr }.__qualname__(vm)) +pub unsafe extern "C" fn PyType_GetQualName(ptr: *mut PyTypeObject) -> *mut PyObject { + with_vm(|vm| unsafe { ptr.assume_borrowed() }.__qualname__(vm)) } #[unsafe(no_mangle)] -pub unsafe extern "C" fn PyType_GetModuleName(ptr: *const PyTypeObject) -> *mut PyObject { - with_vm(|vm| unsafe { &*ptr }.__module__(vm)) +pub unsafe extern "C" fn PyType_GetModuleName(ptr: *mut PyTypeObject) -> *mut PyObject { + with_vm(|vm| unsafe { ptr.assume_borrowed() }.__module__(vm)) } #[unsafe(no_mangle)] -pub unsafe extern "C" fn PyType_GetFullyQualifiedName(ptr: *const PyTypeObject) -> *mut PyObject { +pub unsafe extern "C" fn PyType_GetFullyQualifiedName(ptr: *mut PyTypeObject) -> *mut PyObject { with_vm(|vm| { - let ty = unsafe { &*ptr }; + let ty = unsafe { ptr.assume_borrowed() }; let qualname = ty.__qualname__(vm).try_downcast::(vm)?; let module = ty.__module__(vm); diff --git a/crates/capi/src/objimpl.rs b/crates/capi/src/objimpl.rs index 99b0be7cc68..241a17916f4 100644 --- a/crates/capi/src/objimpl.rs +++ b/crates/capi/src/objimpl.rs @@ -1,13 +1,14 @@ use crate::PyObject; use crate::pymem::{PyMem_Calloc, PyMem_Free, PyMem_Malloc, PyMem_Realloc}; use crate::pystate::with_vm; +use crate::util::FfiPtrExt; use core::ffi::{c_int, c_void}; use rustpython_vm::gc_state; #[unsafe(no_mangle)] pub unsafe extern "C" fn PyObject_GC_Track(op: *mut PyObject) { with_vm(|_vm| { - let obj = unsafe { &*op }; + let obj = unsafe { op.assume_borrowed() }; if !obj.is_gc_tracked() { unsafe { gc_state::gc_state().track_object(obj.into()) }; } @@ -17,7 +18,7 @@ pub unsafe extern "C" fn PyObject_GC_Track(op: *mut PyObject) { #[unsafe(no_mangle)] pub unsafe extern "C" fn PyObject_GC_UnTrack(op: *mut PyObject) { with_vm(|_vm| { - let obj = unsafe { &*op }; + let obj = unsafe { op.assume_borrowed() }; if obj.is_gc_tracked() { unsafe { gc_state::gc_state().untrack_object(obj.into()) }; } @@ -26,12 +27,12 @@ pub unsafe extern "C" fn PyObject_GC_UnTrack(op: *mut PyObject) { #[unsafe(no_mangle)] pub unsafe extern "C" fn PyObject_GC_IsTracked(op: *mut PyObject) -> c_int { - with_vm(|_vm| unsafe { (&*op).is_gc_tracked() }) + with_vm(|_vm| unsafe { op.assume_borrowed() }.is_gc_tracked()) } #[unsafe(no_mangle)] pub unsafe extern "C" fn PyObject_GC_IsFinalized(op: *mut PyObject) -> c_int { - with_vm(|_vm| unsafe { (&*op).gc_finalized() }) + with_vm(|_vm| unsafe { op.assume_borrowed() }.gc_finalized()) } #[unsafe(no_mangle)] diff --git a/crates/capi/src/osmodule.rs b/crates/capi/src/osmodule.rs index 132935ee8af..87d90971bbf 100644 --- a/crates/capi/src/osmodule.rs +++ b/crates/capi/src/osmodule.rs @@ -1,3 +1,4 @@ +use crate::util::FfiPtrExt; use crate::{PyObject, pystate::with_vm}; use rustpython_vm::convert::ToPyObject; use rustpython_vm::function::FsPath; @@ -5,7 +6,7 @@ use rustpython_vm::function::FsPath; #[unsafe(no_mangle)] pub unsafe extern "C" fn PyOS_FSPath(path: *mut PyObject) -> *mut PyObject { with_vm(|vm| { - let path = unsafe { &*path }.to_owned(); + let path = unsafe { path.assume_borrowed() }.to_owned(); let fspath = FsPath::try_from_path_like(path, false, vm)?; Ok(fspath.to_pyobject(vm)) }) diff --git a/crates/capi/src/pycapsule.rs b/crates/capi/src/pycapsule.rs index b36dea3d946..94655c4b22e 100644 --- a/crates/capi/src/pycapsule.rs +++ b/crates/capi/src/pycapsule.rs @@ -1,6 +1,6 @@ use crate::PyObject; use crate::pystate::with_vm; -use crate::util::CStrExt; +use crate::util::{CStrExt, FfiPtrExt}; use core::ffi::{CStr, c_char, c_int, c_void}; use core::ptr::NonNull; use rustpython_vm::builtins::PyCapsule; @@ -29,13 +29,13 @@ pub unsafe extern "C" fn PyCapsule_GetPointer( capsule: *mut PyObject, name: *const c_char, ) -> *mut c_void { - with_vm(|vm| Ok(checked_capsule(vm, unsafe { &*capsule }, name)?.pointer())) + with_vm(|vm| Ok(checked_capsule(vm, unsafe { capsule.assume_borrowed() }, name)?.pointer())) } #[unsafe(no_mangle)] pub unsafe extern "C" fn PyCapsule_GetName(capsule: *mut PyObject) -> *const c_char { with_vm(|vm| { - let capsule = unsafe { &*capsule } + let capsule = unsafe { capsule.assume_borrowed() } .downcast_ref_if_exact::(vm) .ok_or_else(|| vm.new_value_error("Invalid capsule"))?; Ok(capsule.name().map(CStr::as_ptr).unwrap_or_default()) @@ -45,7 +45,7 @@ pub unsafe extern "C" fn PyCapsule_GetName(capsule: *mut PyObject) -> *const c_c #[unsafe(no_mangle)] pub unsafe extern "C" fn PyCapsule_GetContext(capsule: *mut PyObject) -> *mut c_void { with_vm(|vm| { - let capsule = unsafe { &*capsule } + let capsule = unsafe { capsule.assume_borrowed() } .downcast_ref_if_exact::(vm) .ok_or_else(|| vm.new_value_error("Invalid capsule"))?; Ok(capsule.context()) @@ -58,7 +58,7 @@ pub unsafe extern "C" fn PyCapsule_SetContext( context: *mut c_void, ) -> c_int { with_vm(|vm| { - let capsule = unsafe { &*capsule } + let capsule = unsafe { capsule.assume_borrowed() } .downcast_ref_if_exact::(vm) .ok_or_else(|| vm.new_value_error("Invalid capsule"))?; let _: () = capsule.set_context(context); @@ -72,7 +72,7 @@ pub unsafe extern "C" fn PyCapsule_SetPointer( pointer: *mut c_void, ) -> c_int { with_vm(|vm| { - let capsule = unsafe { &*capsule } + let capsule = unsafe { capsule.assume_borrowed() } .downcast_ref_if_exact::(vm) .ok_or_else(|| vm.new_value_error("Invalid capsule"))?; let _: () = capsule.set_pointer(pointer); @@ -87,7 +87,7 @@ pub unsafe extern "C" fn PyCapsule_IsValid(capsule: *mut PyObject, name: *const return false; } - checked_capsule(vm, unsafe { &*capsule }, name).is_ok() + checked_capsule(vm, unsafe { capsule.assume_borrowed() }, name).is_ok() }) } diff --git a/crates/capi/src/pyerrors.rs b/crates/capi/src/pyerrors.rs index 55428ee7604..20ed511699a 100644 --- a/crates/capi/src/pyerrors.rs +++ b/crates/capi/src/pyerrors.rs @@ -1,14 +1,13 @@ use crate::object::define_py_check; -use crate::util::CStrExt; +use crate::util::{CStrExt, FfiPtrExt}; use crate::{PyObject, pystate::with_vm}; use core::convert::Infallible; use core::ffi::{c_char, c_int}; -use core::ptr::NonNull; use core::slice; use rustpython_vm::builtins::{PyBaseException, PyTuple, PyType}; use rustpython_vm::convert::IntoObject; use rustpython_vm::exceptions::ExceptionZoo; -use rustpython_vm::{AsObject, PyObjectRef, PyResult}; +use rustpython_vm::{AsObject, PyResult}; macro_rules! define_exception_statics { ($( $(#[$meta:meta])* $export:ident => $exc:ident ),* $(,)?) => { @@ -121,20 +120,17 @@ pub extern "C" fn PyErr_GetRaisedException() -> *mut PyObject { #[unsafe(no_mangle)] pub unsafe extern "C" fn PyErr_SetRaisedException(exc: *mut PyObject) { with_vm(|vm| { - if let Some(exc) = NonNull::new(exc) { - let exception = unsafe { PyObjectRef::from_raw(exc).downcast_unchecked() }; - vm.set_exception(Some(exception)); - } else { - vm.set_exception(None); - } + let exception = + unsafe { exc.assume_owned_or_opt() }.map(|exc| unsafe { exc.downcast_unchecked() }); + vm.set_exception(exception); }) } #[unsafe(no_mangle)] pub unsafe extern "C" fn PyErr_SetObject(exception: *mut PyObject, value: *mut PyObject) { with_vm::, _>(|vm| { - let exc_type = unsafe { (&*exception).to_owned() }; - let exc_val = unsafe { (&*value).to_owned() }; + let exc_type = unsafe { exception.assume_borrowed() }.to_owned(); + let exc_val = unsafe { value.assume_borrowed() }.to_owned(); let normalized = vm.normalize_exception(exc_type, exc_val, vm.ctx.none())?; Err(normalized) @@ -144,7 +140,7 @@ pub unsafe extern "C" fn PyErr_SetObject(exception: *mut PyObject, value: *mut P #[unsafe(no_mangle)] pub unsafe extern "C" fn PyErr_SetString(exception: *mut PyObject, message: *const c_char) { with_vm::, _>(|vm| { - let exc_type = unsafe { &*exception }.try_downcast_ref::(vm)?; + let exc_type = unsafe { exception.assume_borrowed_and_cast::(vm) }?; let message = unsafe { message.try_as_str(vm) }?; let exc = vm.invoke_exception( @@ -170,7 +166,7 @@ pub extern "C" fn PyErr_PrintEx(_set_sys_last_vars: c_int) { #[unsafe(no_mangle)] pub unsafe extern "C" fn PyErr_DisplayException(exc: *mut PyObject) { with_vm(|vm| { - let exception = unsafe { &*exc } + let exception = unsafe { exc.assume_borrowed() } .downcast_ref::() .expect("PyErr_DisplayException exc must be an exception instance") .to_owned(); @@ -186,7 +182,8 @@ pub unsafe extern "C" fn PyErr_WriteUnraisable(obj: *mut PyObject) { .take_raised_exception() .expect("No exception set in PyErr_WriteUnraisable"); - let object = unsafe { vm.unwrap_or_none(obj.as_ref().map(|obj| obj.to_owned())) }; + let object = + unsafe { vm.unwrap_or_none(obj.assume_borrowed_or_opt().map(ToOwned::to_owned)) }; vm.run_unraisable(exception, None, object) }) @@ -195,7 +192,7 @@ pub unsafe extern "C" fn PyErr_WriteUnraisable(obj: *mut PyObject) { #[unsafe(no_mangle)] pub unsafe extern "C" fn PyExceptionClass_Check(obj: *mut PyObject) -> c_int { with_vm(|vm| unsafe { - obj.as_ref() + obj.assume_borrowed_or_opt() .and_then(|obj| obj.downcast_ref::()) .is_some_and(|ty| ty.is_subtype(vm.ctx.exceptions.base_exception_type)) }) @@ -213,7 +210,7 @@ pub unsafe extern "C" fn PyErr_NewException( .rsplit_once('.') .expect("Exception name must be of the form 'module.ExceptionName'"); - let bases = unsafe { base.as_ref() }.map(|bases| { + let bases = unsafe { base.assume_borrowed_or_opt() }.map(|bases| { if let Some(ty) = bases.downcast_ref::() { vec![ty.to_owned()] } else if let Some(tuple) = bases.downcast_ref::() { @@ -252,8 +249,8 @@ pub unsafe extern "C" fn PyErr_GivenExceptionMatches( exc: *mut PyObject, ) -> c_int { with_vm(|vm| { - let given = unsafe { &*given }; - let exc = unsafe { &*exc }; + let given = unsafe { given.assume_borrowed() }; + let exc = unsafe { exc.assume_borrowed() }; given.is_subclass(exc, vm) }) @@ -262,7 +259,7 @@ pub unsafe extern "C" fn PyErr_GivenExceptionMatches( #[unsafe(no_mangle)] pub unsafe extern "C" fn PyException_GetTraceback(exc: *mut PyObject) -> *mut PyObject { with_vm(|vm| { - let exc = unsafe { &*exc }.try_downcast_ref::(vm)?; + let exc = unsafe { exc.assume_borrowed_and_cast::(vm) }?; let tb = exc .__traceback__() .map(|tb| tb.into_object().into_raw().as_ptr()) @@ -274,7 +271,7 @@ pub unsafe extern "C" fn PyException_GetTraceback(exc: *mut PyObject) -> *mut Py #[unsafe(no_mangle)] pub unsafe extern "C" fn PyException_GetCause(exc: *mut PyObject) -> *mut PyObject { with_vm(|vm| { - let exc = unsafe { &*exc }.try_downcast_ref::(vm)?; + let exc = unsafe { exc.assume_borrowed_and_cast::(vm) }?; let cause = exc .__cause__() .map(|cause| cause.into_object().into_raw().as_ptr()) @@ -286,7 +283,7 @@ pub unsafe extern "C" fn PyException_GetCause(exc: *mut PyObject) -> *mut PyObje #[unsafe(no_mangle)] pub unsafe extern "C" fn PyException_GetContext(exc: *mut PyObject) -> *mut PyObject { with_vm(|vm| { - let exc = unsafe { &*exc }.try_downcast_ref::(vm)?; + let exc = unsafe { exc.assume_borrowed_and_cast::(vm) }?; let context = exc .__context__() .map(|context| context.into_object().into_raw().as_ptr()) @@ -298,9 +295,9 @@ pub unsafe extern "C" fn PyException_GetContext(exc: *mut PyObject) -> *mut PyOb #[unsafe(no_mangle)] pub unsafe extern "C" fn PyException_SetCause(exc: *mut PyObject, cause: *mut PyObject) { with_vm(|vm| { - let exc = unsafe { &*exc }.try_downcast_ref::(vm)?; - let cause = NonNull::new(cause) - .map(|obj| unsafe { PyObjectRef::from_raw(obj).downcast_unchecked() }); + let exc = unsafe { exc.assume_borrowed_and_cast::(vm) }?; + let cause = + unsafe { cause.assume_owned_or_opt() }.map(|obj| unsafe { obj.downcast_unchecked() }); exc.set___cause__(cause); Ok(()) }) @@ -309,9 +306,9 @@ pub unsafe extern "C" fn PyException_SetCause(exc: *mut PyObject, cause: *mut Py #[unsafe(no_mangle)] pub unsafe extern "C" fn PyException_SetContext(exc: *mut PyObject, context: *mut PyObject) { with_vm(|vm| { - let exc = unsafe { &*exc }.try_downcast_ref::(vm)?; - let context = NonNull::new(context) - .map(|obj| unsafe { PyObjectRef::from_raw(obj).downcast_unchecked() }); + let exc = unsafe { exc.assume_borrowed_and_cast::(vm) }?; + let context = + unsafe { context.assume_owned_or_opt() }.map(|obj| unsafe { obj.downcast_unchecked() }); exc.set___context__(context); Ok(()) }) @@ -364,8 +361,8 @@ pub unsafe extern "C" fn PyUnicodeDecodeError_Create( #[unsafe(no_mangle)] pub unsafe extern "C" fn PyException_SetTraceback(exc: *mut PyObject, tb: *mut PyObject) -> c_int { with_vm(|vm| { - let exc = unsafe { &*exc }.try_downcast_ref::(vm)?; - let traceback = unsafe { tb.as_ref() }.map(|obj| obj.to_owned()); + let exc = unsafe { exc.assume_borrowed_and_cast::(vm) }?; + let traceback = unsafe { tb.assume_borrowed_or_opt() }.map(ToOwned::to_owned); exc.set___traceback__(vm.unwrap_or_none(traceback), vm) }) } diff --git a/crates/capi/src/pyframe.rs b/crates/capi/src/pyframe.rs index 5c9ad371708..1c9101c4880 100644 --- a/crates/capi/src/pyframe.rs +++ b/crates/capi/src/pyframe.rs @@ -1,4 +1,5 @@ use crate::pystate::with_vm; +use crate::util::FfiPtrExt; use core::ffi::c_int; use rustpython_vm::Py; use rustpython_vm::builtins::PyCode; @@ -9,13 +10,13 @@ pub type PyCodeObject = Py; #[unsafe(no_mangle)] pub unsafe extern "C" fn PyFrame_GetCode(frame: *mut PyFrameObject) -> *mut PyCodeObject { - with_vm(|_vm| Ok(unsafe { &*frame }.f_code())) + with_vm(|_vm| Ok(unsafe { frame.assume_borrowed() }.f_code())) } #[unsafe(no_mangle)] pub unsafe extern "C" fn PyFrame_GetLineNumber(frame: *mut PyFrameObject) -> c_int { with_vm(|_vm| { - let lineno = unsafe { &*frame }.f_lineno(); + let lineno = unsafe { frame.assume_borrowed() }.f_lineno(); Ok(lineno.try_into().unwrap_or(c_int::MAX)) }) } diff --git a/crates/capi/src/refcount.rs b/crates/capi/src/refcount.rs index 48c7132b0f1..ba42baf6e0a 100644 --- a/crates/capi/src/refcount.rs +++ b/crates/capi/src/refcount.rs @@ -1,27 +1,26 @@ +use crate::util::FfiPtrExt; use crate::{PyObject, pystate::with_vm}; -use core::ptr::NonNull; -use rustpython_vm::PyObjectRef; #[unsafe(no_mangle)] pub unsafe extern "C" fn _Py_DecRef(op: *mut PyObject) { // By dropping PyObjectRef, we will decrement the reference count. - unsafe { drop(PyObjectRef::from_raw(NonNull::new_unchecked(op))) }; + unsafe { drop(op.assume_owned()) }; } #[unsafe(no_mangle)] pub unsafe extern "C" fn _Py_IncRef(op: *mut PyObject) { // Don't drop the owned value, as we just want to increment the refcount. - core::mem::forget(unsafe { (*op).to_owned() }); + core::mem::forget(unsafe { op.assume_borrowed() }.to_owned()); } #[unsafe(no_mangle)] pub unsafe extern "C" fn Py_NewRef(op: *mut PyObject) -> *mut PyObject { - with_vm(|_vm| unsafe { (*op).to_owned() }) + with_vm(|_vm| unsafe { op.assume_borrowed() }.to_owned()) } #[unsafe(no_mangle)] pub unsafe extern "C" fn Py_REFCNT(op: *mut PyObject) -> isize { - with_vm(|_vm| unsafe { &*op }.strong_count()) + with_vm(|_vm| unsafe { op.assume_borrowed() }.strong_count()) } #[cfg(test)] diff --git a/crates/capi/src/setobject.rs b/crates/capi/src/setobject.rs index 1036bb1473a..0ebb58b8442 100644 --- a/crates/capi/src/setobject.rs +++ b/crates/capi/src/setobject.rs @@ -1,6 +1,7 @@ use crate::PyObject; use crate::object::define_py_check; use crate::pystate::with_vm; +use crate::util::FfiPtrExt; use core::ffi::c_int; use itertools::process_results; use rustpython_vm::AsObject; @@ -19,7 +20,8 @@ pub unsafe extern "C" fn PySet_New(iterable: *mut PyObject) -> *mut PyObject { return Ok(PySet::default().into_ref(&vm.ctx)); } - let iterable = ArgIterable::try_from_object(vm, unsafe { &*iterable }.to_owned())?; + let iterable = + ArgIterable::try_from_object(vm, unsafe { iterable.assume_borrowed() }.to_owned())?; let set = PySet::default().into_ref(&vm.ctx); for item in iterable.iter(vm)? { set.add(item?, vm)?; @@ -35,7 +37,8 @@ pub unsafe extern "C" fn PyFrozenSet_New(iterable: *mut PyObject) -> *mut PyObje return Ok(vm.ctx.empty_frozenset.to_owned()); } - let iterable = ArgIterable::try_from_object(vm, unsafe { &*iterable }.to_owned())?; + let iterable = + ArgIterable::try_from_object(vm, unsafe { iterable.assume_borrowed() }.to_owned())?; let set = process_results(iterable.iter(vm)?, |it| PyFrozenSet::from_iter(vm, it))??; Ok(set.into_ref(&vm.ctx)) }) @@ -44,8 +47,8 @@ pub unsafe extern "C" fn PyFrozenSet_New(iterable: *mut PyObject) -> *mut PyObje #[unsafe(no_mangle)] pub unsafe extern "C" fn PySet_Add(set: *mut PyObject, key: *mut PyObject) -> c_int { with_vm(|vm| { - let set = unsafe { &*set }.try_downcast_ref::(vm)?; - let key = unsafe { &*key }.to_owned(); + let set = unsafe { set.assume_borrowed_and_cast::(vm) }?; + let key = unsafe { key.assume_borrowed() }.to_owned(); set.add(key, vm) }) } @@ -53,7 +56,7 @@ pub unsafe extern "C" fn PySet_Add(set: *mut PyObject, key: *mut PyObject) -> c_ #[unsafe(no_mangle)] pub unsafe extern "C" fn PySet_Clear(set: *mut PyObject) -> c_int { with_vm(|vm| { - let set = unsafe { &*set }.try_downcast_ref::(vm)?; + let set = unsafe { set.assume_borrowed_and_cast::(vm) }?; set.clear(); Ok(()) }) @@ -62,8 +65,8 @@ pub unsafe extern "C" fn PySet_Clear(set: *mut PyObject) -> c_int { #[unsafe(no_mangle)] pub unsafe extern "C" fn PySet_Contains(anyset: *mut PyObject, key: *mut PyObject) -> c_int { with_vm(|vm| { - let anyset = unsafe { &*anyset }; - let key = unsafe { &*key }; + let anyset = unsafe { anyset.assume_borrowed() }; + let key = unsafe { key.assume_borrowed() }; if let Some(set) = anyset.downcast_ref::() { set.__contains__(key, vm) @@ -81,8 +84,8 @@ pub unsafe extern "C" fn PySet_Contains(anyset: *mut PyObject, key: *mut PyObjec #[unsafe(no_mangle)] pub unsafe extern "C" fn PySet_Discard(set: *mut PyObject, key: *mut PyObject) -> c_int { with_vm(|vm| { - let set = unsafe { &*set }.try_downcast_ref::(vm)?; - let key = unsafe { &*key }; + let set = unsafe { set.assume_borrowed_and_cast::(vm) }?; + let key = unsafe { key.assume_borrowed() }; let had_item = set.__contains__(key, vm)?; if had_item { set.discard(key.to_owned(), vm)?; @@ -94,7 +97,7 @@ pub unsafe extern "C" fn PySet_Discard(set: *mut PyObject, key: *mut PyObject) - #[unsafe(no_mangle)] pub unsafe extern "C" fn PySet_Pop(set: *mut PyObject) -> *mut PyObject { with_vm(|vm| { - let set = unsafe { &*set }.try_downcast_ref::(vm)?; + let set = unsafe { set.assume_borrowed_and_cast::(vm) }?; set.pop(vm) }) } @@ -102,7 +105,7 @@ pub unsafe extern "C" fn PySet_Pop(set: *mut PyObject) -> *mut PyObject { #[unsafe(no_mangle)] pub unsafe extern "C" fn PySet_Size(anyset: *mut PyObject) -> isize { with_vm(|vm| { - let anyset = unsafe { &*anyset }; + let anyset = unsafe { anyset.assume_borrowed() }; if let Some(set) = anyset.downcast_ref::() { set.as_object().length(vm) } else if let Some(frozenset) = anyset.downcast_ref::() { diff --git a/crates/capi/src/sliceobject.rs b/crates/capi/src/sliceobject.rs index fb588181531..9778d4909d2 100644 --- a/crates/capi/src/sliceobject.rs +++ b/crates/capi/src/sliceobject.rs @@ -1,5 +1,6 @@ use crate::PyObject; use crate::pystate::with_vm; +use crate::util::FfiPtrExt; use core::ffi::c_int; use rustpython_vm::PyPayload; use rustpython_vm::builtins::PySlice; @@ -12,21 +13,10 @@ pub unsafe extern "C" fn PySlice_New( step: *mut PyObject, ) -> *mut PyObject { with_vm(|vm| { - let start = if start.is_null() { - None - } else { - Some(unsafe { &*start }.to_owned()) - }; - let stop = if stop.is_null() { - vm.ctx.none() - } else { - unsafe { &*stop }.to_owned() - }; - let step = if step.is_null() { - None - } else { - Some(unsafe { &*step }.to_owned()) - }; + let start = unsafe { start.assume_borrowed_or_opt() }.map(ToOwned::to_owned); + let stop = unsafe { stop.assume_borrowed_or_opt() } + .map_or_else(|| vm.ctx.none(), ToOwned::to_owned); + let step = unsafe { step.assume_borrowed_or_opt() }.map(ToOwned::to_owned); Ok(PySlice { start, stop, step }.into_ref(&vm.ctx)) }) } @@ -39,7 +29,7 @@ pub unsafe extern "C" fn PySlice_Unpack( step: *mut isize, ) -> c_int { with_vm(|vm| { - let slice = unsafe { &*slice }.try_downcast_ref::(vm)?; + let slice = unsafe { slice.assume_borrowed_and_cast::(vm) }?; let saturated = slice.to_saturated(vm)?; unsafe { *start = saturated.start(); diff --git a/crates/capi/src/traceback.rs b/crates/capi/src/traceback.rs index 8728ba5fab5..a33a469edb8 100644 --- a/crates/capi/src/traceback.rs +++ b/crates/capi/src/traceback.rs @@ -1,6 +1,7 @@ use crate::PyObject; use crate::object::define_py_check; use crate::pystate::with_vm; +use crate::util::FfiPtrExt; use core::ffi::c_int; use rustpython_vm::function::{FuncArgs, KwArgs}; @@ -9,8 +10,8 @@ define_py_check!(exact fn PyTraceBack_Check, types.traceback_type); #[unsafe(no_mangle)] pub unsafe extern "C" fn PyTraceBack_Print(tb: *mut PyObject, file: *mut PyObject) -> c_int { with_vm(|vm| { - let tb = unsafe { &*tb }; - let file = unsafe { &*file }; + let tb = unsafe { tb.assume_borrowed() }; + let file = unsafe { file.assume_borrowed() }; let tb_module = vm.import("traceback", 0)?; let print_tb = tb_module.get_attr("print_tb", vm)?; diff --git a/crates/capi/src/tupleobject.rs b/crates/capi/src/tupleobject.rs index 60c4b81b370..d3f72939d8c 100644 --- a/crates/capi/src/tupleobject.rs +++ b/crates/capi/src/tupleobject.rs @@ -1,6 +1,7 @@ use crate::PyObject; use crate::object::define_py_check; use crate::pystate::with_vm; +use crate::util::FfiPtrExt; use core::ffi::c_int; use core::slice; use rustpython_vm::PyResult; @@ -55,7 +56,7 @@ pub extern "C" fn PyTuple_SetItem( #[unsafe(no_mangle)] pub unsafe extern "C" fn PyTuple_Size(tuple: *mut PyObject) -> isize { with_vm(|vm| { - let tuple = unsafe { &*tuple }.try_downcast_ref::(vm)?; + let tuple = unsafe { tuple.assume_borrowed_and_cast::(vm) }?; Ok(tuple.__len__()) }) } @@ -63,7 +64,7 @@ pub unsafe extern "C" fn PyTuple_Size(tuple: *mut PyObject) -> isize { #[unsafe(no_mangle)] pub unsafe extern "C" fn PyTuple_GetItem(tuple: *mut PyObject, pos: isize) -> *mut PyObject { with_vm(|vm| { - let tuple = unsafe { &*tuple }.try_downcast_ref::(vm)?; + let tuple = unsafe { tuple.assume_borrowed_and_cast::(vm) }?; let result: &PyObject = pos .try_into() .ok() @@ -81,7 +82,7 @@ pub unsafe extern "C" fn PyTuple_GetSlice( high: isize, ) -> *mut PyObject { with_vm(|vm| { - let tuple = unsafe { &*tuple }.try_downcast_ref::(vm)?; + let tuple = unsafe { tuple.assume_borrowed_and_cast::(vm) }?; let len = tuple.__len__() as isize; let low = low.clamp(0, len); let high = high.clamp(low, len); diff --git a/crates/capi/src/unicodeobject.rs b/crates/capi/src/unicodeobject.rs index 1a5e43c0e9d..1907aa60dab 100644 --- a/crates/capi/src/unicodeobject.rs +++ b/crates/capi/src/unicodeobject.rs @@ -1,8 +1,7 @@ use crate::object::define_py_check; -use crate::util::CStrExt; +use crate::util::{CStrExt, FfiPtrExt}; use crate::{PyObject, pystate::with_vm}; use core::ffi::{CStr, c_char, c_int}; -use core::ptr::NonNull; use core::slice; use core::str; use rustpython_vm::builtins::{PyStr, PyStrRef}; @@ -43,7 +42,7 @@ pub unsafe extern "C" fn PyUnicode_AsUTF8AndSize( size: *mut isize, ) -> *const c_char { with_vm(|vm| { - let unicode = unsafe { &*obj }.try_downcast_ref::(vm)?; + let unicode = unsafe { obj.assume_borrowed_and_cast::(vm) }?; let str = unicode.to_str().ok_or_else(|| { vm.new_system_error("PyUnicode_AsUTF8AndSize only supports UTF-8 or ASCII strings") @@ -68,9 +67,7 @@ pub unsafe extern "C" fn PyUnicode_AsEncodedString( errors: *const c_char, ) -> *mut PyObject { with_vm(|vm| { - let unicode = unsafe { &*unicode } - .try_downcast_ref::(vm)? - .to_owned(); + let unicode = unsafe { unicode.assume_borrowed_and_cast::(vm) }?.to_owned(); let encoding = unsafe { encoding.try_as_str_opt(vm) }?.unwrap_or("utf-8"); let errors = unsafe { errors.try_as_str_opt(vm) }?.map(|errors| vm.ctx.new_utf8_str(errors)); @@ -83,9 +80,7 @@ pub unsafe extern "C" fn PyUnicode_AsEncodedString( #[unsafe(no_mangle)] pub unsafe extern "C" fn PyUnicode_AsUTF8String(unicode: *mut PyObject) -> *mut PyObject { with_vm(|vm| { - let unicode = unsafe { &*unicode } - .try_downcast_ref::(vm)? - .to_owned(); + let unicode = unsafe { unicode.assume_borrowed_and_cast::(vm) }?.to_owned(); vm.state .codec_registry .encode_text(unicode, "utf-8", None, vm) @@ -141,9 +136,7 @@ pub(crate) fn decode_fsdefault_and_size( #[unsafe(no_mangle)] pub unsafe extern "C" fn PyUnicode_EncodeFSDefault(unicode: *mut PyObject) -> *mut PyObject { with_vm(|vm| { - let unicode = unsafe { &*unicode } - .try_downcast_ref::(vm)? - .to_owned(); + let unicode = unsafe { unicode.assume_borrowed_and_cast::(vm) }?.to_owned(); vm.state.codec_registry.encode_text( unicode, vm.fs_encoding().as_str(), @@ -160,7 +153,7 @@ pub unsafe extern "C" fn PyUnicode_FromEncodedObject( errors: *const c_char, ) -> *mut PyObject { with_vm(|vm| { - let obj = unsafe { &*obj }; + let obj = unsafe { obj.assume_borrowed() }; if obj.downcast_ref::().is_some() { return Err(vm.new_type_error("decoding str is not supported")); @@ -184,7 +177,7 @@ pub unsafe extern "C" fn PyUnicode_FromEncodedObject( #[unsafe(no_mangle)] pub unsafe extern "C" fn PyUnicode_InternInPlace(string: *mut *mut PyObject) { with_vm(|vm| { - let old_str = unsafe { PyObjectRef::from_raw(NonNull::new_unchecked(*string)) } + let old_str = unsafe { (*string).assume_owned() } .downcast_exact::(vm) .expect("PyUnicode_InternInPlace called with non-string object"); @@ -205,7 +198,7 @@ pub unsafe extern "C" fn PyUnicode_EqualToUTF8AndSize( vm.new_system_error("Negative size passed to PyUnicode_EqualToUTF8AndSize") })?; - let unicode = unsafe { &*unicode }.try_downcast_ref::(vm)?; + let unicode = unsafe { unicode.assume_borrowed_and_cast::(vm) }?; let result = unsafe { let slice = slice::from_raw_parts(string as _, size); str::from_utf8(slice) diff --git a/crates/capi/src/util.rs b/crates/capi/src/util.rs index 32ff775676b..2f6f7d62e69 100644 --- a/crates/capi/src/util.rs +++ b/crates/capi/src/util.rs @@ -2,7 +2,7 @@ use crate::PyObject; use core::convert::Infallible; use core::ffi::{CStr, c_char, c_double, c_int, c_long, c_ulong, c_void}; use core::ptr::NonNull; -use rustpython_vm::{Py, PyObjectRef, PyRef, PyResult, VirtualMachine}; +use rustpython_vm::{Py, PyObjectRef, PyPayload, PyRef, PyResult, VirtualMachine}; pub(crate) trait FfiResult { const ERR_VALUE: Output; @@ -228,6 +228,96 @@ pub(crate) trait CStrExt<'a> { unsafe fn try_as_str_opt(self, vm: &VirtualMachine) -> PyResult>; } +pub(crate) trait FfiPtrExt: Sized { + type Owned; + type Borrowed; + + unsafe fn assume_owned_or_opt(self) -> Option; + unsafe fn assume_owned_or_err(self, vm: &VirtualMachine) -> PyResult { + unsafe { self.assume_owned_or_opt() }.ok_or_else(|| { + vm.take_raised_exception().unwrap_or_else(|| { + vm.new_system_error("Native function returned NULL, but there was no exception set") + }) + }) + } + unsafe fn assume_owned(self) -> Self::Owned; + unsafe fn assume_borrowed_or_opt<'a>(self) -> Option<&'a Self::Borrowed>; + unsafe fn assume_borrowed<'a>(self) -> &'a Self::Borrowed; + + unsafe fn assume_borrowed_and_cast<'a, T: PyPayload>( + self, + vm: &VirtualMachine, + ) -> PyResult<&'a Py>; +} + +impl FfiPtrExt for *mut PyObject { + type Owned = PyObjectRef; + type Borrowed = PyObject; + + #[inline] + unsafe fn assume_owned_or_opt(self) -> Option { + NonNull::new(self).map(|ptr| unsafe { PyObjectRef::from_raw(ptr) }) + } + + #[inline] + unsafe fn assume_owned(self) -> PyObjectRef { + unsafe { PyObjectRef::from_raw(NonNull::new_unchecked(self)) } + } + + #[inline] + unsafe fn assume_borrowed_or_opt<'a>(self) -> Option<&'a PyObject> { + unsafe { self.as_ref() } + } + + #[inline] + unsafe fn assume_borrowed<'a>(self) -> &'a PyObject { + debug_assert!(!self.is_null()); + unsafe { self.as_ref_unchecked() } + } + + #[inline] + unsafe fn assume_borrowed_and_cast<'a, T: PyPayload>( + self, + vm: &VirtualMachine, + ) -> PyResult<&'a Py> { + unsafe { self.assume_borrowed() }.try_downcast_ref(vm) + } +} + +impl FfiPtrExt for *mut Py { + type Owned = PyRef; + type Borrowed = Py; + + #[inline] + unsafe fn assume_owned_or_opt(self) -> Option> { + NonNull::new(self).map(|ptr| unsafe { PyRef::from_non_null(ptr) }) + } + + #[inline] + unsafe fn assume_owned(self) -> PyRef { + unsafe { PyRef::from_raw(self.cast_const()) } + } + + #[inline] + unsafe fn assume_borrowed_or_opt<'a>(self) -> Option<&'a Py> { + unsafe { self.as_ref() } + } + + #[inline] + unsafe fn assume_borrowed<'a>(self) -> &'a Py { + debug_assert!(!self.is_null()); + unsafe { self.as_ref_unchecked() } + } + + #[inline] + unsafe fn assume_borrowed_and_cast<'a, U: PyPayload>( + self, + vm: &VirtualMachine, + ) -> PyResult<&'a Py> { + unsafe { self.cast::().assume_borrowed_and_cast(vm) } + } +} + impl<'a> CStrExt<'a> for *mut c_char { unsafe fn try_as_str(self, vm: &VirtualMachine) -> PyResult<&'a str> { unsafe { self.try_as_str_opt(vm) }? diff --git a/crates/capi/src/warnings.rs b/crates/capi/src/warnings.rs index f9ed82b9fa9..9ec0906befa 100644 --- a/crates/capi/src/warnings.rs +++ b/crates/capi/src/warnings.rs @@ -1,4 +1,4 @@ -use crate::util::CStrExt; +use crate::util::{CStrExt, FfiPtrExt}; use crate::{PyObject, pystate::with_vm}; use core::ffi::{c_char, c_int}; use rustpython_vm::builtins::{PyType, PyTypeRef}; @@ -13,9 +13,7 @@ fn resolve_warning_category( return Ok(vm.ctx.exceptions.runtime_warning.to_owned()); }; - let category = unsafe { &*category } - .try_downcast_ref::(vm)? - .to_owned(); + let category = unsafe { category.assume_borrowed_and_cast::(vm) }?.to_owned(); if !category.fast_issubclass(vm.ctx.exceptions.warning) { return Err(vm.new_type_error(format!( "category must be a Warning subclass, not '{}'", @@ -65,7 +63,7 @@ pub unsafe extern "C" fn PyErr_WarnExplicit( let category = resolve_warning_category(vm, category)?; - let registry = unsafe { registry.as_ref() } + let registry = unsafe { registry.assume_borrowed_or_opt() } .map_or_else(|| vm.ctx.none(), |registry| registry.to_owned()); let lineno = usize::try_from(lineno) diff --git a/crates/capi/src/weakrefobject.rs b/crates/capi/src/weakrefobject.rs index de095e5e594..0df4fac18f8 100644 --- a/crates/capi/src/weakrefobject.rs +++ b/crates/capi/src/weakrefobject.rs @@ -1,6 +1,7 @@ use crate::PyObject; use crate::object::define_py_check; use crate::pystate::with_vm; +use crate::util::FfiPtrExt; use core::ffi::c_int; use rustpython_vm::builtins::{PyWeak, PyWeakProxy}; @@ -17,7 +18,7 @@ pub unsafe extern "C" fn PyWeakref_GetRef( *result = core::ptr::null_mut(); } - let reference = unsafe { &*reference }; + let reference = unsafe { reference.assume_borrowed() }; let upgraded = if let Some(weak) = reference.downcast_ref::() { weak.upgrade() } else if let Some(proxy) = reference.downcast_ref::() { @@ -43,8 +44,8 @@ pub unsafe extern "C" fn PyWeakref_NewProxy( callback: *mut PyObject, ) -> *mut PyObject { with_vm(|vm| { - let ob = unsafe { &*ob }; - let callback = unsafe { callback.as_ref() } + let ob = unsafe { ob.assume_borrowed() }; + let callback = unsafe { callback.assume_borrowed_or_opt() } .filter(|callback| !vm.is_none(callback)) .map(ToOwned::to_owned); PyWeakProxy::new_weakproxy(ob, callback, vm) @@ -57,8 +58,8 @@ pub unsafe extern "C" fn PyWeakref_NewRef( callback: *mut PyObject, ) -> *mut PyObject { with_vm(|vm| { - let ob = unsafe { &*ob }; - let callback = unsafe { callback.as_ref() } + let ob = unsafe { ob.assume_borrowed() }; + let callback = unsafe { callback.assume_borrowed_or_opt() } .filter(|callback| !vm.is_none(callback)) .map(ToOwned::to_owned); ob.downgrade(callback, vm) diff --git a/crates/vm/src/object/core.rs b/crates/vm/src/object/core.rs index 9fa236b87ff..d41fa0b2450 100644 --- a/crates/vm/src/object/core.rs +++ b/crates/vm/src/object/core.rs @@ -2266,15 +2266,18 @@ impl PyRef { // ptr // } + /// # Safety + /// The raw pointer must point to a valid `Py` object + #[must_use] #[inline(always)] - pub(crate) const unsafe fn from_non_null(ptr: NonNull>) -> Self { + pub const unsafe fn from_non_null(ptr: NonNull>) -> Self { Self { ptr } } /// # Safety /// The raw pointer must point to a valid `Py` object #[inline(always)] - pub(crate) const unsafe fn from_raw(raw: *const Py) -> Self { + pub const unsafe fn from_raw(raw: *const Py) -> Self { unsafe { Self::from_non_null(NonNull::new_unchecked(raw as *mut _)) } } From c88dc322c1ad426a03f53363e4601e515dbf6bf5 Mon Sep 17 00:00:00 2001 From: Bas Schoenmaeckers Date: Thu, 16 Jul 2026 17:11:32 +0200 Subject: [PATCH 4/4] Panic on NULL ptrs --- crates/capi/src/util.rs | 43 +++++++++++++++++++++++++++++++++++++++-- 1 file changed, 41 insertions(+), 2 deletions(-) diff --git a/crates/capi/src/util.rs b/crates/capi/src/util.rs index 2f6f7d62e69..51393f80440 100644 --- a/crates/capi/src/util.rs +++ b/crates/capi/src/util.rs @@ -3,6 +3,7 @@ use core::convert::Infallible; use core::ffi::{CStr, c_char, c_double, c_int, c_long, c_ulong, c_void}; use core::ptr::NonNull; use rustpython_vm::{Py, PyObjectRef, PyPayload, PyRef, PyResult, VirtualMachine}; +use std::any::type_name; pub(crate) trait FfiResult { const ERR_VALUE: Output; @@ -260,7 +261,13 @@ impl FfiPtrExt for *mut PyObject { } #[inline] + #[track_caller] unsafe fn assume_owned(self) -> PyObjectRef { + debug_assert!( + !self.is_null(), + "Attempted to dereference NULL {}", + type_name::() + ); unsafe { PyObjectRef::from_raw(NonNull::new_unchecked(self)) } } @@ -270,12 +277,18 @@ impl FfiPtrExt for *mut PyObject { } #[inline] + #[track_caller] unsafe fn assume_borrowed<'a>(self) -> &'a PyObject { - debug_assert!(!self.is_null()); + debug_assert!( + !self.is_null(), + "Attempted to dereference NULL {}", + type_name::() + ); unsafe { self.as_ref_unchecked() } } #[inline] + #[track_caller] unsafe fn assume_borrowed_and_cast<'a, T: PyPayload>( self, vm: &VirtualMachine, @@ -294,7 +307,13 @@ impl FfiPtrExt for *mut Py { } #[inline] + #[track_caller] unsafe fn assume_owned(self) -> PyRef { + debug_assert!( + !self.is_null(), + "Attempted to dereference NULL {}", + type_name::() + ); unsafe { PyRef::from_raw(self.cast_const()) } } @@ -304,12 +323,18 @@ impl FfiPtrExt for *mut Py { } #[inline] + #[track_caller] unsafe fn assume_borrowed<'a>(self) -> &'a Py { - debug_assert!(!self.is_null()); + debug_assert!( + !self.is_null(), + "Attempted to dereference NULL {}", + type_name::() + ); unsafe { self.as_ref_unchecked() } } #[inline] + #[track_caller] unsafe fn assume_borrowed_and_cast<'a, U: PyPayload>( self, vm: &VirtualMachine, @@ -376,4 +401,18 @@ mod tests { assert_error_value::, _>(-1); assert_error_value::, _>(usize::MAX); } + + #[test] + #[should_panic = "Attempted to dereference NULL"] + fn break_ptr_api_contract_owned() { + let ptr: *mut PyObject = core::ptr::null_mut(); + let _ = unsafe { ptr.assume_owned() }; + } + + #[test] + #[should_panic = "Attempted to dereference NULL"] + fn break_ptr_api_contract_borrowed() { + let ptr: *mut PyObject = core::ptr::null_mut(); + let _ = unsafe { ptr.assume_borrowed() }; + } }