]> granicus.if.org Git - graphviz/commitdiff
common: fix invalid use of 'memcpy' in 'printTok'
authorMatthew Fernandez <matthew.fernandez@gmail.com>
Thu, 15 Dec 2022 06:15:37 +0000 (22:15 -0800)
committerMatthew Fernandez <matthew.fernandez@gmail.com>
Wed, 21 Dec 2022 02:54:30 +0000 (18:54 -0800)
1349b895eca0bb04855ba46162d0ec7ba3c65010 refactored `printTok` to introduce a
call to `agxbput` that passes in the return value from a previous `agxbuse` on
the same buffer. This pointer still points into the destination buffer and
`agxbput` bottoms out on a call to `memcpy`. So this ends up calling `memcpy`
with overlapping source and destination, something that is undefined behavior in
C.

This change introduces a local alternative for this situation, because this is
the only known place where we need to do such a thing.

Gitlab: #2302, fixes #2326

lib/common/htmllex.c

index 2c8febc3f33077a53df77b97853861d497fab5fc..a69e62966308bce420f4e07838a16ca7a7b47c36 100644 (file)
 #include <common/htmllex.h>
 #include <cdt/cdt.h>
 #include <ctype.h>
+#include <cgraph/alloc.h>
 #include <cgraph/strcasecmp.h>
 #include <cgraph/strview.h>
 #include <cgraph/tokenize.h>
+#include <cgraph/unused.h>
 #include <limits.h>
 #include <stddef.h>
 
@@ -798,6 +800,15 @@ int clearHTMLlexer()
 #endif
 }
 
+/// \p agxbput, but assume that source and destination may overlap
+static UNUSED void agxbput_move(agxbuf *dst, const char *src) {
+  // we cannot call `agxbput` itself because it calls `memcpy`, thereby
+  // implicitly assuming that source and destination do not overlap
+  char *src_copy = gv_strdup(src);
+  agxbput(dst, src_copy);
+  free(src_copy);
+}
+
 #ifdef HAVE_EXPAT
 /* eatComment:
  * Given first character after open comment, eat characters
@@ -1034,7 +1045,7 @@ static void printTok(int tok)
     if (tok == T_string) {
        const char *token_text = agxbuse(state.xb);
        fprintf(stderr, "%s \"%s\"\n", s, token_text);
-       agxbput(state.xb, token_text);
+       agxbput_move(state.xb, token_text);
     } else
        fprintf(stderr, "%s\n", s);
 }