Fixed UB in generated Monotonic::now()

This commit is contained in:
Emil Fresk 2021-02-21 16:15:34 +01:00
parent 555f36857e
commit 1a46345a2a
3 changed files with 26 additions and 12 deletions

View file

@ -112,9 +112,12 @@ pub fn app(app: &App, analysis: &Analysis, extra: &Extra) -> TokenStream2 {
.iter() .iter()
.map(|(_, monotonic)| { .map(|(_, monotonic)| {
let name = &monotonic.ident; let name = &monotonic.ident;
let name_str = &name.to_string();
let ty = &monotonic.ty; let ty = &monotonic.ty;
let mangled_name = util::mangle_monotonic_type(&name.to_string()); let mangled_name = util::mangle_monotonic_type(&name_str);
let ident = util::monotonic_ident(&name.to_string()); let ident = util::monotonic_ident(&name_str);
let panic_str = &format!("Use of monotonic '{}' before it was passed to the runtime", name_str);
quote! { quote! {
pub use rtic::Monotonic as _; pub use rtic::Monotonic as _;
@ -123,14 +126,20 @@ pub fn app(app: &App, analysis: &Analysis, extra: &Extra) -> TokenStream2 {
#[allow(non_snake_case)] #[allow(non_snake_case)]
pub mod #name { pub mod #name {
/// Access the global `Monotonic` implementation, not that this will panic
/// before the this `Monotonic` has been passed to the RTIC runtime.
pub fn now() -> rtic::time::Instant<#app_path::#mangled_name> { pub fn now() -> rtic::time::Instant<#app_path::#mangled_name> {
rtic::export::interrupt::free(|_| { rtic::export::interrupt::free(|_| {
use rtic::Monotonic as _; use rtic::Monotonic as _;
use rtic::time::Clock as _; use rtic::time::Clock as _;
if let Ok(v) = unsafe{ (&*#app_path::#ident.as_ptr()).try_now() } { if let Some(m) = unsafe{ #app_path::#ident.as_ref() } {
v if let Ok(v) = m.try_now() {
v
} else {
unreachable!("Your monotonic is not infallible!")
}
} else { } else {
unreachable!("Your monotonic is not infallible!") panic!(#panic_str);
} }
}) })
} }

View file

@ -35,7 +35,7 @@ pub fn codegen(app: &App, analysis: &Analysis) -> Vec<TokenStream2> {
// Store the monotonic // Store the monotonic
let name = util::monotonic_ident(&monotonic.to_string()); let name = util::monotonic_ident(&monotonic.to_string());
stmts.push(quote!(#name.as_mut_ptr().write(monotonics.#idx);)); stmts.push(quote!(#name = Some(monotonics.#idx);));
} }
// Enable the interrupts -- this completes the `init`-ialization phase // Enable the interrupts -- this completes the `init`-ialization phase

View file

@ -69,11 +69,11 @@ pub fn codegen(app: &App, analysis: &Analysis, _extra: &Extra) -> Vec<TokenStrea
let mono = util::monotonic_ident(&monotonic_name); let mono = util::monotonic_ident(&monotonic_name);
let doc = &format!("Storage for {}", monotonic_name); let doc = &format!("Storage for {}", monotonic_name);
let mono_ty = quote!(core::mem::MaybeUninit<#m>); let mono_ty = quote!(Option<#m>);
items.push(quote!( items.push(quote!(
#[doc = #doc] #[doc = #doc]
static mut #mono: #mono_ty = core::mem::MaybeUninit::uninit(); static mut #mono: #mono_ty = None;
)); ));
} }
@ -122,10 +122,15 @@ pub fn codegen(app: &App, analysis: &Analysis, _extra: &Extra) -> Vec<TokenStrea
#[no_mangle] #[no_mangle]
#[allow(non_snake_case)] #[allow(non_snake_case)]
unsafe fn #bound_interrupt() { unsafe fn #bound_interrupt() {
while let Some((task, index)) = rtic::export::interrupt::free(|_| #tq.dequeue(
|| #disable_isr, while let Some((task, index)) = rtic::export::interrupt::free(|_|
&mut *#app_path::#m_ident.as_mut_ptr(), if let Some(mono) = #app_path::#m_ident.as_mut() {
)) #tq.dequeue(|| #disable_isr, mono)
} else {
// We can only use the timer queue if `init` has returned, and it
// writes the `Some(monotonic)` we are accessing here.
core::hint::unreachable_unchecked()
})
{ {
match task { match task {
#(#arms)* #(#arms)*