Skip to content

Commit 8ebce7e

Browse files
committed
fix: Prevent double-enter with same &mut ExtCtxt (which would be UB)
1 parent 2a49c14 commit 8ebce7e

File tree

2 files changed

+20
-8
lines changed

2 files changed

+20
-8
lines changed

compiler/rustc_expand/src/derive_macro_expansion.rs

Lines changed: 19 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ use rustc_span::LocalExpnId;
1212
use crate::base::ExtCtxt;
1313
use crate::errors;
1414

15-
pub(super) fn expand<'tcx>(
15+
pub(super) fn provide_derive_macro_expansion<'tcx>(
1616
tcx: TyCtxt<'tcx>,
1717
key: (LocalExpnId, &'tcx TokenStream),
1818
) -> Result<&'tcx TokenStream, ()> {
@@ -51,7 +51,6 @@ pub(super) fn expand<'tcx>(
5151
type CLIENT = pm::bridge::client::Client<pm::TokenStream, pm::TokenStream>;
5252

5353
// based on rust/compiler/rustc_middle/src/ty/context/tls.rs
54-
// #[cfg(not(parallel_compiler))]
5554
thread_local! {
5655
/// A thread local variable that stores a pointer to the current `CONTEXT`.
5756
static TLV: Cell<(*mut (), Option<CLIENT>)> = const { Cell::new((ptr::null_mut(), None)) };
@@ -67,21 +66,29 @@ unsafe fn downcast<'a>(context: *mut ()) -> &'a mut ExtCtxt<'a> {
6766
unsafe { &mut *(context as *mut ExtCtxt<'a>) }
6867
}
6968

70-
/// Sets `context` as the new current `CONTEXT` for the duration of the function `f`.
7169
#[inline]
72-
pub fn enter_context<'a, F, R>(context: (&mut ExtCtxt<'a>, CLIENT), f: F) -> R
70+
fn enter_context_erased<F, R>(erased: (*mut (), Option<CLIENT>), f: F) -> R
7371
where
7472
F: FnOnce() -> R,
7573
{
76-
let (ectx, client) = context;
77-
let erased = (erase(ectx), Some(client));
7874
TLV.with(|tlv| {
7975
let old = tlv.replace(erased);
8076
let _reset = rustc_data_structures::defer(move || tlv.set(old));
8177
f()
8278
})
8379
}
8480

81+
/// Sets `context` as the new current `CONTEXT` for the duration of the function `f`.
82+
#[inline]
83+
pub fn enter_context<'a, F, R>(context: (&mut ExtCtxt<'a>, CLIENT), f: F) -> R
84+
where
85+
F: FnOnce() -> R,
86+
{
87+
let (ectx, client) = context;
88+
let erased = (erase(ectx), Some(client));
89+
enter_context_erased(erased, f)
90+
}
91+
8592
/// Allows access to the current `CONTEXT` in a closure if one is available.
8693
#[inline]
8794
#[track_caller]
@@ -98,7 +105,12 @@ where
98105
// TODO: we should not be able to?
99106
// sync::assert_dyn_sync::<CONTEXT<'_>>();
100107

101-
unsafe { f(Some(&mut (downcast(ectx), client_opt.unwrap()))) }
108+
// prevent double entering, as that would allow creating two `&mut ExtCtxt`s
109+
// TODO: probably use a RefCell instead (which checks this properly)?
110+
enter_context_erased((ptr::null_mut(), None), || unsafe {
111+
let ectx = downcast(ectx);
112+
f(Some(&mut (ectx, client_opt.unwrap())))
113+
})
102114
}
103115
}
104116

compiler/rustc_expand/src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ pub mod module;
3636
pub mod proc_macro;
3737

3838
pub fn provide(providers: &mut rustc_middle::util::Providers) {
39-
providers.derive_macro_expansion = derive_macro_expansion::expand;
39+
providers.derive_macro_expansion = derive_macro_expansion::provide_derive_macro_expansion;
4040
}
4141

4242
rustc_fluent_macro::fluent_messages! { "../messages.ftl" }

0 commit comments

Comments
 (0)