]> git.eshelyaron.com Git - emacs.git/commitdiff
Avoid undefined behavior when printing function pointers.
authorPhilipp Stephani <phst@google.com>
Sat, 4 May 2019 20:59:46 +0000 (22:59 +0200)
committerPhilipp Stephani <phst@google.com>
Sat, 4 May 2019 21:04:24 +0000 (23:04 +0200)
* src/print.c (print_vectorlike): Don’t pass a function pointer to
‘snprintf’, as that is undefined behavior.  Instead, print the
individual bytes making up the function pointer.

src/print.c

index 68ed6781c812560f2e8df8b09db46791ebee1279..57aac5f5471144eee5e4d7708749bc42f95bd647 100644 (file)
@@ -1794,17 +1794,24 @@ print_vectorlike (Lisp_Object obj, Lisp_Object printcharfun, bool escapeflag,
 
        if (symbol == NULL)
          {
-           print_c_string ("at ", printcharfun);
-           enum { pointer_bufsize = sizeof ptr * 16 / CHAR_BIT + 2 + 1 };
-           char buffer[pointer_bufsize];
-           int needed = snprintf (buffer, sizeof buffer, "%p", ptr);
-           const char p0x[] = "0x";
-           eassert (needed <= sizeof buffer);
-           /* ANSI C doesn't guarantee that %p produces a string that
-              begins with a "0x".  */
-           if (c_strncasecmp (buffer, p0x, sizeof (p0x) - 1) != 0)
-             print_c_string (p0x, printcharfun);
-           print_c_string (buffer, printcharfun);
+           print_c_string ("at 0x", printcharfun);
+            /* See https://stackoverflow.com/a/2741896 for how to
+               portably print a function pointer.  */
+            const unsigned char *p = (const unsigned char *) &ptr;
+            for (size_t i = 0; i < sizeof ptr; ++i)
+              {
+#ifdef WORDS_BIGENDIAN
+                unsigned char b = p[i];
+#else
+                unsigned char b = p[sizeof ptr - i - 1];
+#endif
+                enum { digits = (CHAR_BIT + 4 - 1) / 4 };
+                char buffer[digits + 1];
+                int needed
+                  = snprintf (buffer, sizeof buffer, "%0*hhx", digits, b);
+                eassert (needed == digits);
+                print_c_string (buffer, printcharfun);
+              }
          }
        else
          print_c_string (symbol, printcharfun);