Reputation: 239
I'm preparing a script for PDB information extraction. Currently I cannot use info
variable even once because of its short lifetime.
I get 'borrowed value does not live long enough' error with the code below.
I understand this happens because of info.symbols()?
borrow, but I ran out of ideas on how this could be fixed.
How can I append the items into mod_symbols
?
Relevant library code (github.com/willglynn/pdb):
pub struct PDB<'s, S> {
msf: Box<dyn Msf<'s, S> + 's>,
dbi_header: Option<DBIHeader>,
dbi_extra_streams: Option<DBIExtraStreams>,
}
impl<'s, S: Source<'s> + 's> PDB<'s, S> {
pub fn module_info<'m>(&mut self, module: &Module<'m>) -> Result<Option<ModuleInfo<'s>>> {
Ok(self
.raw_stream(module.info().stream)?
.map(|stream| ModuleInfo::parse(stream, module)))
}
}
pub struct ModuleInfo<'s> {
stream: Stream<'s>,
symbols_size: usize,
lines_size: LinesSize,
}
impl<'s> ModuleInfo<'s> {
/// Get an iterator over the all symbols in this module.
pub fn symbols(&self) -> Result<SymbolIter<'_>> {
let mut buf = self.stream.parse_buffer();
buf.truncate(self.symbols_size)?;
if self.symbols_size > 0 {
let sig = buf.parse_u32()?;
if sig != constants::CV_SIGNATURE_C13 {
return Err(Error::UnimplementedFeature(
"Unsupported symbol data format",
));
}
}
Ok(SymbolIter::new(buf))
}
}
My script:
fn dump_pdb<'a>(filename: &str, imagebase: u64) -> pdb::Result<()> {
let file: File = std::fs::File::open(filename)?;
let mut pdb: PDB<File> = pdb::PDB::open(file)?;
// ...
let dbi: DebugInformation = pdb.debug_information()?;
let mut modules: ModuleIter = dbi.modules()?;
// merge the module functions
let mut mod_symbols: Vec<pdb::Symbol> = Vec::new();
while let Some(module) = modules.next()? {
println!("Module: {}", module.object_file_name());
let info: ModuleInfo = match pdb.module_info(&module)? {
Some(info) => info,
None => {
println!("no module info");
continue;
}
};
while let Some(symbol) = info.symbols()?.next()? { // `info` does not live long enough
mod_symbols.push(symbol); // borrow later used here
}
}
// ...
}
Error:
error[E0597]: `info` does not live long enough
--> examples\pdb_symbols2json.rs:251:34
|
251 | while let Some(symbol) = info.symbols()?.next()? {
| ^^^^^^^^^^^^^^ borrowed value does not live long enough
252 | mod_symbols.push(symbol);
| ------------------------ borrow later used here
...
282 | }
| - `info` dropped here while still borrowed
Upvotes: 0
Views: 90
Reputation: 98476
The problem is that it looks like most types in pdb
have a hidden lifetime argument.
IMO, you should write pdb::Symbol<'_>
and pdb::Module<'_>
to make that apparent. I expect that a future Rust edition will make not writing the lifetime argument a hard error.
About your particular situation, I don't know the details of that crate, but I guess that your mod_symbols
is storing values ultimately borrowed from info
, so one should outlive the other. But you are creating and destroying info
with each iteration of the loop, and that would invalidate the values stored in the mod_symbols
.
You can try storing the info
values in an outer scope. Something like this (untested):
// infos lives longer than mod_symbols!
let mut infos: Vec<ModuleInfo<'_>> = Vec::new();
let mut mod_symbols: Vec<pdb::Symbol<'_>> = Vec::new();
while let Some(module) = modules.next()? {
println!("Module: {}", module.object_file_name());
let info = match pdb.module_info(&module)? {
Some(info) => info,
None => {
println!("no module info");
continue;
}
};
infos.push(info);
}
for info in &infos {
while let Some(symbol) = info.symbols()?.next()? {
mod_symbols.push(symbol);
}
}
Upvotes: 2