summaryrefslogtreecommitdiff
path: root/plugins
diff options
context:
space:
mode:
Diffstat (limited to 'plugins')
-rw-r--r--plugins/warp/src/processor.rs59
1 files changed, 42 insertions, 17 deletions
diff --git a/plugins/warp/src/processor.rs b/plugins/warp/src/processor.rs
index 1611dff3..86ac5d02 100644
--- a/plugins/warp/src/processor.rs
+++ b/plugins/warp/src/processor.rs
@@ -11,6 +11,7 @@ use ar::Archive;
use dashmap::DashMap;
use rayon::iter::IntoParallelIterator;
use rayon::iter::{IntoParallelRefIterator, ParallelIterator};
+use rayon::prelude::ParallelSlice;
use regex::Regex;
use serde_json::{json, Value};
use tempdir::TempDir;
@@ -36,6 +37,11 @@ use crate::cache::cached_type_references;
use crate::convert::platform_to_target;
use crate::{build_function, INCLUDE_TAG_ICON, INCLUDE_TAG_NAME};
+/// Ensure we never exceed these many functions per signature chunk.
+///
+/// This was added to fix running into the max table limit on certain files.
+const MAX_FUNCTIONS_PER_CHUNK: usize = 1_000_000;
+
#[derive(Error, Debug)]
pub enum ProcessingError {
#[error("Failed to open archive: {0}")]
@@ -618,6 +624,15 @@ impl WarpFileProcessor {
}
}
+ // In the future we may want to do something with a view that has no functions, but for now
+ // we do not care to create any chunks. By skipping this we can avoid merging of empty chunks,
+ // which is quick, but it still requires some allocations that we can avoid.
+ if view.functions().is_empty() {
+ self.state
+ .set_file_state(path.clone(), ProcessingFileState::Processed);
+ return Err(ProcessingError::SkippedFile(path));
+ }
+
// Process the view
let warp_file = self.process_view(path, &view);
// Close the view manually, see comment in [`BinaryView`].
@@ -655,6 +670,10 @@ impl WarpFileProcessor {
})
.filter_map(|res| match res {
Ok(result) => Some(Ok(result)),
+ Err(ProcessingError::SkippedFile(path)) => {
+ log::debug!("Skipping directory file: {:?}", path);
+ None
+ }
Err(ProcessingError::Cancelled) => Some(Err(ProcessingError::Cancelled)),
Err(e) => {
log::error!("Directory file processing error: {:?}", e);
@@ -739,21 +758,23 @@ impl WarpFileProcessor {
let mut chunks = Vec::new();
if self.file_data != FileDataKindField::Types {
let mut signature_chunks = self.create_signature_chunks(view)?;
- for (target, signature_chunk) in signature_chunks.drain() {
- if signature_chunk.raw_functions().count() != 0 {
- let chunk = Chunk::new_with_target(
- ChunkKind::Signature(signature_chunk),
- self.compression_type.into(),
- target,
- );
- chunks.push(chunk)
+ for (target, mut target_chunks) in signature_chunks.drain() {
+ for signature_chunk in target_chunks.drain(..) {
+ if signature_chunk.raw_functions().next().is_some() {
+ let chunk = Chunk::new_with_target(
+ ChunkKind::Signature(signature_chunk),
+ self.compression_type.into(),
+ target.clone(),
+ );
+ chunks.push(chunk)
+ }
}
}
}
if self.file_data != FileDataKindField::Signatures {
let type_chunk = self.create_type_chunk(view)?;
- if type_chunk.raw_types().count() != 0 {
+ if type_chunk.raw_types().next().is_some() {
chunks.push(Chunk::new(
ChunkKind::Type(type_chunk),
self.compression_type.into(),
@@ -773,7 +794,7 @@ impl WarpFileProcessor {
pub fn create_signature_chunks(
&self,
view: &BinaryView,
- ) -> Result<HashMap<Target, SignatureChunk<'static>>, ProcessingError> {
+ ) -> Result<HashMap<Target, Vec<SignatureChunk<'static>>>, ProcessingError> {
let is_function_named = |f: &Guard<BNFunction>| {
self.included_functions == IncludedFunctionsField::All
|| view.symbol_by_address(f.start()).is_some()
@@ -836,15 +857,19 @@ impl WarpFileProcessor {
acc
});
- let chunks: Result<HashMap<Target, SignatureChunk<'static>>, ProcessingError> =
+ // Split into multiple chunks if a target has more than MAX_FUNCTIONS_PER_CHUNK functions.
+ // We do this because otherwise some chunks may have too many flatbuffer tables for the verifier to handle.
+ let chunks: Result<HashMap<Target, Vec<SignatureChunk<'static>>>, ProcessingError> =
built_functions
- .into_iter()
+ .into_par_iter()
.map(|(target, functions)| {
- Ok((
- target,
- SignatureChunk::new(&functions)
- .ok_or(ProcessingError::ChunkCreationFailed)?,
- ))
+ let chunks: Result<Vec<_>, _> = functions
+ .par_chunks(MAX_FUNCTIONS_PER_CHUNK)
+ .map(|f| {
+ SignatureChunk::new(&f).ok_or(ProcessingError::ChunkCreationFailed)
+ })
+ .collect();
+ Ok((target, chunks?))
})
.collect();