Skip to content

Commit 1fb465f

Browse files
authored
Merge pull request #19459 from Veykril/push-swywyozvsqow
refactor: Shuffle some unsafety around in proc-macro-srv
2 parents d6b9261 + c6d3c4f commit 1fb465f

File tree

3 files changed

+41
-41
lines changed

3 files changed

+41
-41
lines changed

crates/proc-macro-srv/src/dylib.rs

+39-13
Original file line numberDiff line numberDiff line change
@@ -21,13 +21,32 @@ use crate::{ProcMacroKind, ProcMacroSrvSpan, proc_macros::ProcMacros, server_imp
2121
/// [here](https://github.com/fedochet/rust-proc-macro-panic-inside-panic-expample/issues/1)
2222
///
2323
/// It seems that on Windows that behaviour is default, so we do nothing in that case.
24+
///
25+
/// # Safety
26+
///
27+
/// The caller is responsible for ensuring that the path is valid proc-macro library
2428
#[cfg(windows)]
25-
fn load_library(file: &Utf8Path) -> Result<Library, libloading::Error> {
29+
unsafe fn load_library(file: &Utf8Path) -> Result<Library, libloading::Error> {
30+
// SAFETY: The caller is responsible for ensuring that the path is valid proc-macro library
2631
unsafe { Library::new(file) }
2732
}
2833

34+
/// Loads dynamic library in platform dependent manner.
35+
///
36+
/// For unix, you have to use RTLD_DEEPBIND flag to escape problems described
37+
/// [here](https://github.com/fedochet/rust-proc-macro-panic-inside-panic-expample)
38+
/// and [here](https://github.com/rust-lang/rust/issues/60593).
39+
///
40+
/// Usage of RTLD_DEEPBIND
41+
/// [here](https://github.com/fedochet/rust-proc-macro-panic-inside-panic-expample/issues/1)
42+
///
43+
/// It seems that on Windows that behaviour is default, so we do nothing in that case.
44+
///
45+
/// # Safety
46+
///
47+
/// The caller is responsible for ensuring that the path is valid proc-macro library
2948
#[cfg(unix)]
30-
fn load_library(file: &Utf8Path) -> Result<Library, libloading::Error> {
49+
unsafe fn load_library(file: &Utf8Path) -> Result<Library, libloading::Error> {
3150
// not defined by POSIX, different values on mips vs other targets
3251
#[cfg(target_env = "gnu")]
3352
use libc::RTLD_DEEPBIND;
@@ -39,6 +58,7 @@ fn load_library(file: &Utf8Path) -> Result<Library, libloading::Error> {
3958
#[cfg(not(target_env = "gnu"))]
4059
const RTLD_DEEPBIND: std::os::raw::c_int = 0x0;
4160

61+
// SAFETY: The caller is responsible for ensuring that the path is valid proc-macro library
4262
unsafe { UnixLibrary::open(Some(file), RTLD_NOW | RTLD_DEEPBIND).map(|lib| lib.into()) }
4363
}
4464

@@ -84,26 +104,32 @@ struct ProcMacroLibrary {
84104
impl ProcMacroLibrary {
85105
fn open(path: &Utf8Path) -> Result<Self, LoadProcMacroDylibError> {
86106
let file = fs::File::open(path)?;
107+
#[allow(clippy::undocumented_unsafe_blocks)] // FIXME
87108
let file = unsafe { memmap2::Mmap::map(&file) }?;
88109
let obj = object::File::parse(&*file)
89110
.map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))?;
90111
let version_info = version::read_dylib_info(&obj)?;
112+
if version_info.version_string != crate::RUSTC_VERSION_STRING {
113+
return Err(LoadProcMacroDylibError::AbiMismatch(version_info.version_string));
114+
}
115+
91116
let symbol_name =
92117
find_registrar_symbol(&obj).map_err(invalid_data_err)?.ok_or_else(|| {
93118
invalid_data_err(format!("Cannot find registrar symbol in file {path}"))
94119
})?;
95120

96-
let lib = load_library(path).map_err(invalid_data_err)?;
97-
let proc_macros = unsafe {
98-
// SAFETY: We extend the lifetime here to avoid referential borrow problems
99-
// We never reveal proc_macros to the outside and drop it before _lib
100-
std::mem::transmute::<&ProcMacros, &'static ProcMacros>(ProcMacros::from_lib(
101-
&lib,
102-
symbol_name,
103-
&version_info.version_string,
104-
)?)
105-
};
106-
Ok(ProcMacroLibrary { _lib: lib, proc_macros })
121+
// SAFETY: We have verified the validity of the dylib as a proc-macro library
122+
let lib = unsafe { load_library(path) }.map_err(invalid_data_err)?;
123+
// SAFETY: We have verified the validity of the dylib as a proc-macro library
124+
// The 'static lifetime is a lie, it's actually the lifetime of the library but unavoidable
125+
// due to self-referentiality
126+
// But we make sure that we do not drop it before the symbol is dropped
127+
let proc_macros =
128+
unsafe { lib.get::<&'static &'static ProcMacros>(symbol_name.as_bytes()) };
129+
match proc_macros {
130+
Ok(proc_macros) => Ok(ProcMacroLibrary { proc_macros: *proc_macros, _lib: lib }),
131+
Err(e) => Err(e.into()),
132+
}
107133
}
108134
}
109135

crates/proc-macro-srv/src/lib.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
#![cfg_attr(feature = "in-rust-tree", feature(rustc_private))]
1616
#![feature(proc_macro_internals, proc_macro_diagnostic, proc_macro_span)]
1717
#![allow(unreachable_pub, internal_features, clippy::disallowed_types, clippy::print_stderr)]
18-
#![deny(deprecated_safe)]
18+
#![deny(deprecated_safe, clippy::undocumented_unsafe_blocks)]
1919

2020
extern crate proc_macro;
2121
#[cfg(feature = "in-rust-tree")]

crates/proc-macro-srv/src/proc_macros.rs

+1-27
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,7 @@
22
33
use proc_macro::bridge;
44

5-
use libloading::Library;
6-
7-
use crate::{
8-
ProcMacroKind, ProcMacroSrvSpan, dylib::LoadProcMacroDylibError, server_impl::TopSubtree,
9-
};
5+
use crate::{ProcMacroKind, ProcMacroSrvSpan, server_impl::TopSubtree};
106

117
#[repr(transparent)]
128
pub(crate) struct ProcMacros([bridge::client::ProcMacro]);
@@ -18,28 +14,6 @@ impl From<bridge::PanicMessage> for crate::PanicMessage {
1814
}
1915

2016
impl ProcMacros {
21-
/// Load a new ABI.
22-
///
23-
/// # Arguments
24-
///
25-
/// *`lib` - The dynamic library containing the macro implementations
26-
/// *`symbol_name` - The symbol name the macros can be found attributes
27-
/// *`info` - RustCInfo about the compiler that was used to compile the
28-
/// macro crate. This is the information we use to figure out
29-
/// which ABI to return
30-
pub(crate) fn from_lib<'l>(
31-
lib: &'l Library,
32-
symbol_name: String,
33-
version_string: &str,
34-
) -> Result<&'l ProcMacros, LoadProcMacroDylibError> {
35-
if version_string != crate::RUSTC_VERSION_STRING {
36-
return Err(LoadProcMacroDylibError::AbiMismatch(version_string.to_owned()));
37-
}
38-
unsafe { lib.get::<&'l &'l ProcMacros>(symbol_name.as_bytes()) }
39-
.map(|it| **it)
40-
.map_err(Into::into)
41-
}
42-
4317
pub(crate) fn expand<S: ProcMacroSrvSpan>(
4418
&self,
4519
macro_name: &str,

0 commit comments

Comments
 (0)