From: Philipp Stephani Date: Sat, 4 May 2019 20:59:46 +0000 (+0200) Subject: Avoid undefined behavior when printing function pointers. X-Git-Tag: emacs-27.0.90~2990 X-Git-Url: http://git.eshelyaron.com/gitweb/?a=commitdiff_plain;h=1242a63671f3fc3d427d9d8061338f826e585031;p=emacs.git Avoid undefined behavior when printing function pointers. * 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. --- diff --git a/src/print.c b/src/print.c index 68ed6781c81..57aac5f5471 100644 --- a/src/print.c +++ b/src/print.c @@ -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);