]> granicus.if.org Git - graphviz/commitdiff
cgraph: rewrite scanner to use an agxbuf
authorMatthew Fernandez <matthew.fernandez@gmail.com>
Tue, 13 Sep 2022 03:15:13 +0000 (20:15 -0700)
committerMatthew Fernandez <matthew.fernandez@gmail.com>
Tue, 13 Sep 2022 14:50:40 +0000 (07:50 -0700)
This is a reattempt of 2d7852a049b729fb0db71c5a8ef2366215ae2035. The original
change introduced a bug where unterminated strings (both `qstring` and
`hstring`) would not reset the buffer, causing an assertion failure the next
time a graph was parsed. This failed attempt was reverted in
16a04fe061bf6c9b3fe5fdc6250255a9b55cd337.

The approach taken here is essentially the same as
2d7852a049b729fb0db71c5a8ef2366215ae2035, except that it resets the buffer on
error conditions. This appears to be the only way to exit the `qstring` and
`hstring` states that was not covered by the original attempt.

Gitlab: related to #2272

lib/cgraph/scan.l

index 597c79c1969f69bfd8d09499f586b2b37b66f9eb..5b2ba3809e60f21973021bb4e979271701c377ea 100644 (file)
@@ -23,6 +23,7 @@
 %option noinput
 
 %{
+#include <assert.h>
 #include <grammar.h>
 #include <cghdr.h>
 #include <agxbuf.h>
@@ -69,40 +70,25 @@ int gv_isatty_suppression;
 #endif
 
 /* buffer for arbitrary length strings (longer than BUFSIZ) */
-static char    *Sbuf,*Sptr,*Send;
+static agxbuf Sbuf;
+
 static void beginstr(void) {
-       if (Sbuf == NULL) {
-               Sbuf = malloc(BUFSIZ);
-               Send = Sbuf + BUFSIZ;
-       }
-       Sptr = Sbuf;
-       *Sptr = 0;
+  // nothing required, but we should not have pending string data
+  assert(agxblen(&Sbuf) == 0 &&
+         "pending string data that was not consumed (missing "
+         "endstr()/endhtmlstr()?)");
 }
 
 static void addstr(char *src) {
-       char    c;
-       if (Sptr > Sbuf) Sptr--;
-       do {
-               do {c = *Sptr++ = *src++;} while (c && Sptr < Send);
-               if (c) {
-                       long    sz = Send - Sbuf;
-                       long    off = Sptr - Sbuf;
-                       sz *= 2;
-                       Sbuf = realloc(Sbuf,sz);
-                       Send = Sbuf + sz;
-                       Sptr = Sbuf + off;
-               }
-       } while (c);
+  agxbput(&Sbuf, src);
 }
 
 static void endstr(void) {
-       aaglval.str = agstrdup(Ag_G_global,Sbuf);
-       *Sbuf = 0;
+  aaglval.str = agstrdup(Ag_G_global, agxbuse(&Sbuf));
 }
 
 static void endstr_html(void) {
-       aaglval.str = agstrdup_html(Ag_G_global,Sbuf);
-       *Sbuf = 0;
+  aaglval.str = agstrdup_html(Ag_G_global, agxbuse(&Sbuf));
 }
 
 static void
@@ -246,24 +232,28 @@ void aagerror(const char *str)
                agxbprint(&xb, " near '%s'", aagtext);
        }
        else switch (YYSTATE) {
-       case qstring :
+       case qstring: {
                agxbprint(&xb, " scanning a quoted string (missing endquote? longer than %d?)", YY_BUF_SIZE);
-               if (*Sbuf) {
-                       size_t len = strlen(Sbuf);
+               size_t len = agxblen(&Sbuf);
+               if (len > 0) {
                        if (len > 80)
-                               Sbuf[80] = '\0';
-                       agxbprint (&xb, "\nString starting:\"%s", Sbuf);
+                               len = 80;
+                       agxbprint(&xb, "\nString starting:\"%.*s", (int)len, Sbuf.buf);
                }
+               agxbclear(&Sbuf);
                break;
-       case hstring :
+       }
+       case hstring: {
                agxbprint(&xb, " scanning a HTML string (missing '>'? bad nesting? longer than %d?)", YY_BUF_SIZE);
-               if (*Sbuf) {
-                       size_t len = strlen(Sbuf);
+               size_t len = agxblen(&Sbuf);
+               if (len > 0) {
                        if (len > 80)
-                               Sbuf[80] = '\0';
-                       agxbprint (&xb, "\nString starting:<%s", Sbuf);
+                               len = 80;
+                       agxbprint(&xb, "\nString starting:<%.*s", (int)len, Sbuf.buf);
                }
+               agxbclear(&Sbuf);
                break;
+       }
        case comment :
                agxbprint(&xb, " scanning a /*...*/ comment (missing '*/? longer than %d?)", YY_BUF_SIZE);
                break;