You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
"To avoid re-allocating the context multiple times when evaluating multiple CFI programs, it can be reused."
However, reusing the context can be tricky: If your unwind data is stored in a slice with a limited lifetime, and you use EndianSlice<'mylifetime> as the Reader, then the unwind context cannot outlive that lifetime.
Example program (does not compile):
use gimli::{BaseAddresses,EhFrame,EndianSlice,NativeEndian,UnwindContext,UnwindSection};use std::collections::HashMap;#[derive(Default)]structUnwinder{eh_frame_data_for_module:HashMap<String,Vec<u8>>,unwind_context:UnwindContext<EndianSlice<'static,NativeEndian>>,}implUnwinder{fnadd_module(&mutself,module_name:implInto<String>,eh_frame_data:Vec<u8>){self.eh_frame_data_for_module.insert(module_name.into(), eh_frame_data);}fnremove_module(&mutself,module_name:&str){self.eh_frame_data_for_module.remove(module_name);}fnunwind_in_module(&mutself,module_name:&str,address:u64){let eh_frame_data = self.eh_frame_data_for_module.get(module_name).unwrap();let eh_frame = EhFrame::new(&eh_frame_data,NativeEndian);let bases = BaseAddresses::default();let _unwind_info = eh_frame
.unwind_info_for_address(&bases,&mutself.unwind_context,// ERROR: can't be used due to eh_frame_data's lifetime
address,EhFrame::cie_from_offset,).unwrap();}}fnmain(){letmut unwinder = Unwinder::default();
unwinder.add_module("lib1.so",vec![0,1,2,3]);
unwinder.unwind_in_module("lib1.so",0x1234);
unwinder.add_module("lib2.so",vec![0,1,2,3]);
unwinder.unwind_in_module("lib2.so",0x5678);}
The two remedies I know of are:
If you do not own the data, then you have to create a new UnwindContext every time. Ideally you have some scope inside which you can do as many batched unwinds as possible, so that you can at least reuse the context to some degree.
If you have (shared or full) ownership over the data, then you can create an EndianRcSlice or your own Rc-based Reader implementation which makes the data live as long as necessary.
With the Rc solution, the UnwindContext may keep your data alive for longer than you anticipated because the context is not reset at the end of each use - it's only reset at the start of the next use.
Furthermore, if you're writing an unwinding library which wraps gimli and you allow the user to provide custom OwnedData types, and your library uses EndianReader to create a custom Reader implementation which wraps the user-provided OwnedData type, then you have to take extra care to make sure that the type you give to EndianReader implements StableDeref correctly (your type must guarantee that it derefs to the same address every time even if the OwnedData type does not, or alternatively you have to put a StableDeref trait bound on your library's OwnedData trait).
It would be great if we could find a way to reuse the allocations inside UnwindContext in such a way that the same allocation can be used with EndianSlice readers of different lifetimes.
Could we add a reset_and_recycle method on UnwindContext?
/// Tries to reuse the allocation if the layouts of `R2` and `R` matchfnreset_and_recycle<R2:Reader>(self) -> UnwindContext<R2,A>{letmut ctx = UnwindContext{stack:self.stack.clear_and_recycle(),initial_rule:None,is_initialized:false,};
ctx.reset();
ctx
}
The docs for
UnwindContext
say:"To avoid re-allocating the context multiple times when evaluating multiple CFI programs, it can be reused."
However, reusing the context can be tricky: If your unwind data is stored in a slice with a limited lifetime, and you use
EndianSlice<'mylifetime>
as theReader
, then the unwind context cannot outlive that lifetime.Example program (does not compile):
The two remedies I know of are:
UnwindContext
every time. Ideally you have some scope inside which you can do as many batched unwinds as possible, so that you can at least reuse the context to some degree.EndianRcSlice
or your own Rc-basedReader
implementation which makes the data live as long as necessary.With the Rc solution, the
UnwindContext
may keep your data alive for longer than you anticipated because the context is not reset at the end of each use - it's only reset at the start of the next use.Furthermore, if you're writing an unwinding library which wraps
gimli
and you allow the user to provide customOwnedData
types, and your library usesEndianReader
to create a customReader
implementation which wraps the user-providedOwnedData
type, then you have to take extra care to make sure that the type you give toEndianReader
implementsStableDeref
correctly (your type must guarantee that it derefs to the same address every time even if theOwnedData
type does not, or alternatively you have to put aStableDeref
trait bound on your library'sOwnedData
trait).It would be great if we could find a way to reuse the allocations inside
UnwindContext
in such a way that the same allocation can be used withEndianSlice
readers of different lifetimes.Could we add a
reset_and_recycle
method onUnwindContext
?Then the example above would become:
The text was updated successfully, but these errors were encountered: