[3/4] gdb: remove last alloca call from printcmd.c

Message ID 35bd5c487f6cda38f1668a3ad815b7d382113a6f.1685611213.git.aburgess@redhat.com
State New
Headers
Series Some alloca removal and a printf bug fix |

Commit Message

Andrew Burgess June 1, 2023, 9:27 a.m. UTC
  This commit removes the last alloca call from printcmd.c.  This is
similar to the patches I originally posted here:

  https://inbox.sourceware.org/gdb-patches/cover.1677533215.git.aburgess@redhat.com/

However, this change was not included in that original series.

The original series received push back because it was thought that
replacing alloca with a C++ container type would introduce unnecessary
malloc/free overhead.

However, in this case we are building a string, and (at least for
GCC), the std::string type has a small string optimisation, where
small strings are stored on the stack.

And in this case we are building what will usually be a very small
string, we're just constructing a printf format specifier for a hex
value, so it'll be something like '%#x' -- though it could also have a
width in there too -- but still, it should normally fit within GCCs
small string buffer.

So, in this commit, I propose replacing the use of alloca with a
std::string.  This shouldn't result (normally) in any additional
malloc or free calls, so should be similar in performance to the
original approach.

There should be no user visible differences after this commit.
---
 gdb/printcmd.c | 30 +++++++++++++-----------------
 1 file changed, 13 insertions(+), 17 deletions(-)
  

Patch

diff --git a/gdb/printcmd.c b/gdb/printcmd.c
index 6f8a7f1420a..61b009fb7f2 100644
--- a/gdb/printcmd.c
+++ b/gdb/printcmd.c
@@ -2653,62 +2653,58 @@  printf_pointer (struct ui_file *stream, const char *format,
      modifier for %p is a width; extract that, and then
      handle %p as glibc would: %#x or a literal "(nil)".  */
 
-  const char *p;
-  char *fmt, *fmt_p;
 #ifdef PRINTF_HAS_LONG_LONG
   long long val = value_as_long (value);
 #else
   long val = value_as_long (value);
 #endif
 
-  fmt = (char *) alloca (strlen (format) + 5);
+  /* Build the new output format in FMT.  */
+  std::string fmt;
 
   /* Copy up to the leading %.  */
-  p = format;
-  fmt_p = fmt;
+  const char *p = format;
   while (*p)
     {
       int is_percent = (*p == '%');
 
-      *fmt_p++ = *p++;
+      fmt.push_back (*p++);
       if (is_percent)
 	{
 	  if (*p == '%')
-	    *fmt_p++ = *p++;
+	    fmt.push_back (*p++);
 	  else
 	    break;
 	}
     }
 
   if (val != 0)
-    *fmt_p++ = '#';
+    fmt.push_back ('#');
 
   /* Copy any width or flags.  Only the "-" flag is valid for pointers
      -- see the format_pieces constructor.  */
   while (*p == '-' || (*p >= '0' && *p < '9'))
-    *fmt_p++ = *p++;
+    fmt.push_back (*p++);
 
   gdb_assert (*p == 'p' && *(p + 1) == '\0');
   if (val != 0)
     {
 #ifdef PRINTF_HAS_LONG_LONG
-      *fmt_p++ = 'l';
+      fmt.push_back ('l');
 #endif
-      *fmt_p++ = 'l';
-      *fmt_p++ = 'x';
-      *fmt_p++ = '\0';
+      fmt.push_back ('l');
+      fmt.push_back ('x');
       DIAGNOSTIC_PUSH
       DIAGNOSTIC_IGNORE_FORMAT_NONLITERAL
-	gdb_printf (stream, fmt, val);
+	gdb_printf (stream, fmt.c_str (), val);
       DIAGNOSTIC_POP
     }
   else
     {
-      *fmt_p++ = 's';
-      *fmt_p++ = '\0';
+      fmt.push_back ('s');
       DIAGNOSTIC_PUSH
       DIAGNOSTIC_IGNORE_FORMAT_NONLITERAL
-	gdb_printf (stream, fmt, "(nil)");
+	gdb_printf (stream, fmt.c_str (), "(nil)");
       DIAGNOSTIC_POP
     }
 }