From e20834fbeb0f32304902678ad3b0a975cdc25914 Mon Sep 17 00:00:00 2001 From: William Venner Date: Mon, 3 Jan 2022 01:10:35 +0000 Subject: [PATCH] Make error handling for loading shared libraries not silently discard errors --- Cargo.lock | 2 +- gmod/Cargo.toml | 2 +- gmod/src/gmcl.rs | 2 +- gmod/src/lib.rs | 119 ++++++++++++++++++++++++++++++----------- gmod/src/lua/import.rs | 22 ++++---- 5 files changed, 101 insertions(+), 46 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 60b9621..76e8a76 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -135,7 +135,7 @@ dependencies = [ [[package]] name = "gmod" -version = "10.2.2" +version = "11.0.0" dependencies = [ "cfg_table 1.0.0", "cstr", diff --git a/gmod/Cargo.toml b/gmod/Cargo.toml index d5dd99d..f067a6a 100644 --- a/gmod/Cargo.toml +++ b/gmod/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "gmod" -version = "10.2.2" +version = "11.0.0" authors = ["William Venner "] edition = "2018" license = "MIT" diff --git a/gmod/src/gmcl.rs b/gmod/src/gmcl.rs index 3752fe6..a015fd4 100644 --- a/gmod/src/gmcl.rs +++ b/gmod/src/gmcl.rs @@ -80,5 +80,5 @@ pub fn restore_stdout() { let _ = join_handle.join(); } - std::io::set_output_capture(None); + std::io::set_output_capture(None); // TODO fix side effect } \ No newline at end of file diff --git a/gmod/src/lib.rs b/gmod/src/lib.rs index d72182b..a6807ef 100644 --- a/gmod/src/lib.rs +++ b/gmod/src/lib.rs @@ -98,7 +98,10 @@ pub fn is_x86_64() -> bool { #[macro_export] macro_rules! open_library_raw { ($($path:literal),+) => { - $crate::libloading::Library::new(concat!($($path),+)).map(|lib| (lib, concat!($($path),+))) + match $crate::libloading::Library::new(concat!($($path),+)) { + Ok(lib) => Ok((lib, concat!($($path),+))), + Err(err) => Err((err, concat!($($path),+))) + } } } @@ -119,28 +122,36 @@ macro_rules! open_library_srv { } #[cfg(all(target_os = "windows", target_pointer_width = "64"))] { - $crate::open_library_raw!("bin/win64/", $name, ".dll") + $crate::__private__gmod_rs__try_chained_open! { + $crate::open_library_raw!("bin/win64/", $name, ".dll") + } } #[cfg(all(target_os = "windows", target_pointer_width = "32"))] { - $crate::open_library_raw!("bin/", $name, ".dll") - .or_else(|_| $crate::open_library_raw!("garrysmod/bin/", $name, ".dll")) + $crate::__private__gmod_rs__try_chained_open! { + $crate::open_library_raw!("bin/", $name, ".dll"), + $crate::open_library_raw!("garrysmod/bin/", $name, ".dll") + } } #[cfg(all(target_os = "linux", target_pointer_width = "64"))] { - $crate::open_library_raw!("bin/linux64/", $name, ".so") - .or_else(|_| $crate::open_library_raw!("bin/linux64/lib", $name, ".so")) + $crate::__private__gmod_rs__try_chained_open! { + $crate::open_library_raw!("bin/linux64/", $name, ".so"), + $crate::open_library_raw!("bin/linux64/lib", $name, ".so") + } } #[cfg(all(target_os = "linux", target_pointer_width = "32"))] { - $crate::open_library_raw!("bin/linux32/", $name, ".so") - .or_else(|_| $crate::open_library_raw!("bin/linux32/lib", $name, ".so")) - .or_else(|_| $crate::open_library_raw!("bin/", $name, "_srv.so")) - .or_else(|_| $crate::open_library_raw!("bin/lib", $name, "_srv.so")) - .or_else(|_| $crate::open_library_raw!("garrysmod/bin/", $name, "_srv.so")) - .or_else(|_| $crate::open_library_raw!("garrysmod/bin/lib", $name, "_srv.so")) - .or_else(|_| $crate::open_library_raw!("bin/", $name, ".so")) - .or_else(|_| $crate::open_library_raw!("bin/lib", $name, ".so")) - .or_else(|_| $crate::open_library_raw!("garrysmod/bin/", $name, ".so")) - .or_else(|_| $crate::open_library_raw!("garrysmod/bin/lib", $name, ".so")) + $crate::__private__gmod_rs__try_chained_open! { + $crate::open_library_raw!("bin/linux32/", $name, ".so"), + $crate::open_library_raw!("bin/linux32/lib", $name, ".so"), + $crate::open_library_raw!("bin/", $name, "_srv.so"), + $crate::open_library_raw!("bin/lib", $name, "_srv.so"), + $crate::open_library_raw!("garrysmod/bin/", $name, "_srv.so"), + $crate::open_library_raw!("garrysmod/bin/lib", $name, "_srv.so"), + $crate::open_library_raw!("bin/", $name, ".so"), + $crate::open_library_raw!("bin/lib", $name, ".so"), + $crate::open_library_raw!("garrysmod/bin/", $name, ".so"), + $crate::open_library_raw!("garrysmod/bin/lib", $name, ".so"), + } } }}; } @@ -162,28 +173,74 @@ macro_rules! open_library { } #[cfg(all(target_os = "windows", target_pointer_width = "64"))] { - $crate::open_library_raw!("bin/win64/", $name, ".dll") + $crate::__private__gmod_rs__try_chained_open! { + $crate::open_library_raw!("bin/win64/", $name, ".dll") + } } #[cfg(all(target_os = "windows", target_pointer_width = "32"))] { - $crate::open_library_raw!("bin/", $name, ".dll") - .or_else(|_| $crate::open_library_raw!("garrysmod/bin/", $name, ".dll")) + $crate::__private__gmod_rs__try_chained_open! { + $crate::open_library_raw!("bin/", $name, ".dll"), + $crate::open_library_raw!("garrysmod/bin/", $name, ".dll"), + } } #[cfg(all(target_os = "linux", target_pointer_width = "64"))] { - $crate::open_library_raw!("bin/linux64/", $name, ".so") - .or_else(|_| $crate::open_library_raw!("bin/linux64/lib", $name, ".so")) + $crate::__private__gmod_rs__try_chained_open! { + $crate::open_library_raw!("bin/linux64/", $name, ".so"), + $crate::open_library_raw!("bin/linux64/lib", $name, ".so"), + } } #[cfg(all(target_os = "linux", target_pointer_width = "32"))] { - $crate::open_library_raw!("bin/linux32/", $name, ".so") - .or_else(|_| $crate::open_library_raw!("bin/linux32/lib", $name, ".so")) - .or_else(|_| $crate::open_library_raw!("bin/", $name, ".so")) - .or_else(|_| $crate::open_library_raw!("bin/lib", $name, ".so")) - .or_else(|_| $crate::open_library_raw!("garrysmod/bin/", $name, ".so")) - .or_else(|_| $crate::open_library_raw!("garrysmod/bin/lib", $name, ".so")) - .or_else(|_| $crate::open_library_raw!("bin/", $name, "_srv.so")) - .or_else(|_| $crate::open_library_raw!("bin/lib", $name, "_srv.so")) - .or_else(|_| $crate::open_library_raw!("garrysmod/bin/", $name, "_srv.so")) - .or_else(|_| $crate::open_library_raw!("garrysmod/bin/lib", $name, "_srv.so")) + $crate::__private__gmod_rs__try_chained_open! { + $crate::open_library_raw!("bin/linux32/", $name, ".so"), + $crate::open_library_raw!("bin/linux32/lib", $name, ".so"), + $crate::open_library_raw!("bin/", $name, ".so"), + $crate::open_library_raw!("bin/lib", $name, ".so"), + $crate::open_library_raw!("garrysmod/bin/", $name, ".so"), + $crate::open_library_raw!("garrysmod/bin/lib", $name, ".so"), + $crate::open_library_raw!("bin/", $name, "_srv.so"), + $crate::open_library_raw!("bin/lib", $name, "_srv.so"), + $crate::open_library_raw!("garrysmod/bin/", $name, "_srv.so"), + $crate::open_library_raw!("garrysmod/bin/lib", $name, "_srv.so"), + } } }}; +} + +#[derive(Default)] +#[doc(hidden)] +pub struct OpenGmodLibraryErrs(pub std::collections::HashMap<&'static str, libloading::Error>); +impl std::error::Error for OpenGmodLibraryErrs {} +impl std::fmt::Display for OpenGmodLibraryErrs { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + writeln!(f, "")?; + for (path, err) in &self.0 { + writeln!(f, "{} = {}", path, err)?; + } + writeln!(f, "")?; + Ok(()) + } +} +impl std::fmt::Debug for OpenGmodLibraryErrs { + #[inline] + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + std::fmt::Display::fmt(self, f) + } +} + +#[doc(hidden)] +#[macro_export] +macro_rules! __private__gmod_rs__try_chained_open { + {$($expr:expr),+} => { + loop { + let mut errors = $crate::OpenGmodLibraryErrs::default(); + $( + match $expr { + Ok(val) => break Ok(val), + Err((err, path)) => { errors.0.insert(path, err); } + } + )+ + break Err(errors); + } + }; } \ No newline at end of file diff --git a/gmod/src/lua/import.rs b/gmod/src/lua/import.rs index 315a756..b30a24b 100644 --- a/gmod/src/lua/import.rs +++ b/gmod/src/lua/import.rs @@ -5,12 +5,6 @@ use std::{cell::UnsafeCell, ffi::c_void}; use libloading::{Library, Symbol}; -macro_rules! find_library { - ($path:literal) => { - Library::new($path).map(|lib| (lib, $path)) - }; -} - use super::{LuaError, State as LuaState, LuaDebug}; pub type LuaInt = isize; @@ -250,27 +244,31 @@ impl LuaShared { #[cfg(all(target_os = "windows", target_pointer_width = "64"))] pub unsafe fn find_lua_shared() -> (Library, &'static str) { - find_library!("bin/win64/lua_shared.dll") + crate::open_library_raw!("bin/win64/lua_shared.dll") .expect("Failed to load lua_shared.dll") } #[cfg(all(target_os = "windows", target_pointer_width = "32"))] pub unsafe fn find_lua_shared() -> (Library, &'static str) { - find_library!("garrysmod/bin/lua_shared.dll") - .or_else(|_| find_library!("bin/lua_shared.dll")) + crate::__private__gmod_rs__try_chained_open! { + crate::open_library_raw!("garrysmod/bin/lua_shared.dll"), + crate::open_library_raw!("bin/lua_shared.dll") + } .expect("Failed to load lua_shared.dll") } #[cfg(all(target_os = "linux", target_pointer_width = "32"))] pub unsafe fn find_lua_shared() -> (Library, &'static str) { - find_library!("garrysmod/bin/lua_shared_srv.so") - .or_else(|_| find_library!("bin/linux32/lua_shared.so")) + crate::__private__gmod_rs__try_chained_open! { + crate::open_library_raw!("garrysmod/bin/lua_shared_srv.so"), + crate::open_library_raw!("bin/linux32/lua_shared.so") + } .expect("Failed to find lua_shared.so or lua_shared_srv.so") } #[cfg(all(target_os = "linux", target_pointer_width = "64"))] pub unsafe fn find_lua_shared() -> (Library, &'static str) { - find_library!("bin/linux64/lua_shared.so") + crate::open_library_raw!("bin/linux64/lua_shared.so") .expect("Failed to find lua_shared.so") } }