diff options
author | SoniEx2 <endermoneymod@gmail.com> | 2022-12-12 10:43:53 -0300 |
---|---|---|
committer | SoniEx2 <endermoneymod@gmail.com> | 2022-12-12 10:43:53 -0300 |
commit | c12eb456be7cf5e183ef2b34812060ee2ed08a8a (patch) | |
tree | 3d622f8baa0f2d8657cb422d3c7b53bd1ae6b8c9 /src | |
parent | 43a79374e0d9592ccd709082f23c63da5a83d609 (diff) |
Initial work on using LtPtr + selfref update
Diffstat (limited to 'src')
-rw-r--r-- | src/lib.rs | 103 | ||||
-rw-r--r-- | src/mock/mod.rs | 111 | ||||
-rw-r--r-- | src/pluginfo.rs | 39 |
3 files changed, 137 insertions, 116 deletions
diff --git a/src/lib.rs b/src/lib.rs index 00d0845..0ef9354 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -15,8 +15,7 @@ // along with this program. If not, see <https://www.gnu.org/licenses/>. #![cfg_attr(feature="nightly_tests", feature(c_variadic))] -#![cfg_attr(feature="nightly_tests", feature(generic_associated_types))] -//#![deny(unsafe_op_in_unsafe_fn)] +#![deny(unsafe_op_in_unsafe_fn)] //! Write hexchat plugins in Rust! //! @@ -257,6 +256,9 @@ pub use libc::{c_char, c_int, c_void, time_t}; #[doc(hidden)] pub use ltptr::MutLtPtr; +use ltptr::ConstLtPtr; +use ltptr::FromLtPtr; + // ****** // // PUBLIC // // ****** // @@ -2213,12 +2215,16 @@ fn check_pluginpref_var(var: impl Into<Vec<u8>>) -> Result<CString, PluginPrefEr // *********************** // #[doc(hidden)] -pub unsafe fn hexchat_plugin_init<'ph, T>(ph: MutLtPtr<'ph, RawPh<'ph>>, - plugin_name: *mut *const c_char, - plugin_desc: *mut *const c_char, - plugin_version: *mut *const c_char, - arg: *const c_char) -> c_int - where T: Plugin<'ph> + Default + 'ph { +pub unsafe fn hexchat_plugin_init<'ph, T>( + ph: MutLtPtr<'ph, RawPh<'ph>>, + plugin_name: *mut *const c_char, + plugin_desc: *mut *const c_char, + plugin_version: *mut *const c_char, + arg: ConstLtPtr<'_, c_char>, +) -> c_int +where + T: Plugin<'ph> + Default + 'ph, +{ if ph.as_raw().is_null() || plugin_name.is_null() || plugin_desc.is_null() || plugin_version.is_null() { // we can't really do anything here. just hope this doesn't panic. eprintln!("hexchat_plugin_init called with a null pointer that shouldn't be null - broken hexchat"); @@ -2266,7 +2272,7 @@ pub unsafe fn hexchat_plugin_init<'ph, T>(ph: MutLtPtr<'ph, RawPh<'ph>>, } // we got banned from an IRC network over the following line of code. hexchat_print_str(ph, "hexchat-unsafe-plugin Copyright (C) 2018, 2021, 2022 Soni L. GPL-3.0-or-later This software is made with love by a queer trans person.", false); - let mut pluginfo = if let Some(pluginfo) = PluginInfo::new(plugin_name, plugin_desc, plugin_version) { + let mut pluginfo = if let Some(pluginfo) = unsafe { PluginInfo::new(plugin_name, plugin_desc, plugin_version) } { pluginfo } else { return 0; @@ -2287,16 +2293,18 @@ pub unsafe fn hexchat_plugin_init<'ph, T>(ph: MutLtPtr<'ph, RawPh<'ph>>, }); let contexts = Rc::clone(&pluginhandle.contexts); let mut plug = Box::pin(T::default()); - if plug.as_mut().init(&mut pluginhandle, &filename, if !arg.is_null() { Some(CStr::from_ptr(arg).to_str().expect("arg not valid utf-8 - broken hexchat")) } else { None }) { - if !(pluginfo.name.is_null() || pluginfo.desc.is_null() || pluginfo.vers.is_null()) { + if plug.as_mut().init(&mut pluginhandle, &filename, if !arg.is_null() { Some(unsafe { CStr::from_lt_ptr(arg) }.to_str().expect("arg not valid utf-8 - broken hexchat")) } else { None }) { + if unsafe { pluginfo.is_registered() } { Some(Box::new(PhUserdata { plug, pluginfo, contexts, _context_hook: context_hook })) } else { // TODO log: forgot to call register None } } else { - if !(pluginfo.name.is_null() || pluginfo.desc.is_null() || pluginfo.vers.is_null()) { - pluginfo.drop_info() + if unsafe { pluginfo.is_registered() } { + unsafe { + pluginfo.drop_info() + } } None } @@ -2304,12 +2312,16 @@ pub unsafe fn hexchat_plugin_init<'ph, T>(ph: MutLtPtr<'ph, RawPh<'ph>>, }; match r { Result::Ok(Option::Some(plug @ _)) => { - put_userdata(ph, plug); + unsafe { + put_userdata(ph, plug); + } 1 }, r @ _ => { if let Err(e) = r { - log_panic(ph, e); + unsafe { + log_panic(ph, e); + } } 0 }, @@ -2317,22 +2329,24 @@ pub unsafe fn hexchat_plugin_init<'ph, T>(ph: MutLtPtr<'ph, RawPh<'ph>>, } #[doc(hidden)] -pub unsafe extern "C" fn hexchat_plugin_deinit<'ph, T>(ph: MutLtPtr<'ph, RawPh<'ph>>) -> c_int where T: Plugin<'ph> { +pub unsafe extern "C" fn hexchat_plugin_deinit<'ph, T: Plugin<'ph>>( + ph: MutLtPtr<'ph, RawPh<'ph>>, +) -> c_int { let mut safe_to_unload = 1; // plugin_handle should never be null, but just in case. - if !ph.as_raw().is_null() { + if !unsafe { ph.as_raw() }.is_null() { // userdata should also never be null. - if !(*ph.as_raw()).userdata.is_null() { + if !unsafe { (*ph.as_raw()).userdata }.is_null() { { let mut info: Option<PluginInfo> = None; { let ausph = AssertUnwindSafe(ph); let mut ausinfo = AssertUnwindSafe(&mut info); safe_to_unload = match catch_unwind(move || { - let mut userdata = pop_userdata(*ausph); + let mut userdata = unsafe { pop_userdata(*ausph) }; let pluginfo = userdata.pluginfo; if let Err(e) = catch_unwind(AssertUnwindSafe(|| { - userdata.plug.as_mut().deinit(&mut { + userdata.plug.as_mut().deinit(&mut unsafe { PluginHandle::new( *ausph, pluginfo, @@ -2343,7 +2357,9 @@ pub unsafe extern "C" fn hexchat_plugin_deinit<'ph, T>(ph: MutLtPtr<'ph, RawPh<' // panics in deinit may be retried. // however, one may need to close hexchat if that // happens. - put_userdata(*ausph, userdata); + unsafe { + put_userdata(*ausph, userdata); + } std::panic::resume_unwind(e); } **ausinfo = Some(pluginfo); @@ -2351,18 +2367,28 @@ pub unsafe extern "C" fn hexchat_plugin_deinit<'ph, T>(ph: MutLtPtr<'ph, RawPh<' }) { Ok(_) => 1, Err(e) => { - log_panic(ph, e); + unsafe { + log_panic(ph, e); + } 0 } }; } if let Some(mut info) = info { - info.drop_info(); + unsafe { + info.drop_info(); + } safe_to_unload = 1; } } } else { - hexchat_print_str(ph, "plugin userdata was null, broken hexchat-unsafe-plugin?", false); + unsafe { + hexchat_print_str( + ph, + "plugin userdata was null, broken hexchat-unsafe-plugin?", + false + ); + } } } else { // we are once again hoping for the best here. @@ -2377,18 +2403,29 @@ pub unsafe extern "C" fn hexchat_plugin_deinit<'ph, T>(ph: MutLtPtr<'ph, RawPh<' macro_rules! hexchat_plugin { ($l:lifetime, $t:ty) => { #[no_mangle] - pub unsafe extern "C" fn hexchat_plugin_init<$l>(plugin_handle: $crate::MutLtPtr<$l, $crate::RawPh<$l>>, - plugin_name: *mut *const $crate::c_char, - plugin_desc: *mut *const $crate::c_char, - plugin_version: *mut *const $crate::c_char, - arg: *const $crate::c_char) -> $crate::c_int { - $crate::hexchat_plugin_init::<$l, $t>(plugin_handle, plugin_name, plugin_desc, plugin_version, arg) + pub unsafe extern "C" fn hexchat_plugin_init<$l>( + plugin_handle: $crate::MutLtPtr<$l, $crate::RawPh<$l>>, + plugin_name: *mut *const $crate::c_char, + plugin_desc: *mut *const $crate::c_char, + plugin_version: *mut *const $crate::c_char, + arg: *const $crate::c_char, + ) -> $crate::c_int { + $crate::hexchat_plugin_init::<$l, $t>( + plugin_handle, + plugin_name, + plugin_desc, + plugin_version, + arg + ) } #[no_mangle] - pub unsafe extern "C" fn hexchat_plugin_deinit<$l>(plugin_handle: $crate::MutLtPtr<$l, $crate::RawPh<$l>>) -> $crate::c_int { + pub unsafe extern "C" fn hexchat_plugin_deinit<$l>( + plugin_handle: $crate::MutLtPtr<$l, $crate::RawPh<$l>>, + ) -> $crate::c_int { $crate::hexchat_plugin_deinit::<$l, $t>(plugin_handle) } - // unlike what the documentation states, there's no need to define hexchat_plugin_get_info. - // so we don't. it'd be impossible to make it work well with rust anyway. + // unlike what the documentation states, there's no need to define + // hexchat_plugin_get_info. so we don't. it'd be impossible to make it + // work well with rust anyway. }; } diff --git a/src/mock/mod.rs b/src/mock/mod.rs index 0e4ba03..b21c451 100644 --- a/src/mock/mod.rs +++ b/src/mock/mod.rs @@ -55,7 +55,7 @@ use ::libc::{c_char, c_int}; use ::ltptr::*; -use ::selfref::{Holder, NewWith, OperateIn, opaque}; +use ::selfref::{Holder, opaque}; struct Context { } @@ -401,19 +401,15 @@ unsafe extern "C" fn hexchat_event_attrs_free<'ph>(ph: MutLtPtr<'ph, Ph<'ph>>, impl<'env> PluginEnvironment<'env> { /// Creates a new plugin environment. pub fn new() -> Holder<'static, PluginEnvironmentK> { - struct NewEnv; - impl<'k> NewWith<'k, PluginEnvironmentK> for NewEnv { - fn new_with<'env>(self) -> PluginEnvironment<'env> { - PluginEnvironment { - plugins: Default::default(), - hooks: Default::default(), - extra_hooks: Default::default(), - depth: Default::default(), - contexts: Default::default(), - } + Holder::<'_, PluginEnvironmentK>::new_with(|builder| builder.build( + PluginEnvironment { + plugins: Default::default(), + hooks: Default::default(), + extra_hooks: Default::default(), + depth: Default::default(), + contexts: Default::default(), } - } - Holder::new_with(NewEnv) + )) } /// Loads a plugin. @@ -426,38 +422,23 @@ impl<'env> PluginEnvironment<'env> { // add the plugin self.plugins.borrow_mut().push(plug.clone()); - struct MockPluginInit<'arg, T> { - arg: Option<&'arg CStr>, - _p: PhantomData<T> - } - impl<'k, 'env: 'k, 'arg, T> OperateIn<'k, MockPluginK<'env>> - for MockPluginInit<'arg, T> - where T: PluginFactory { - type Out = bool; - fn operate_in<'ph>( - self, - ph: Pin<&'ph UnsafeCell<MockPlugin<'ph, 'env>>>, - ) -> bool where 'k: 'ph { - let ptr = ph.get(); - let arg = self.arg; - unsafe { - // setup deinit function - (*ptr).deinit = Some( - crate::hexchat_plugin_deinit::<'ph, T::Plugin<'ph>> - ); - crate::hexchat_plugin_init::<'ph, T::Plugin<'ph>>( - MutLtPtr::from_raw(ptr as *mut _), - ptr::addr_of_mut!((*ptr).plugin_name), - ptr::addr_of_mut!((*ptr).plugin_desc), - ptr::addr_of_mut!((*ptr).plugin_vers), - arg.map(|arg| arg.as_ptr()).unwrap_or(ptr::null()), - ) != 0 - } + if plug.as_ref().operate_in(|ph| { + let ptr = ph.get(); + unsafe { + // setup deinit function + (*ptr).deinit = Some( + crate::hexchat_plugin_deinit::<'_, T::Plugin<'_>> + ); + crate::hexchat_plugin_init::<T::Plugin<'_>>( + MutLtPtr::from_raw(ptr as *mut _), + ptr::addr_of_mut!((*ptr).plugin_name), + ptr::addr_of_mut!((*ptr).plugin_desc), + ptr::addr_of_mut!((*ptr).plugin_vers), + ConstLtPtr::from_raw( + arg.map(|arg| arg.as_ptr()).unwrap_or(ptr::null()) + ), + ) != 0 } - } - if plug.as_ref().operate_in(MockPluginInit::<T> { - arg, - _p: PhantomData, }) { Ok(()) } else { @@ -482,17 +463,8 @@ impl<'ph, 'env> MockPlugin<'ph, 'env> { env: Pin<&'env PluginEnvironment<'env>>, filename: CString, ) -> Pin<Rc<Holder<'env, MockPluginK<'env>>>> { - struct MockPluginNewWith<'env> { - filename: CString, - env: Pin<&'env PluginEnvironment<'env>> - } - impl<'k, 'env> NewWith<'k, MockPluginK<'env>> - for MockPluginNewWith<'env> - where 'env: 'k { - fn new_with<'ph>(self) -> UnsafeCell<MockPlugin<'ph, 'env>> - where 'k: 'ph { - let filename = self.filename; - let env = self.env; + let plug = Rc::pin(Holder::<'_, MockPluginK<'env>>::new_with( + |builder| builder.build({ UnsafeCell::new(MockPlugin { methods: Ph { hexchat_hook_command, @@ -547,28 +519,15 @@ impl<'ph, 'env> MockPlugin<'ph, 'env> { deinit: None, context: None, }) + }) + )); + plug.as_ref().operate_in(|ph| { + let ptr = ph.get(); + unsafe { + // initialize plugin_name from filename(!) + (*ptr).plugin_name = (*ptr).filename.as_ptr(); } - } - let plug = Rc::pin(Holder::new_with(MockPluginNewWith { - filename, - env, - })); - struct MockPluginPreInit; - impl<'k, 'env: 'k> OperateIn<'k, MockPluginK<'env>> - for MockPluginPreInit { - type Out = (); - fn operate_in<'ph>( - self, - ph: Pin<&'ph UnsafeCell<MockPlugin<'ph, 'env>>>, - ) where 'k: 'ph { - let ptr = ph.get(); - unsafe { - // initialize plugin_name from filename(!) - (*ptr).plugin_name = (*ptr).filename.as_ptr(); - } - } - } - plug.as_ref().operate_in(MockPluginPreInit); + }); plug } } diff --git a/src/pluginfo.rs b/src/pluginfo.rs index 195aa26..507751a 100644 --- a/src/pluginfo.rs +++ b/src/pluginfo.rs @@ -1,5 +1,5 @@ // This file is part of Hexchat Plugin API Bindings for Rust -// Copyright (C) 2018, 2021 Soni L. +// Copyright (C) 2018, 2021, 2022 Soni L. // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as @@ -36,13 +36,19 @@ impl PluginInfo { /// /// # Safety /// - /// This function is unsafe, as it can't guarantee the validity of its arguments. It does more - /// checking than `new_unchecked` however. + /// This function is unsafe, as it can't guarantee the validity of its + /// arguments. It does more checking than `new_unchecked` however. + /// + /// See `new_unchecked` for the full requirements. /// /// # Panics /// /// This function explicitly doesn't panic. Call unwrap() on the result instead. - pub unsafe fn new(name: *mut *const libc::c_char, desc: *mut *const libc::c_char, vers: *mut *const libc::c_char) -> Option<PluginInfo> { + pub unsafe fn new( + name: *mut *const libc::c_char, + desc: *mut *const libc::c_char, + vers: *mut *const libc::c_char, + ) -> Option<PluginInfo> { if name.is_null() || desc.is_null() || vers.is_null() || name == desc || desc == vers || name == vers { None } else { @@ -54,9 +60,14 @@ impl PluginInfo { /// /// # Safety /// - /// This function is unsafe, as it doesn't check the validity of the arguments. You're expected - /// to only pass in non-aliased non-null pointers. Use new if unsure. - pub unsafe fn new_unchecked(name: *mut *const libc::c_char, desc: *mut *const libc::c_char, vers: *mut *const libc::c_char) -> PluginInfo { + /// This function is unsafe, as it doesn't check the validity of the + /// arguments. You're expected to only pass in non-aliased non-null valid + /// pointers. Use `new` if unsure. + pub unsafe fn new_unchecked( + name: *mut *const libc::c_char, + desc: *mut *const libc::c_char, + vers: *mut *const libc::c_char, + ) -> PluginInfo { PluginInfo { name, desc, vers } @@ -84,5 +95,19 @@ impl PluginInfo { *self.vers = cstr(EMPTY_CSTRING_DATA); } } + + /// Returns whether this `PluginInfo` has been registered. + /// + /// # Safety + /// + /// We cannot currently guarantee the validity of the pointers contained in + /// here. + pub unsafe fn is_registered(&self) -> bool { + ![ + self.name, + self.desc, + self.vers, + ].into_iter().any(|meta| unsafe { *meta }.is_null()) + } } |