Description
I am relatively new to rust, but I am a huge, huge fan. I hate to report an issue and hope that it's something worthwhile.
I am attempting to use proc_macro[2]::TokenStream
in the implementation of a proc macro. I share a vector of TokenStream
s across multiple invocations of those proc macros using storage allocated with thread_local!
. That sounds complicated, but I promise it's not:
extern crate proc_macro;
extern crate proc_macro2;
use proc_macro::TokenStream;
use quote::quote;
use std::cell::RefCell;
thread_local!(static ARMS: RefCell<Vec<proc_macro2::TokenStream>> = RefCell::new(Vec::<proc_macro2::TokenStream>::new()));
#[proc_macro_attribute]
pub fn arm(
_ : TokenStream,
item: TokenStream,
) -> TokenStream {
let ts = proc_macro2::TokenStream::new();
ARMS.with(|arms| {
arms.borrow_mut().push(ts);
});
item
}
#[proc_macro]
pub fn make_arms(_: proc_macro::TokenStream) -> proc_macro::TokenStream {
proc_macro::TokenStream::from(quote!{ pub fn arms(&self) { self.arm1(); } })
}
Here's how I could use these proc macros:
extern crate rust_macro_error;
use rust_macro_error::arm;
use rust_macro_error::make_arms;
struct T {
_i: usize,
}
impl T {
pub fn new() -> Self {
T { _i: 2 }
}
#[arm]
pub fn arm1(&self) {
}
make_arms!();
}
fn main() {
T::new().arms();
}
Here is my Cargo.toml
[package]
name = "rust_macro_error"
version = "0.1.0"
authors = ["Will Hawkins <[email protected]>"]
edition = "2018"
[lib]
proc-macro = true
[[bin]]
name = "rust_macro_error"
path = "src/main.rs"
[dependencies]
quote="1.0.0"
proc-macro2="1.0.1"
[dependencies.syn]
version="1.0"
features = ["full"]
If it's easier, you can grab these files from this git repository: http://git.obs.cr/hawkinsw/rust_macro_error
When I run cargo build
, I get a rustc
failure. I have attempted to compile this with stable, nightly and "head" (stage2 compiler of HEAD). I get the same error no matter which compiler:
fatal runtime error: failed to initiate panic, error 5
I can run the compiler under gdb
but see nothing worthwhile:
#0 0x00007ffff32999f3 in futex_wait_cancelable (private=<optimized out>,
expected=0, futex_word=0x7fffec4f54a8)
at ../sysdeps/unix/sysv/linux/futex-internal.h:88
#1 __pthread_cond_wait_common (abstime=0x0, mutex=0x7fffec4f5450,
cond=0x7fffec4f5480) at pthread_cond_wait.c:502
#2 __pthread_cond_wait (cond=0x7fffec4f5480, mutex=0x7fffec4f5450)
at pthread_cond_wait.c:655
#3 0x00007ffff3db4e62 in std::sys::unix::condvar::Condvar::wait (
mutex=<optimized out>, self=<optimized out>)
at src/libstd/sys/unix/condvar.rs:71
#4 std::sys_common::condvar::Condvar::wait (mutex=<optimized out>,
self=<optimized out>) at src/libstd/sys_common/condvar.rs:41
#5 std::sync::condvar::Condvar::wait (self=<optimized out>, guard=...)
at src/libstd/sync/condvar.rs:204
#6 0x00007ffff3d917db in std::thread::park () at src/libstd/thread/mod.rs:911
#7 0x00007ffff3d746e2 in std::sync::mpsc::blocking::WaitToken::wait (self=...)
at src/libstd/sync/mpsc/blocking.rs:71
#8 0x00007ffff702275d in std::sync::mpsc::stream::Packet<T>::recv (
self=0x7fffd8001080, deadline=...)
at /home/hawkinsw/code/rust/rust/src/libstd/sync/mpsc/stream.rs:194
#9 0x00007ffff70267ac in std::sync::mpsc::Receiver<T>::recv (
self=0x7ffff04f88f0)
at /home/hawkinsw/code/rust/rust/src/libstd/sync/mpsc/mod.rs:1197
#10 0x00007ffff7027055 in <std::sync::mpsc::IntoIter<T> as core::iter::traits::iterator::Iterator>::next (self=0x7ffff04f88f0)
at /home/hawkinsw/code/rust/rust/src/libstd/sync/mpsc/mod.rs:1533
#11 jobserver::imp::spawn_helper::{{closure}} ()
at /home/hawkinsw/.cargo/registry/src/github.com-1ecc6299db9ec823/jobserver-0.1.16/src/lib.rs:635
#12 std::sys_common::backtrace::__rust_begin_short_backtrace (f=...)
at /home/hawkinsw/code/rust/rust/src/libstd/sys_common/backtrace.rs:77
#13 0x00007ffff702a983 in std::thread::Builder::spawn_unchecked::{{closure}}::{{closure}} () at /home/hawkinsw/code/rust/rust/src/libstd/thread/mod.rs:470
#14 <std::panic::AssertUnwindSafe<F> as core::ops::function::FnOnce<()>>::call_once (self=..., _args=<optimized out>)
at /home/hawkinsw/code/rust/rust/src/libstd/panic.rs:315
#15 std::panicking::try::do_call (data=<optimized out>)
at /home/hawkinsw/code/rust/rust/src/libstd/panicking.rs:296
#16 0x00007ffff3db6a14 in __rust_maybe_catch_panic (f=0x0,
data=0x7fffec4f54a8 "\002", data_ptr=0x7ffff04f8a00,
vtable_ptr=0x7ffff04f8a08) at src/libpanic_unwind/lib.rs:80
#17 0x00007ffff702ab84 in std::panicking::try (f=...)
at /home/hawkinsw/code/rust/rust/src/libstd/panicking.rs:275
#18 std::panic::catch_unwind (f=...)
at /home/hawkinsw/code/rust/rust/src/libstd/panic.rs:394
#19 std::thread::Builder::spawn_unchecked::{{closure}} ()
at /home/hawkinsw/code/rust/rust/src/libstd/thread/mod.rs:469
#20 core::ops::function::FnOnce::call_once{{vtable-shim}} ()
at /home/hawkinsw/code/rust/rust/src/libcore/ops/function.rs:235
#21 0x00007ffff3d75a6f in <alloc::boxed::Box<F> as core::ops::function::FnOnce<A>>::call_once (self=..., args=<optimized out>)
at /home/hawkinsw/code/rust/rust/src/liballoc/boxed.rs:922
#22 0x00007ffff3d7e7d0 in <alloc::boxed::Box<F> as core::ops::function::FnOnce<A>>::call_once (self=0x7fffec4f55b0, args=<optimized out>)
at /home/hawkinsw/code/rust/rust/src/liballoc/boxed.rs:922
#23 std::sys_common::thread::start_thread (main=<optimized out>)
at src/libstd/sys_common/thread.rs:13
#24 std::sys::unix::thread::Thread::new::thread_start (main=0x7fffec4f55b0)
at src/libstd/sys/unix/thread.rs:79
#25 0x00007ffff32936db in start_thread (arg=0x7ffff04fa700)
at pthread_create.c:463
#26 0x00007ffff3a4b88f in clone ()
at ../sysdeps/unix/sysv/linux/x86_64/clone.S:95
There are a few interesting things that I have noticed while attempting to debug this:
- If I use another type, say
String
, in the TLS vector, everything works fine. - If I don't push any values to the vector, everything works a-ok.
- I can sometimes get the error message:
use-after-free in 'proc_macro' handle
and can narrow that down to line 315 in libproc_macro/bridge/client.rs. I understand that to mean that the "server" for the proc_macro implementation is not alive, for some reason. I have seen Panic inside panic when procedural macro is called with proc_macro::bridge::client #60593 and think that they are related but cannot seem to find the common thread.
I have debugged as much as I can and I am reaching out for your help! I would love to help solve the problem if you can point me in the right direction.
Again, thank you for all the work that you are doing for rust and the community around the language.