[tex-live] pdftex segfault with \pdflastmatch

Karl Berry karl at freefriends.org
Sun Jun 12 20:19:59 CEST 2016


    dc> This plain tex document demonstrates \pdflastmatch failing if
    dc> used after a \pdfmatch that returned no matches.

Thanks for the report, of course, though it's sad.

    ak> The crash disappears if I apply an attached utils.c.diff.
    ak> But I don't know that the patch is right or not.

I was still seeing garbage for the position reported by \pdflastmatch
unless I added an explicit check (and variable) for whether the
preceding match succeeded.  (Because otherwise the various arrays are
accessed without necessarily being set.)

Patch (minus the documentation, etc.) below; I installed it in pdftex
and TL.  Akira (or anyone), let me know you see problems with it.

Thanks,
Karl

My test file (with the example from the pdftex manual):

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% This file public domain.  Bug report of \pdflastmatch crash:
% http://tug.org/pipermail/tex-live/2016-June/038664.html
%
\catcode`\{=1 \catcode`\}=2 \catcode`^=7 \newlinechar=`^^J
%
\message{^^Jpdflastmatch0 before any match: \pdflastmatch0}
\message{^^J}%
%
\message{^^Jmatch a to b: \pdfmatch{a}{b}}
\message{^^J}%
\message{pdflastmatch0: \pdflastmatch0}
\message{^^J}%
%
\message{^^Jmatch example: \pdfmatch subcount 3 {ab(cd)*ef(gh)(ij)}{abefghij}}
\message{^^J}%
\message{pdflastmatch0 (0->abefghij): \pdflastmatch0 ^^J}
\message{pdflastmatch1 (-1->): \pdflastmatch1 ^^J}
\message{pdflastmatch2 (4->gh): \pdflastmatch2 ^^J}
\message{pdflastmatch3 (-1->): \pdflastmatch3}
\message{^^J}%
\end
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%


And the patch:

--- pdftexdir/utils.c	(revision 757)
+++ pdftexdir/utils.c	(working copy)
@@ -817,12 +817,16 @@
     pdf_printf("/ModDate (%s)\n", start_time_str);
 }
 
+
 #define DEFAULT_SUB_MATCH_COUNT 10
 static int sub_match_count = DEFAULT_SUB_MATCH_COUNT;
 static regmatch_t *pmatch = NULL;
 static char *match_string = NULL;
+static int last_match_succeeded = 0;
 
-void matchstrings(strnumber s, strnumber t, int subcount, boolean icase)
+/* Implements \pdfmatch */
+void
+matchstrings(strnumber s, strnumber t, int subcount, boolean icase)
 {
     regex_t preg;
     int cflags = REG_EXTENDED;
@@ -857,20 +861,31 @@
             pmatch = xtalloc(sub_match_count, regmatch_t);
         }
         ret = regexec(&preg, str, sub_match_count, pmatch, eflags);
+        
         xfree(match_string);
-        match_string = xstrdup(str);
-        strpool[poolptr++] = ((ret == 0) ? '1' : '0');
+        match_string = xstrdup(str);  /* save searched-in string, used below */
+        last_match_succeeded = ret == 0;     /* save whether match succeeded */
+        strpool[poolptr++] = ((ret == 0) ? '1' : '0'); /* in string pool too */
     }
 
     regfree(&preg);
 }
 
-void getmatch(int i)
+/* Implements \pdflastmatch */
+
+void
+getmatch(int i)
 {
-    int size, len = 0;          /* to avoid warning about uninitialized use of len */
+    int size;
+    int len = 0;                /* avoid spurious uninitialized warning */
 
-    boolean found = i < sub_match_count
-        && match_string != NULL && pmatch[i].rm_so >= 0 && i >= 0;
+    boolean found
+      = i >= 0                  /* should always be so due to pdftex.web */
+        && i < sub_match_count  /* if >subcount, not found by definition */
+        && match_string != NULL /* first call, and just in case */
+        && last_match_succeeded /* if no match, not found */
+        && pmatch[i].rm_so >= 0 /* if no starting position, not found */
+        && pmatch[i].rm_eo >= pmatch[i].rm_so; /* just in case */
 
     if (found) {
         len = pmatch[i].rm_eo - pmatch[i].rm_so;


More information about the tex-live mailing list