From 90b05314741124fdd1acf2ea2b379a0199ab4a12 Mon Sep 17 00:00:00 2001 From: Rua Date: Sun, 18 Apr 2021 21:53:56 +0200 Subject: [PATCH] Entry::new returns Err when entry point isn't found (#390) * Check for entry point in EntryCustom::new and return error * Split off into load_checked * Remove string from MissingEntryPoint * Change MissingEntryPoint error message --- ash/src/entry.rs | 44 +++++++++++++++++++++++++++++++++---- ash/src/entry_libloading.rs | 28 ++++++++++++++++++----- 2 files changed, 63 insertions(+), 9 deletions(-) diff --git a/ash/src/entry.rs b/ash/src/entry.rs index 558df95..29fccbf 100644 --- a/ash/src/entry.rs +++ b/ash/src/entry.rs @@ -3,6 +3,7 @@ use crate::prelude::*; use crate::vk; use crate::RawPtr; use std::error::Error; +use std::ffi::CStr; use std::fmt; use std::mem; use std::os::raw::c_char; @@ -163,11 +164,15 @@ impl EntryV1_2 for EntryCustom { } impl EntryCustom { - pub fn new_custom(mut lib: L, mut load: Load) -> Self + pub fn new_custom( + mut lib: L, + mut load: Load, + ) -> std::result::Result where Load: FnMut(&mut L, &::std::ffi::CStr) -> *const c_void, { - let static_fn = vk::StaticFn::load(|name| load(&mut lib, name)); + // Bypass the normal StaticFn::load so we can return an error + let static_fn = vk::StaticFn::load_checked(|name| load(&mut lib, name))?; let entry_fn_1_0 = vk::EntryFnV1_0::load(|name| unsafe { mem::transmute(static_fn.get_instance_proc_addr(vk::Instance::null(), name.as_ptr())) @@ -181,13 +186,13 @@ impl EntryCustom { mem::transmute(static_fn.get_instance_proc_addr(vk::Instance::null(), name.as_ptr())) }); - EntryCustom { + Ok(EntryCustom { static_fn, entry_fn_1_0, entry_fn_1_1, entry_fn_1_2, lib, - } + }) } #[doc = ""] @@ -226,3 +231,34 @@ impl EntryCustom { } } } + +impl vk::StaticFn { + pub fn load_checked(mut _f: F) -> Result + where + F: FnMut(&::std::ffi::CStr) -> *const c_void, + { + // TODO: Make this a &'static CStr once CStr::from_bytes_with_nul_unchecked is const + static ENTRY_POINT: &[u8] = b"vkGetInstanceProcAddr\0"; + + Ok(vk::StaticFn { + get_instance_proc_addr: unsafe { + let cname = CStr::from_bytes_with_nul_unchecked(ENTRY_POINT); + let val = _f(cname); + if val.is_null() { + return Err(MissingEntryPoint); + } else { + ::std::mem::transmute(val) + } + }, + }) + } +} + +#[derive(Clone, Debug)] +pub struct MissingEntryPoint; +impl std::fmt::Display for MissingEntryPoint { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::result::Result<(), std::fmt::Error> { + write!(f, "Cannot load `vkGetInstanceProcAddr` symbol from library") + } +} +impl std::error::Error for MissingEntryPoint {} diff --git a/ash/src/entry_libloading.rs b/ash/src/entry_libloading.rs index ab286eb..8acb030 100644 --- a/ash/src/entry_libloading.rs +++ b/ash/src/entry_libloading.rs @@ -1,4 +1,5 @@ use crate::entry::EntryCustom; +use crate::entry::MissingEntryPoint; use libloading::Library; use std::error::Error; use std::ffi::OsStr; @@ -25,17 +26,32 @@ const LIB_PATH: &str = "libvulkan.dylib"; pub type Entry = EntryCustom>; #[derive(Debug)] -pub struct LoadingError(libloading::Error); +pub enum LoadingError { + LibraryLoadFailure(libloading::Error), + MissingEntryPoint(MissingEntryPoint), +} impl fmt::Display for LoadingError { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - fmt::Display::fmt(&self.0, f) + match self { + LoadingError::LibraryLoadFailure(err) => fmt::Display::fmt(err, f), + LoadingError::MissingEntryPoint(err) => fmt::Display::fmt(err, f), + } } } impl Error for LoadingError { fn source(&self) -> Option<&(dyn Error + 'static)> { - Error::source(&self.0) + Some(match self { + LoadingError::LibraryLoadFailure(err) => err, + LoadingError::MissingEntryPoint(err) => err, + }) + } +} + +impl From for LoadingError { + fn from(err: MissingEntryPoint) -> Self { + LoadingError::MissingEntryPoint(err) } } @@ -71,13 +87,15 @@ impl EntryCustom> { /// `dlopen`ing native libraries is inherently unsafe. The safety guidelines /// for [`Library::new`] and [`Library::get`] apply here. pub unsafe fn with_library(path: impl AsRef) -> Result { - let lib = Library::new(path).map_err(LoadingError).map(Arc::new)?; + let lib = Library::new(path) + .map_err(LoadingError::LibraryLoadFailure) + .map(Arc::new)?; Ok(Self::new_custom(lib, |vk_lib, name| { vk_lib .get(name.to_bytes_with_nul()) .map(|symbol| *symbol) .unwrap_or(ptr::null_mut()) - })) + })?) } }