]> git.ipfire.org Git - thirdparty/rrdtool-1.x.git/commitdiff
issue #914, rrdtool graph with --title segfaults and misparses single-line args
authorAlexander Zangerl <alexz@opmantek.com>
Tue, 30 Oct 2018 04:49:58 +0000 (14:49 +1000)
committerTobias Oetiker <tobi@oetiker.ch>
Thu, 1 Nov 2018 10:41:22 +0000 (11:41 +0100)
reworked graph_title_split() to not segfault,
to handle leading/trailing/duplicate delimiters, and to produce the
appropriate number of output lines.

code now works and properly handles nasties
like --title '\n\none\n\nfourtyseven\n'

src/rrd_graph.c

index 99f135b08b62c342ec9f7d6f3cf70911606e5cb3..108891fc97a35827995d3aba08873705b3c81389 100644 (file)
@@ -6178,50 +6178,61 @@ image_title_t graph_title_split(
     const char *title)
 {
     image_title_t retval;
-    int start = 0;
-    int length = 0;
-    int pos = 0;
-    int count = 0;
-    int delim = 1;
+    int count = 0;              /* line count */
+    int found_delim;
 
     retval.lines = malloc((MAX_IMAGE_TITLE_LINES + 1 ) * sizeof(char *));
-    length = strlen(title);
 
-    char *delims[6] = { "\n", "\\n", "<br>", "<br/>" };
-    printf("title: %s\n", title);
+    char *delims[4] = { "\n", "\\n", "<br>", "<br/>" };
+    // printf("unsplit title: %s\n", title);
+
+    char *consumed = strdup(title); /* allocates copy */
     do
     {
-        pos = 0;
-        delim = 0;
-
-        while (delim == 0 && start + pos < length) {
-            for(int i=0; i<4;i++) {
-                int delim_size = strlen(delims[i]);
-                int delim_match = strncasecmp(title+start+pos, delims[i], delim_size);
-
-                //printf("Comparing '%s' with '%s' (%d=%d from %d) = %d\n",
-                //    title+start+pos, delims[i], i, delim_size, start+pos, delim_match);
-                if (delim_match == 0) {
-                    delim = delim_size;
-                    break;
-                }
-            }
-
-            pos++;
-        }
-
-        if (pos != 0)
-        {
-            char *str = substring(title, start, pos - 1);
-            //printf("str: %s (%d - %d)\n", str, start, pos);
-            retval.lines[count] = str;
-        }
+       /*
+         search for next delimiter occurrence in the title,
+         if found, save the string before the delimiter for the next line & search the remainder
+
+         note: this logic cannot work if the title contains different delimiters,
+         as there's no guarantee that we'll find the earliest delimiter first!
+       */
+       found_delim = 0;
+       for(unsigned int i=0; i < 4; i++)
+       {
+          // printf("looking for delim '%s', in '%s'\n", delims[i], consumed);
+          int delim_size = strlen(delims[i]);
+
+          char *delimloc = strstr(consumed, delims[i]);
+          if (delimloc)
+          {
+             /* ignore an empty line caused by a leading delimiter (or two in a row) */
+             if (delimloc != consumed)
+             {
+                *delimloc = '\0'; /* split the string where the delimiter starts*/
+                retval.lines[count] = consumed; /* strdup allocated space for us, reuse that */
+
+                // printf("found delim '%s', line %d split after '%s', rest is '%s'\n",
+                //       delims[i], count, consumed, delimloc+delim_size);
+                ++count;
+             }
+             consumed = delimloc + delim_size;
+             found_delim = 1;
+             break;             /* try all delims on the remainder */
+          }
+       }
+    }
+    /* must not create more than MAX lines, so must stop splitting one short... */
+    while (found_delim && count < MAX_IMAGE_TITLE_LINES-1);
 
-        start = start + pos + delim - 1;
-        count++;
+    /* ...so that (unsplittable) remainder goes into the final line */
+    if (strlen(consumed))
+    {
+       retval.lines[count] = consumed;
+       // printf("found nothing more, line %d is now '%s'\n", count, consumed);
+       ++count;
     }
-    while (pos != 0 && retval.lines[count] != NULL && count < MAX_IMAGE_TITLE_LINES);
 
+//    printf("final line count is %d\n", count);
     retval.lines[count] = NULL;
     retval.count = count;