0

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?

mimak
  • 211
  • 2
  • 9
  • 1
    `globals` is made up of `Symbol`s that have a lifetime bound to the original `symbol_table`, and thus `chunks` and `data` do as well since you're just shuffling elements. And `thread::spawn` requires a `'static` lifetime, meaning the bound lifetime to `symbol_table` must be `'static` as well, but its not and thus the error. You can resolve it in this case by using `thread::scope` instead. See [How can I pass a reference to a stack variable to a thread?](/q/32750829/2189130) – kmdreko May 22 '23 at 03:10

0 Answers0