I'm struggling with a lifecycle issue which only appears when I add thread spawning to a function:
error[E0597]: `symbol_table` does not live long enough
--> examples\pdb_symbols2json.rs:173:49
|
173 | let globals = match preiterate_symbols(&mut symbol_table.iter()).ok() {
| ------------------------^^^^^^^^^^^^^^^^^^^-
| | |
| | borrowed value does not live long enough
| argument requires that `symbol_table` is borrowed for `'static`
...
235 | }
| - `symbol_table` dropped here while still borrowed
Here's the code:
#[derive(Debug)]
pub struct SymbolTable<'s> {
stream: Stream<'s>,
}
impl<'s> SymbolTable<'s> {
/// Parses a symbol table from raw stream data.
pub(crate) fn new(stream: Stream<'s>) -> Self {
SymbolTable { stream }
}
/// Returns an iterator that can traverse the symbol table in sequential order.
pub fn iter(&self) -> SymbolIter<'_> {
SymbolIter::new(self.stream.parse_buffer())
}
/// Returns an iterator over symbols starting at the given index.
pub fn iter_at(&self, index: SymbolIndex) -> SymbolIter<'_> {
let mut iter = self.iter();
iter.seek(index);
iter
}
}
fn preiterate_symbols<'a>(begin: &mut pdb::SymbolIter<'a>) -> pdb::Result<Vec<pdb::Symbol<'a>>> {
let mut symbols = Vec::new();
while let Some(symbol) = begin.next()? {
symbols.push(symbol);
}
Ok(symbols)
}
fn dump_pdb<'a>(filename: &str, imagebase: u64) -> pdb::Result<()> {
let file = std::fs::File::open(filename)?;
let mut pdb = pdb::PDB::open(file)?;
let address_map = pdb.address_map()?;
let symbol_table = pdb.global_symbols()?;
let binary_info = BinaryInfo {
file: filename.to_string(),
imagebase,
address_map,
};
print!("{}", binary_info);
// save function-address mappings to a JSON file
let mut mapping: Vec<Function> = Vec::new();
// pre-iterate over global symbols and create a symbol vector
let globals = match preiterate_symbols(&mut symbol_table.iter()).ok() {
Some(symbols) => symbols,
None => Vec::new()
};
// divide the data for multi-threading
let thread_nb = 8;
let chunk_size = globals.len() / thread_nb;
let mut chunks: Vec<Vec<pdb::Symbol>> = Vec::new();
let raw_chunks = globals.chunks_exact(chunk_size);
let remainder = raw_chunks.remainder();
for chunk in raw_chunks {
chunks.push(chunk.to_vec());
}
if remainder.len() > 0 {
for i in 0..remainder.len() {
chunks[i % thread_nb].push(remainder[i]);
}
}
// spawn threads
let mut handles: Vec<JoinHandle<()>> = vec![];
let data = Arc::new(Mutex::new(chunks));
for n in 0..thread_nb {
let data = Arc::clone(&data);
let handle = thread::spawn( move || {
let chunks = data.lock().unwrap();
println!("Thread {} chunk size: {}", n, chunks[n].len());
}
);
handles.push(handle);
}
for handle in handles {
handle.join().unwrap();
}
println!("Global symbols ({}):", globals.len());
// ...
Ok(())
}
What confuses me the most is when I comment out the multithreading part, the error disappears:
//let handle = thread::spawn( move || {
// let chunks = data.lock().unwrap();
// println!("Thread {} chunk size: {}", n, chunks[n].len());
// }
//);
This doesn't directly depend on symbol_table
. How can I make the variable's lifetime bound to the function scope?