Skip to content

Commit e14f096

Browse files
authored
Add a "warnings" member to Rules. (VirusTotal#208)
When compiling rules that have warnings currently the only way to know they have warnings is to specify error_on_warning=True to yara.compile(). This will throw an exception that you can then check the warnings member of, like this: ``` r = 'rule a { strings: $a = "a" condition: $a } rule b { strings: $b = "b" condition: $b }' try: rules = yara.compile(source=r, error_on_warning=True) except yara.WarningError as e: print(e.warnings) ``` This stops the compilation process, so if you're trying to just know if there are warnings but still run the rules there is no good way to do it without using the exception mechanism and then compiling the rules a second time (with error_on_warning not set). This patch adds a warnings member to the compiled Rules object, which is always set to a list of warning strings. If you want to error on warning you can still use error_on_warning=True in yara.compile() and get the normal behavior, but if you just want to compile and know if there are warnings you can now use this new member without having to compile a second time. Suggested by: Tom Lancaster Fixes: VirusTotal#207
1 parent 0a8659d commit e14f096

File tree

2 files changed

+41
-3
lines changed

2 files changed

+41
-3
lines changed

tests.py

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1132,6 +1132,31 @@ def testWarningCallback(self):
11321132
self.assertTrue(warnings_callback_message.rule == "x")
11331133
self.assertTrue(warnings_callback_message.string == "$x")
11341134

1135+
def testCompilerErrorOnWarning(self):
1136+
# Make sure we always throw on warnings if requested, and that warnings
1137+
# are accumulated.
1138+
1139+
rules = """
1140+
rule a { strings: $a = "A" condition: $a }
1141+
rule b { strings: $b = "B" condition: $b }
1142+
"""
1143+
1144+
expected = [
1145+
'line 2: string "$a" may slow down scanning',
1146+
'line 3: string "$b" may slow down scanning',
1147+
]
1148+
1149+
with self.assertRaises(yara.WarningError) as ctx:
1150+
yara.compile(source=rules, error_on_warning=True)
1151+
1152+
e = ctx.exception
1153+
self.assertListEqual(e.warnings, expected)
1154+
1155+
# Now make sure the warnings member is set if error_on_warning is not
1156+
# set.
1157+
rules = yara.compile(source=rules)
1158+
self.assertListEqual(rules.warnings, expected)
1159+
11351160

11361161
if __name__ == "__main__":
11371162
unittest.main()

yara-python.c

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -316,6 +316,7 @@ typedef struct
316316
{
317317
PyObject_HEAD
318318
PyObject* externals;
319+
PyObject* warnings;
319320
YR_RULES* rules;
320321
YR_RULE* iter_current_rule;
321322
} Rules;
@@ -347,6 +348,17 @@ static PyObject* Rules_getattro(
347348
static PyObject* Rules_next(
348349
PyObject* self);
349350

351+
static PyMemberDef Rules_members[] = {
352+
{
353+
"warnings",
354+
T_OBJECT_EX,
355+
offsetof(Rules, warnings),
356+
READONLY,
357+
"List of compiler warnings"
358+
},
359+
{ NULL } // End marker
360+
};
361+
350362
static PyMethodDef Rules_methods[] =
351363
{
352364
{
@@ -399,7 +411,7 @@ static PyTypeObject Rules_Type = {
399411
PyObject_SelfIter, /* tp_iter */
400412
(iternextfunc) Rules_next, /* tp_iternext */
401413
Rules_methods, /* tp_methods */
402-
0, /* tp_members */
414+
Rules_members, /* tp_members */
403415
0, /* tp_getset */
404416
0, /* tp_base */
405417
0, /* tp_dict */
@@ -1517,6 +1529,7 @@ static Rules* Rules_NEW(void)
15171529
{
15181530
rules->rules = NULL;
15191531
rules->externals = NULL;
1532+
rules->warnings = NULL;
15201533
}
15211534

15221535
return rules;
@@ -1528,6 +1541,7 @@ static void Rules_dealloc(
15281541
Rules* object = (Rules*) self;
15291542

15301543
Py_XDECREF(object->externals);
1544+
Py_XDECREF(object->warnings);
15311545

15321546
if (object->rules != NULL)
15331547
yr_rules_destroy(object->rules);
@@ -2435,8 +2449,6 @@ static PyObject* yara_compile(
24352449
PyErr_SetObject(YaraWarningError, warnings);
24362450
}
24372451

2438-
Py_DECREF(warnings);
2439-
24402452
if (PyErr_Occurred() == NULL)
24412453
{
24422454
rules = Rules_NEW();
@@ -2451,6 +2463,7 @@ static PyObject* yara_compile(
24512463
{
24522464
rules->rules = yara_rules;
24532465
rules->iter_current_rule = rules->rules->rules_table;
2466+
rules->warnings = warnings;
24542467

24552468
if (externals != NULL && externals != Py_None)
24562469
rules->externals = PyDict_Copy(externals);

0 commit comments

Comments
 (0)