From 4fc02aa41f476db06d057ab7462a4bc1aa38ca29 Mon Sep 17 00:00:00 2001 From: Ivan Dlugos <6349682+vaind@users.noreply.github.com> Date: Tue, 7 Feb 2023 15:12:10 +0100 Subject: [PATCH] feat: PE embedded PPDB decompression to a custom writer (#757) --- CHANGELOG.md | 2 +- symbolic-debuginfo/src/pe.rs | 23 ++++++++++------------- symbolic-debuginfo/tests/test_objects.rs | 10 ++++++++-- symbolic-ppdb/tests/test_ppdb.rs | 6 ++++-- 4 files changed, 23 insertions(+), 18 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5ad99cde8..79acefb99 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,7 +6,7 @@ - Correctly read the `debug_id` of Deterministic PE files ([#658](https://github.com/getsentry/symbolic/pull/658)) - Gracefully handle invalid PPDBs ([#751](https://github.com/getsentry/symbolic/pull/751)) -- Support embedded PortablePDB in DLLs ([#752](https://github.com/getsentry/symbolic/pull/752)) +- Support embedded PortablePDB in DLLs ([#752](https://github.com/getsentry/symbolic/pull/752), [#757](https://github.com/getsentry/symbolic/pull/757)) ## 11.0.0 diff --git a/symbolic-debuginfo/src/pe.rs b/symbolic-debuginfo/src/pe.rs index 8cf4d7f21..31a6995a1 100644 --- a/symbolic-debuginfo/src/pe.rs +++ b/symbolic-debuginfo/src/pe.rs @@ -3,9 +3,8 @@ use std::borrow::Cow; use std::error::Error; use std::fmt; -use std::io::Read; +use std::io::Write; -use flate2::read::DeflateDecoder; use gimli::RunTimeEndian; use goblin::pe; use scroll::{Pread, LE}; @@ -504,16 +503,14 @@ impl<'data, 'object> PeEmbeddedPortablePDB<'data> { self.uncompressed_size } - /// Reads the Portable PDB contents into the provided vector. - pub fn decompress(&self) -> Result, PeError> { - let mut decoder = DeflateDecoder::new(self.compressed_data); - let mut output: Vec = vec![0; self.uncompressed_size]; - let read_size = decoder.read(&mut output).map_err(PeError::new)?; - if read_size != self.uncompressed_size { - return Err(PeError::new(symbolic_ppdb::FormatError::from( - symbolic_ppdb::FormatErrorKind::InvalidLength, - ))); - } - Ok(output) + /// Reads the Portable PDB contents into the writer. + pub fn decompress_to(&self, output: W) -> Result<(), PeError> { + use std::io::prelude::*; + let mut decoder = flate2::write::DeflateDecoder::new(output); + decoder + .write_all(self.compressed_data) + .and_then(|_| decoder.finish()) + .map_err(PeError::new)?; + Ok(()) } } diff --git a/symbolic-debuginfo/tests/test_objects.rs b/symbolic-debuginfo/tests/test_objects.rs index d34460585..dcfd3797c 100644 --- a/symbolic-debuginfo/tests/test_objects.rs +++ b/symbolic-debuginfo/tests/test_objects.rs @@ -1,4 +1,4 @@ -use std::{ffi::CString, fmt}; +use std::{env, ffi::CString, fmt, io::BufWriter}; use symbolic_common::ByteView; use symbolic_debuginfo::{ @@ -565,8 +565,14 @@ fn test_pe_embedded_ppdb() -> Result<(), Error> { let embedded_ppdb = pe.embedded_ppdb().unwrap().unwrap(); assert_eq!(embedded_ppdb.get_size(), 10540); - let buf = embedded_ppdb.decompress()?; + let mut buf = Vec::new(); + embedded_ppdb.decompress_to(&mut buf)?; assert_eq!(&buf[15..25], "\0PDB v1.0\0".as_bytes()); + + let tmp_file = tempfile::tempfile()?; + embedded_ppdb.decompress_to(BufWriter::new(&tmp_file))?; + let file_buf = ByteView::map_file(tmp_file)?; + assert_eq!(buf, file_buf.as_slice()); } Ok(()) } diff --git a/symbolic-ppdb/tests/test_ppdb.rs b/symbolic-ppdb/tests/test_ppdb.rs index a3b5c0903..1e5e6da47 100644 --- a/symbolic-ppdb/tests/test_ppdb.rs +++ b/symbolic-ppdb/tests/test_ppdb.rs @@ -109,7 +109,8 @@ fn test_pe_embedded_ppdb_without_sources() { let pe = PeObject::parse(&pe_buf).unwrap(); let embedded_ppdb = pe.embedded_ppdb().unwrap().unwrap(); - let ppdb_buf = embedded_ppdb.decompress().unwrap(); + let mut ppdb_buf = Vec::new(); + embedded_ppdb.decompress_to(&mut ppdb_buf).unwrap(); let ppdb = PortablePdb::parse(&ppdb_buf).unwrap(); assert_eq!(ppdb.pdb_id().unwrap(), pe.debug_id()); @@ -128,7 +129,8 @@ fn test_pe_embedded_ppdb_with_sources() { let pe = PeObject::parse(&pe_buf).unwrap(); let embedded_ppdb = pe.embedded_ppdb().unwrap().unwrap(); - let ppdb_buf = embedded_ppdb.decompress().unwrap(); + let mut ppdb_buf = Vec::new(); + embedded_ppdb.decompress_to(&mut ppdb_buf).unwrap(); let ppdb = PortablePdb::parse(&ppdb_buf).unwrap(); assert_eq!(ppdb.pdb_id().unwrap(), pe.debug_id());