From 021c352651340224487d465143a390e5eda71fa2 Mon Sep 17 00:00:00 2001
From: Wesley Shields <wxs@atarininja.org>
Date: Fri, 12 Mar 2021 03:40:59 -0500
Subject: [PATCH] Improve callback function performance and fix build on MacOS (#175)

* When building on macos I noticed that libcrypto was not found when using
has_function(). This is because the compiler used to compile the check program
is not being told about the library and include paths. Fix it by passing those
into the has_function() check where appropriate.

* Improve callback performance for non-matching case.
---
 setup.py      | 14 +++++++++-----
 yara-python.c | 17 ++++++++++++++++-
 2 files changed, 25 insertions(+), 6 deletions(-)

diff --git a/setup.py b/setup.py
index fddb16d..9593cb0 100644
--- a/setup.py
+++ b/setup.py
@@ -76,12 +76,15 @@ def muted(*streams):
     devnull.close()
 
 
-def has_function(function_name, libraries=None):
+def has_function(function_name, include_dirs=None, libraries=None, library_dirs=None):
   """Checks if a given functions exists in the current platform."""
   compiler = distutils.ccompiler.new_compiler()
   with muted(sys.stdout, sys.stderr):
-    result = compiler.has_function(
-        function_name, libraries=libraries)
+      result = compiler.has_function(
+          function_name,
+          include_dirs=include_dirs,
+          libraries=libraries,
+          library_dirs=library_dirs)
   if os.path.exists('a.out'):
     os.remove('a.out')
   return result
@@ -218,6 +221,7 @@ class BuildExtCommand(build_ext):
       module.library_dirs.append('/opt/local/lib')
       module.include_dirs.append('/usr/local/include')
       module.library_dirs.append('/usr/local/lib')
+      module.library_dirs.append('/usr/local/opt/openssl/lib')
     elif building_for_freebsd:
       module.define_macros.append(('_GNU_SOURCE', '1'))
       module.define_macros.append(('USE_FREEBSD_PROC', '1'))
@@ -255,8 +259,8 @@ class BuildExtCommand(build_ext):
       module.libraries.append('yara')
     else:
       if not self.define or not ('HASH_MODULE', '1') in self.define:
-        if (has_function('MD5_Init', libraries=['crypto']) and
-            has_function('SHA256_Init', libraries=['crypto'])):
+        if (has_function('MD5_Init', include_dirs=module.include_dirs, libraries=['crypto'], library_dirs=module.library_dirs) and
+            has_function('SHA256_Init', include_dirs=module.include_dirs, libraries=['crypto'], library_dirs=module.library_dirs)):
           module.define_macros.append(('HASH_MODULE', '1'))
           module.define_macros.append(('HAVE_LIBCRYPTO', '1'))
           module.libraries.append('crypto')
diff --git a/yara-python.c b/yara-python.c
index 3d6ffce..d43039e 100644
--- a/yara-python.c
+++ b/yara-python.c
@@ -623,6 +623,13 @@ int yara_callback(
 
   int result = CALLBACK_CONTINUE;
 
+  // If the rule doesn't match and the user has not specified that they want to
+  // see non-matches then nothing to do here.
+  if (message == CALLBACK_MSG_RULE_NOT_MATCHING &&
+      callback != NULL &&
+      (which & CALLBACK_NON_MATCHES) != CALLBACK_NON_MATCHES)
+    return CALLBACK_CONTINUE;
+
   if (message == CALLBACK_MSG_SCAN_FINISHED)
     return CALLBACK_CONTINUE;
 
@@ -788,7 +795,15 @@ int yara_callback(
     }
   }
 
-
+  // At this point we have handled all the other cases of when this callback
+  // can be called. The only things left are:
+  //
+  // 1. A matching rule.
+  //
+  // 2 A non-matching rule and the user has requested to see non-matching rules.
+  //
+  // In both cases, we need to create the data that will be either passed back
+  // to the python callback or stored in the matches list.
   rule = (YR_RULE*) message_data;
 
   gil_state = PyGILState_Ensure();
--
libgit2 0.26.0