Skip to content

Commit 595a2bd

Browse files
committed
chore(capi+go): don't enable rules profiling by default.
Also improves the profiling-related documentation in the Go library.
1 parent fef1c63 commit 595a2bd

File tree

6 files changed

+70
-54
lines changed

6 files changed

+70
-54
lines changed

capi/Cargo.toml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ homepage.workspace = true
1212

1313
[features]
1414
# The `capi` feature is required by `cargo-c`.
15-
default = ["capi", "rules-profiling"]
15+
default = ["capi"]
1616
capi = []
1717

1818
# When enabled, the serialization of compiled rules include native code for
@@ -29,7 +29,7 @@ native-code-serialization = ["yara-x/native-code-serialization"]
2929

3030
# Enables rules profiling.
3131
#
32-
# This feature is enabled by default.
32+
# This feature is disabled by default.
3333
rules-profiling = ["yara-x/rules-profiling"]
3434

3535

capi/include/yara_x.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,9 @@ typedef enum YRX_RESULT {
8080
SERIALIZATION_ERROR,
8181
// An error returned when a rule doesn't have any metadata.
8282
NO_METADATA,
83+
// An error returned in cases where some API is not supported because the
84+
// library was not built with the required features.
85+
NOT_SUPPORTED,
8386
} YRX_RESULT;
8487

8588
// A compiler that takes YARA source code and produces compiled rules.
@@ -708,7 +711,7 @@ enum YRX_RESULT yrx_scanner_set_global_float(struct YRX_SCANNER *scanner,
708711
// Iterates over the top N most expensive rules, calling the callback for
709712
// each rule.
710713
//
711-
// Requires the `rules-profiling` feature.
714+
// Requires the `rules-profiling` feature, otherwise the
712715
//
713716
// See [`YRX_MOST_EXPENSIVE_RULES_CALLBACK`] for more details.
714717
enum YRX_RESULT yrx_scanner_iter_most_expensive_rules(struct YRX_SCANNER *scanner,

capi/src/lib.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -152,6 +152,9 @@ pub enum YRX_RESULT {
152152
SERIALIZATION_ERROR,
153153
/// An error returned when a rule doesn't have any metadata.
154154
NO_METADATA,
155+
/// An error returned in cases where some API is not supported because the
156+
/// library was not built with the required features.
157+
NOT_SUPPORTED,
155158
}
156159

157160
/// Returns the error message for the most recent function in this API

capi/src/scanner.rs

Lines changed: 40 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -61,11 +61,11 @@ pub unsafe extern "C" fn yrx_scanner_set_timeout(
6161
scanner: *mut YRX_SCANNER,
6262
timeout: u64,
6363
) -> YRX_RESULT {
64-
if scanner.is_null() {
65-
return YRX_RESULT::INVALID_ARGUMENT;
66-
}
64+
let scanner = match scanner.as_mut() {
65+
Some(s) => s,
66+
None => return YRX_RESULT::INVALID_ARGUMENT,
67+
};
6768

68-
let scanner = scanner.as_mut().unwrap();
6969
scanner.inner.set_timeout(Duration::from_secs(timeout));
7070

7171
YRX_RESULT::SUCCESS
@@ -84,16 +84,16 @@ pub unsafe extern "C" fn yrx_scanner_scan(
8484
) -> YRX_RESULT {
8585
_yrx_set_last_error::<ScanError>(None);
8686

87-
if scanner.is_null() {
88-
return YRX_RESULT::INVALID_ARGUMENT;
89-
}
87+
let scanner = match scanner.as_mut() {
88+
Some(s) => s,
89+
None => return YRX_RESULT::INVALID_ARGUMENT,
90+
};
9091

9192
let data = match slice_from_ptr_and_len(data, len) {
9293
Some(data) => data,
9394
None => return YRX_RESULT::INVALID_ARGUMENT,
9495
};
9596

96-
let scanner = scanner.as_mut().unwrap();
9797
let scan_results = scanner.inner.scan(data);
9898

9999
if let Err(err) = scan_results {
@@ -178,9 +178,10 @@ pub unsafe extern "C" fn yrx_scanner_set_module_output(
178178
data: *const u8,
179179
len: usize,
180180
) -> YRX_RESULT {
181-
if scanner.is_null() {
182-
return YRX_RESULT::INVALID_ARGUMENT;
183-
}
181+
let scanner = match scanner.as_mut() {
182+
Some(s) => s,
183+
None => return YRX_RESULT::INVALID_ARGUMENT,
184+
};
184185

185186
let module_name = match CStr::from_ptr(name).to_str() {
186187
Ok(name) => name,
@@ -195,8 +196,6 @@ pub unsafe extern "C" fn yrx_scanner_set_module_output(
195196
None => return YRX_RESULT::INVALID_ARGUMENT,
196197
};
197198

198-
let scanner = scanner.as_mut().unwrap();
199-
200199
match scanner.inner.set_module_output_raw(module_name, data) {
201200
Ok(_) => {
202201
_yrx_set_last_error::<ScanError>(None);
@@ -216,9 +215,10 @@ unsafe extern "C" fn yrx_scanner_set_global<
216215
ident: *const c_char,
217216
value: T,
218217
) -> YRX_RESULT {
219-
if scanner.is_null() {
220-
return YRX_RESULT::INVALID_ARGUMENT;
221-
}
218+
let scanner = match scanner.as_mut() {
219+
Some(s) => s,
220+
None => return YRX_RESULT::INVALID_ARGUMENT,
221+
};
222222

223223
let ident = match CStr::from_ptr(ident).to_str() {
224224
Ok(ident) => ident,
@@ -228,8 +228,6 @@ unsafe extern "C" fn yrx_scanner_set_global<
228228
}
229229
};
230230

231-
let scanner = scanner.as_mut().unwrap();
232-
233231
match scanner.inner.set_global(ident, value) {
234232
Ok(_) => {
235233
_yrx_set_last_error::<ScanError>(None);
@@ -327,35 +325,40 @@ pub type YRX_MOST_EXPENSIVE_RULES_CALLBACK = extern "C" fn(
327325
/// Iterates over the top N most expensive rules, calling the callback for
328326
/// each rule.
329327
///
330-
/// Requires the `rules-profiling` feature.
328+
/// Requires the `rules-profiling` feature, otherwise the
331329
///
332330
/// See [`YRX_MOST_EXPENSIVE_RULES_CALLBACK`] for more details.
333-
#[cfg(feature = "rules-profiling")]
334331
#[no_mangle]
332+
#[allow(unused_variables)]
335333
pub unsafe extern "C" fn yrx_scanner_iter_most_expensive_rules(
336334
scanner: *mut YRX_SCANNER,
337335
n: usize,
338336
callback: YRX_MOST_EXPENSIVE_RULES_CALLBACK,
339337
user_data: *mut c_void,
340338
) -> YRX_RESULT {
341-
if scanner.is_null() {
342-
return YRX_RESULT::INVALID_ARGUMENT;
343-
}
344-
345-
let scanner = scanner.as_ref().unwrap();
339+
#[cfg(not(feature = "rules-profiling"))]
340+
return YRX_RESULT::NOT_SUPPORTED;
341+
342+
#[cfg(feature = "rules-profiling")]
343+
{
344+
let scanner = match scanner.as_ref() {
345+
Some(s) => s,
346+
None => return YRX_RESULT::INVALID_ARGUMENT,
347+
};
346348

347-
for profiling_info in scanner.inner.most_expensive_rules(n) {
348-
let namespace = CString::new(profiling_info.namespace).unwrap();
349-
let rule = CString::new(profiling_info.rule).unwrap();
349+
for profiling_info in scanner.inner.most_expensive_rules(n) {
350+
let namespace = CString::new(profiling_info.namespace).unwrap();
351+
let rule = CString::new(profiling_info.rule).unwrap();
352+
353+
callback(
354+
namespace.as_ptr(),
355+
rule.as_ptr(),
356+
profiling_info.pattern_matching_time.as_secs_f64(),
357+
profiling_info.condition_exec_time.as_secs_f64(),
358+
user_data,
359+
);
360+
}
350361

351-
callback(
352-
namespace.as_ptr(),
353-
rule.as_ptr(),
354-
profiling_info.pattern_matching_time.as_secs_f64(),
355-
profiling_info.condition_exec_time.as_secs_f64(),
356-
user_data,
357-
);
362+
YRX_RESULT::SUCCESS
358363
}
359-
360-
YRX_RESULT::SUCCESS
361364
}

go/scanner.go

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -247,6 +247,13 @@ func (s *Scanner) Scan(buf []byte) (*ScanResults, error) {
247247
return scanResults, err
248248
}
249249

250+
// ProfilingInfo contains profiling information about a YARA rule.
251+
//
252+
// For each rule it contains: the rule's namespace, the rule's name,
253+
// the time spent in matching patterns declared by the rule, and the time
254+
// spent evaluating the rule's condition.
255+
//
256+
// See [Scanner.MostExpensiveRules].
250257
type ProfilingInfo struct {
251258
Namespace string
252259
Rule string
@@ -276,16 +283,28 @@ func mostExpensiveRulesCallback(
276283
})
277284
}
278285

286+
// MostExpensiveRules returns information about the slowest rules and how much
287+
// time they spent matching patterns and executing their conditions.
288+
//
289+
// In order to use this function the YARA-X C library must be built with
290+
// support for rules profiling, which is done by enabling the `rules-profiling`
291+
// feature. Otherwise, calling this function will cause a panic.
279292
func (s *Scanner) MostExpensiveRules(n int) []ProfilingInfo {
280293
profilingInfo := make([]ProfilingInfo, 0)
281294
mostExpensiveRules := cgo.NewHandle(&profilingInfo)
282295
defer mostExpensiveRules.Delete()
283296

284-
if C._yrx_scanner_iter_most_expensive_rules(
297+
result := C._yrx_scanner_iter_most_expensive_rules(
285298
s.cScanner,
286299
C.size_t(n),
287300
C.YRX_MOST_EXPENSIVE_RULES_CALLBACK(C.mostExpensiveRulesCallback),
288-
C.uintptr_t(mostExpensiveRules)) != C.SUCCESS {
301+
C.uintptr_t(mostExpensiveRules))
302+
303+
if result == C.NOT_SUPPORTED {
304+
panic("MostExpensiveRules requires that the YARA-X C library is built with the `rules-profiling` feature")
305+
}
306+
307+
if result != C.SUCCESS {
289308
panic("yrx_scanner_iter_most_expensive_rules failed")
290309
}
291310

go/scanner_test.go

Lines changed: 0 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -91,18 +91,6 @@ func TestScannerTimeout(t *testing.T) {
9191
assert.ErrorIs(t, err, ErrTimeout)
9292
}
9393

94-
func TestScannerMostExpensiveRules(t *testing.T) {
95-
r, _ := Compile("rule t { strings: $a = /a(.*)*a/ condition: $a }")
96-
s := NewScanner(r)
97-
_, err := s.Scan(bytes.Repeat([]byte("a"), 5000))
98-
assert.NoError(t, err)
99-
profilingInfo := s.MostExpensiveRules(1)
100-
assert.Equal(t, "t", profilingInfo[0].Rule)
101-
assert.Equal(t, "default", profilingInfo[0].Namespace)
102-
assert.Greater(t, profilingInfo[0].PatternMatchingTime, time.Duration(0))
103-
assert.Greater(t, profilingInfo[0].ConditionExecTime, time.Duration(0))
104-
}
105-
10694
func TestScannerMetadata(t *testing.T) {
10795
r, _ := Compile(`rule t {
10896
meta:

0 commit comments

Comments
 (0)