rust 借用时如何延长变量的生存期

ne5o7dgx  于 2023-05-29  发布在  其他
关注(0)|答案(1)|浏览(143)

我在准备PDB信息提取的脚本。目前我不能使用info变量,因为它的生命周期很短。
我得到'借来的价值不活足够长'的错误与下面的代码。
我知道这是因为info.symbols()?借用而发生的,但我已经不知道如何修复了。
如何将项目追加到mod_symbols中?
相关库代码(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))
    }
}

我的剧本:

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[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
ctehm74n

ctehm74n1#

问题是看起来pdb中的mosttypes有一个隐藏的生命周期参数。
IMO,你应该写pdb::Symbol<'_>pdb::Module<'_>来使这一点变得明显。我预计未来的Rust版本会让不写生命周期参数成为一个严重错误。
关于您的具体情况,我不知道那个crate的细节,但我猜您的mod_symbols存储的值最终是从info借用的,因此一个应该比另一个更长寿。但是您在循环的每次迭代中创建和销毁info,这将使存储在mod_symbols中的值无效。
您可以尝试将info值存储在外部作用域中。类似这样(未经测试):

// 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);
        }
    }

相关问题