]> granicus.if.org Git - neomutt/commitdiff
Prevent trying to match a failing color body regex repeatedly
authorKevin McCarthy <kevin@8t8.us>
Mon, 26 Nov 2018 03:48:49 +0000 (19:48 -0800)
committerRichard Russon <rich@flatcap.org>
Mon, 10 Dec 2018 14:04:36 +0000 (14:04 +0000)
Emails with really long lines (e.g. spam), can suffer performance if a
complicated regex is matched to no effect over and over.  If the regex
failed at the beginning, it won't match at the end of another's regex
match range, so turn it off.

mutt_curses.h
pager.c

index d8e8158fcf0f014d6ac7c32d9834df4d160b3ab0..265c53e6665e32e3d86dd825397ca58743fc9902 100644 (file)
@@ -186,6 +186,8 @@ struct ColorLine
   short bg;
   int pair;
   STAILQ_ENTRY(ColorLine) entries;
+
+  bool stop_matching : 1; ///< used by the pager for body patterns, to prevent the color from being retried once it fails
 };
 STAILQ_HEAD(ColorLineHead, ColorLine);
 
diff --git a/pager.c b/pager.c
index 6a74a15ea78c43869678713c2ba5211f7e554ef0..34511ab18599fe6cfdab952413a192ae2692f891 100644 (file)
--- a/pager.c
+++ b/pager.c
@@ -894,6 +894,7 @@ static void resolve_types(char *buf, char *raw, struct Line *line_info, int n,
                           bool *force_redraw, bool q_classify)
 {
   struct ColorLine *color_line = NULL;
+  struct ColorLineHead *head = NULL;
   regmatch_t pmatch[1];
   bool found;
   bool null_rx;
@@ -1012,6 +1013,14 @@ static void resolve_types(char *buf, char *raw, struct Line *line_info, int n,
     i = 0;
     offset = 0;
     line_info[n].chunks = 0;
+    if (line_info[n].type == MT_COLOR_HDEFAULT)
+      head = &ColorHdrList;
+    else
+      head = &ColorBodyList;
+    STAILQ_FOREACH(color_line, head, entries)
+    {
+      color_line->stop_matching = false;
+    }
     do
     {
       if (!buf[offset])
@@ -1019,15 +1028,10 @@ static void resolve_types(char *buf, char *raw, struct Line *line_info, int n,
 
       found = false;
       null_rx = false;
-      struct ColorLineHead *head = NULL;
-      if (line_info[n].type == MT_COLOR_HDEFAULT)
-        head = &ColorHdrList;
-      else
-        head = &ColorBodyList;
       STAILQ_FOREACH(color_line, head, entries)
       {
-        if (regexec(&color_line->regex, buf + offset, 1, pmatch,
-                    (offset ? REG_NOTBOL : 0)) == 0)
+        if (!color_line->stop_matching && regexec(&color_line->regex, buf + offset, 1, pmatch,
+                                                  (offset ? REG_NOTBOL : 0)) == 0)
         {
           if (pmatch[0].rm_eo != pmatch[0].rm_so)
           {
@@ -1063,6 +1067,13 @@ static void resolve_types(char *buf, char *raw, struct Line *line_info, int n,
           else
             null_rx = true; /* empty regex; don't add it, but keep looking */
         }
+        else
+        {
+          /* Once a regexp fails to match, don't try matching it again.
+           * On very long lines this can cause a performance issue if there
+           * are other regexps that have many matches. */
+          color_line->stop_matching = true;
+        }
       }
 
       if (null_rx)