diff --git a/crates/bevy_dynamic_plugin/src/loader.rs b/crates/bevy_dynamic_plugin/src/loader.rs index 948d6dc9784e3..80c0ac9526d59 100644 --- a/crates/bevy_dynamic_plugin/src/loader.rs +++ b/crates/bevy_dynamic_plugin/src/loader.rs @@ -21,19 +21,29 @@ pub enum DynamicPluginLoadError { /// The specified plugin must be linked against the exact same libbevy.so as this program. /// In addition the `_bevy_create_plugin` symbol must not be manually created, but instead created /// by deriving `DynamicPlugin` on a unit struct implementing [`Plugin`]. +/// +/// Dynamically loading plugins is orchestrated through dynamic linking. When linking against foreign +/// code, initialization routines may be run (as well as termination routines when the program exits). +/// The caller of this function is responsible for ensuring these routines are sound. For more +/// information, please see the safety section of [`libloading::Library::new`]. pub unsafe fn dynamically_load_plugin>( path: P, ) -> Result<(Library, Box), DynamicPluginLoadError> { - // TODO: Safety comment for `Library::new`, `Library::get`, and `Box::from_raw`. - unsafe { - let lib = Library::new(path).map_err(DynamicPluginLoadError::Library)?; - let func: Symbol = lib - .get(b"_bevy_create_plugin") - .map_err(DynamicPluginLoadError::Plugin)?; - let plugin = Box::from_raw(func()); - - Ok((lib, plugin)) - } + // SAFETY: Caller must follow the safety requirements of Library::new. + let lib = unsafe { Library::new(path).map_err(DynamicPluginLoadError::Library)? }; + + // SAFETY: Loaded plugins are not allowed to specify `_bevy_create_plugin` symbol manually, but must + // instead automatically generate it through `DynamicPlugin`. + let func: Symbol = unsafe { + lib.get(b"_bevy_create_plugin") + .map_err(DynamicPluginLoadError::Plugin)? + }; + + // SAFETY: `func` is automatically generated and is guaranteed to return a pointer created using + // `Box::into_raw`. + let plugin = unsafe { Box::from_raw(func()) }; + + Ok((lib, plugin)) } pub trait DynamicPluginExt {