Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion capi/include/yara_x.h
Original file line number Diff line number Diff line change
Expand Up @@ -710,7 +710,7 @@ enum YRX_RESULT yrx_scanner_set_timeout(struct YRX_SCANNER *scanner,
// check `$a`).
//
// Note that using fast scan mode implies that not all matches will be
// reported. For instance, when iterating matches using [`ScanResults`],
// reported. For instance, when iterating matches using [`yara_x::ScanResults`],
// you won't get all occurrences of the pattern in the file, only the first
// one.
enum YRX_RESULT yrx_scanner_fast_scan(struct YRX_SCANNER *scanner,
Expand Down
2 changes: 1 addition & 1 deletion capi/src/scanner.rs
Original file line number Diff line number Diff line change
Expand Up @@ -173,7 +173,7 @@ pub unsafe extern "C" fn yrx_scanner_set_timeout(
/// check `$a`).
///
/// Note that using fast scan mode implies that not all matches will be
/// reported. For instance, when iterating matches using [`ScanResults`],
/// reported. For instance, when iterating matches using [`yara_x::ScanResults`],
/// you won't get all occurrences of the pattern in the file, only the first
/// one.
#[unsafe(no_mangle)]
Expand Down
6 changes: 5 additions & 1 deletion lib/src/models.rs
Original file line number Diff line number Diff line change
Expand Up @@ -374,6 +374,10 @@ impl<'a, 'r> Pattern<'a, 'r> {
}

/// Returns the matches found for this pattern.
///
/// The returned matches are affected by [`crate::Scanner::fast_scan`].
/// If fast scan mode is enabled, not all matches are guaranteed to be
/// returned.
pub fn matches(&self) -> Matches<'a, 'r> {
Matches {
ctx: self.ctx,
Expand Down Expand Up @@ -451,7 +455,7 @@ impl<'a> Match<'a, '_> {
/// and some extra bytes at its left and right. The returned range indicates
/// the portion of the slice that corresponds to the match itself.
///
/// Calling this function only makes sense if [`Scanner::match_context_size`]
/// Calling this function only makes sense if [`crate::Scanner::match_context_size`]
/// is used for indicating how many bytes at the left and right of each
/// match are desired. Otherwise, this function will return the same result
/// as [`Match::data`].
Expand Down
47 changes: 44 additions & 3 deletions lib/src/scanner/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -229,14 +229,55 @@ impl<'r> Scanner<'r> {

/// Enables or disables fast scan mode.
///
/// In fast scan mode, the scanner avoids tracking matches for patterns
/// when it is not necessary (e.g. when a rule condition only performs a
/// simple boolean check `$a`).
/// During rule compilation, the compiler analyzes rule conditions to
/// identify patterns that are only ever used in simple boolean existence
/// checks (e.g., `$a` in YARA). If a pattern is never queried for its match
/// count (`#a`), specific match offset (`@a`), match length (`!a`), or
/// evaluated inside a loop, it is classified as a fast-scan pattern.
///
/// In fast scan mode, the scanner optimizes scans by stopping the search
/// and match tracking for these fast-scan patterns once their **very first
/// match** is found. Subsequent occurrences in the input data are ignored,
/// preventing redundant Aho-Corasick scans, regex evaluations, and match
/// memory allocations.
///
/// Note that using fast scan mode implies that not all matches will be
/// reported. For instance, when iterating matches using [`ScanResults`],
/// you won't get all occurrences of the pattern in the file, only the first
/// one.
///
/// ### Example
///
/// ```
/// # use yara_x::{Compiler, Scanner};
/// let mut compiler = Compiler::new();
/// compiler.add_source(r#"
/// rule test {
/// strings:
/// $a = "abc"
/// condition:
/// $a
/// }
/// "#).unwrap();
///
/// let rules = compiler.build();
/// let mut scanner = Scanner::new(&rules);
///
/// // Enable fast scan mode.
/// scanner.fast_scan(true);
///
/// // The haystack contains two matches of "abc".
/// let results = scanner.scan(b"abc...abc").unwrap();
///
/// // Find the matching rule.
/// let matching_rule = results.matching_rules().next().unwrap();
///
/// // Only a single match is returned for pattern $a.
/// let pattern = matching_rule.patterns().next().unwrap();
/// let mut matches = pattern.matches();
/// assert_eq!(matches.next().unwrap().range().start, 0); // The first match
/// assert!(matches.next().is_none()); // No other matches are returned
/// ```
pub fn fast_scan(&mut self, yes: bool) -> &mut Self {
self.scan_context_mut().tracker.fast_scan = yes;
self
Expand Down
2 changes: 1 addition & 1 deletion lib/src/teddy/mod.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/*! Teddy is a SIMD accelerated multiple substring matching algorithm.

This implementation was taken from https://github.com/BurntSushi/aho-corasick
This implementation was taken from <https://github.com/BurntSushi/aho-corasick>
with minor modifications.

*/
Expand Down
Loading