Unverified Commit e14f096e by Wesley Shields Committed by GitHub

Add a "warnings" member to Rules. (#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: #207
parent 0a8659d6
......@@ -1132,6 +1132,31 @@ class TestYara(unittest.TestCase):
self.assertTrue(warnings_callback_message.rule == "x")
self.assertTrue(warnings_callback_message.string == "$x")
def testCompilerErrorOnWarning(self):
# Make sure we always throw on warnings if requested, and that warnings
# are accumulated.
rules = """
rule a { strings: $a = "A" condition: $a }
rule b { strings: $b = "B" condition: $b }
"""
expected = [
'line 2: string "$a" may slow down scanning',
'line 3: string "$b" may slow down scanning',
]
with self.assertRaises(yara.WarningError) as ctx:
yara.compile(source=rules, error_on_warning=True)
e = ctx.exception
self.assertListEqual(e.warnings, expected)
# Now make sure the warnings member is set if error_on_warning is not
# set.
rules = yara.compile(source=rules)
self.assertListEqual(rules.warnings, expected)
if __name__ == "__main__":
unittest.main()
......@@ -316,6 +316,7 @@ typedef struct
{
PyObject_HEAD
PyObject* externals;
PyObject* warnings;
YR_RULES* rules;
YR_RULE* iter_current_rule;
} Rules;
......@@ -347,6 +348,17 @@ static PyObject* Rules_getattro(
static PyObject* Rules_next(
PyObject* self);
static PyMemberDef Rules_members[] = {
{
"warnings",
T_OBJECT_EX,
offsetof(Rules, warnings),
READONLY,
"List of compiler warnings"
},
{ NULL } // End marker
};
static PyMethodDef Rules_methods[] =
{
{
......@@ -399,7 +411,7 @@ static PyTypeObject Rules_Type = {
PyObject_SelfIter, /* tp_iter */
(iternextfunc) Rules_next, /* tp_iternext */
Rules_methods, /* tp_methods */
0, /* tp_members */
Rules_members, /* tp_members */
0, /* tp_getset */
0, /* tp_base */
0, /* tp_dict */
......@@ -1517,6 +1529,7 @@ static Rules* Rules_NEW(void)
{
rules->rules = NULL;
rules->externals = NULL;
rules->warnings = NULL;
}
return rules;
......@@ -1528,6 +1541,7 @@ static void Rules_dealloc(
Rules* object = (Rules*) self;
Py_XDECREF(object->externals);
Py_XDECREF(object->warnings);
if (object->rules != NULL)
yr_rules_destroy(object->rules);
......@@ -2435,8 +2449,6 @@ static PyObject* yara_compile(
PyErr_SetObject(YaraWarningError, warnings);
}
Py_DECREF(warnings);
if (PyErr_Occurred() == NULL)
{
rules = Rules_NEW();
......@@ -2451,6 +2463,7 @@ static PyObject* yara_compile(
{
rules->rules = yara_rules;
rules->iter_current_rule = rules->rules->rules_table;
rules->warnings = warnings;
if (externals != NULL && externals != Py_None)
rules->externals = PyDict_Copy(externals);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment