From 916415857f084e63efda03cf25a67fe7f6d24244 Mon Sep 17 00:00:00 2001 From: Andrew Gallant Date: Sun, 12 Oct 2025 14:18:14 -0400 Subject: [PATCH] core: don't build decompression reader unless we intend to use it Building it can consume resources. In particular, on Windows, the various binaries are eagerly resolved. I think this originally wasn't done. The eager resolution was added later for security purposes. But the "eager" part isn't actually necessary. It would probably be better to change the decompression reader to do lazy resolution only when the binary is needed. But this will at least avoid doing anything when the `-z/--search-zip` flag isn't used. But when it is, ripgrep will still eagerly resolve all possible binaries. Fixes #2111 --- crates/core/search.rs | 39 +++++++++++++++++++++------------------ 1 file changed, 21 insertions(+), 18 deletions(-) diff --git a/crates/core/search.rs b/crates/core/search.rs index d03433f6..2fb4cbad 100644 --- a/crates/core/search.rs +++ b/crates/core/search.rs @@ -41,7 +41,6 @@ impl Default for Config { pub(crate) struct SearchWorkerBuilder { config: Config, command_builder: grep::cli::CommandReaderBuilder, - decomp_builder: grep::cli::DecompressionReaderBuilder, } impl Default for SearchWorkerBuilder { @@ -53,17 +52,10 @@ impl Default for SearchWorkerBuilder { impl SearchWorkerBuilder { /// Create a new builder for configuring and constructing a search worker. pub(crate) fn new() -> SearchWorkerBuilder { - let mut cmd_builder = grep::cli::CommandReaderBuilder::new(); - cmd_builder.async_stderr(true); + let mut command_builder = grep::cli::CommandReaderBuilder::new(); + command_builder.async_stderr(true); - let mut decomp_builder = grep::cli::DecompressionReaderBuilder::new(); - decomp_builder.async_stderr(true); - - SearchWorkerBuilder { - config: Config::default(), - command_builder: cmd_builder, - decomp_builder, - } + SearchWorkerBuilder { config: Config::default(), command_builder } } /// Create a new search worker using the given searcher, matcher and @@ -76,7 +68,12 @@ impl SearchWorkerBuilder { ) -> SearchWorker { let config = self.config.clone(); let command_builder = self.command_builder.clone(); - let decomp_builder = self.decomp_builder.clone(); + let decomp_builder = config.search_zip.then(|| { + let mut decomp_builder = + grep::cli::DecompressionReaderBuilder::new(); + decomp_builder.async_stderr(true); + decomp_builder + }); SearchWorker { config, command_builder, @@ -233,7 +230,11 @@ impl Printer { pub(crate) struct SearchWorker { config: Config, command_builder: grep::cli::CommandReaderBuilder, - decomp_builder: grep::cli::DecompressionReaderBuilder, + /// This is `None` when `search_zip` is not enabled, since in this case it + /// can never be used. We do this because building the reader can sometimes + /// do non-trivial work (like resolving the paths of decompression binaries + /// on Windows). + decomp_builder: Option, matcher: PatternMatcher, searcher: grep::searcher::Searcher, printer: Printer, @@ -273,10 +274,9 @@ impl SearchWorker { /// Returns true if and only if the given file path should be /// decompressed before searching. fn should_decompress(&self, path: &Path) -> bool { - if !self.config.search_zip { - return false; - } - self.decomp_builder.get_matcher().has_command(path) + self.decomp_builder.as_ref().is_some_and(|decomp_builder| { + decomp_builder.get_matcher().has_command(path) + }) } /// Returns true if and only if the given file path should be run through @@ -327,7 +327,10 @@ impl SearchWorker { /// result. If the given file path isn't recognized as a compressed file, /// then search it without doing any decompression. fn search_decompress(&mut self, path: &Path) -> io::Result { - let mut rdr = self.decomp_builder.build(path)?; + let Some(ref decomp_builder) = self.decomp_builder else { + return self.search_path(path); + }; + let mut rdr = decomp_builder.build(path)?; let result = self.search_reader(path, &mut rdr); let close_result = rdr.close(); let search_result = result?;