Mirror of the gdb-patches mailing list
 help / color / mirror / Atom feed
From: Pedro Alves <palves@redhat.com>
To: Sergio Durigan Junior <sergiodj@redhat.com>
Cc: GDB Patches <gdb-patches@sourceware.org>
Subject: [PATCH] fork-child.c: Avoid unnecessary heap-allocation / string copying (Re: [PATCH v5 3/5] C++-fy and prepare for sharing fork_inferior)
Date: Wed, 12 Apr 2017 10:14:00 -0000	[thread overview]
Message-ID: <36f28afa-1174-df6a-cb54-fdcf129fa816@redhat.com> (raw)
In-Reply-To: <87o9w2z068.fsf@redhat.com>

On 04/12/2017 06:04 AM, Sergio Durigan Junior wrote:

>>>>  static void
>>>> -breakup_args (char *scratch, char **argv)
>>>> +breakup_args (const std::string &scratch, std::vector<char *> &argv)
>>>>  {
>>>
>>> ...
>>>
>>>> +
>>>> +      std::string arg = scratch.substr (cur_pos, next_sep - cur_pos);
>>>> +
>>>
>>> This creates a temporary string (heap allocates) ...
>>>
>>>> +      argv.push_back (xstrdup (arg.c_str ()));
>>>
>>> ... and here you create yet another copy.
>>>
>>> You should be able to avoid it by using e.g., savestring:
>>>
>>>     char *arg = savestring (scratch.c_str () + cur_pos, next_sep - cur_pos);
>>>     argv.push_back (arg);
>>
>> Fair enough.  I had my mind on "C++-only mode" when writing this code.

Yup, in C++, it's good to keep unnecessary temporaries
and hidden heap allocations in mind.  Actually, now that I look a bit
deeper, I think we can avoid a "premature pessimization" here, keeping
the same level of clarity.

I think it'd be good to push this patch below.  WDYT?

From 64d0035762344ed33858a3b8930a83e7071ea4a8 Mon Sep 17 00:00:00 2001
From: Pedro Alves <palves@redhat.com>
Date: Wed, 12 Apr 2017 10:55:36 +0100
Subject: [PATCH] fork-child.c: Avoid unnecessary heap-allocation / string
 copying

The previous patch converted the argv building from an
alloca-allocated array of non-owning arg pointers, to a std::vector of
owning pointers, which results in N string dups, with N being the
number of arguments in the vector, and then requires manually
releasing the pointers owned by the vector.

This patch makes the vector hold non-owning pointers, and avoids the
string dups, by doing one single string copy of the arguments upfront,
and replacing separators with NULL terminators in place, like we used
to.

With this, there's no need to remember to call free_vector_argv either.

Tested on x86_64 Fedora 23.

gdb/ChangeLog:
yyyy-mm-dd  Pedro Alves  <palves@redhat.com>

	* fork-child.c (breakup_args): Make 'scratch' non-const.
	Replace separators with NULL terminators in place.  Change
	type of vector.  (fork_inferior): The argument vector now
	holds non-owning pointers.  Don't strdup strings into the
	vector.  Remove free_vector_argv call.
---
 gdb/fork-child.c | 57 ++++++++++++++++++++++++++++++++++++--------------------
 1 file changed, 37 insertions(+), 20 deletions(-)

diff --git a/gdb/fork-child.c b/gdb/fork-child.c
index 6b7386e..8a6f9e6 100644
--- a/gdb/fork-child.c
+++ b/gdb/fork-child.c
@@ -46,10 +46,12 @@ static char *exec_wrapper;
 /* Break up SCRATCH into an argument vector suitable for passing to
    execvp and store it in ARGV.  E.g., on "run a b c d" this routine
    would get as input the string "a b c d", and as output it would
-   fill in ARGV with the four arguments "a", "b", "c", "d".  */
+   fill in ARGV with the four arguments "a", "b", "c", "d".  The
+   pointers pushed to ARGV point directly into SCRATCH, which is
+   modified in place with the necessary NULL terminators.  */
 
 static void
-breakup_args (const std::string &scratch, std::vector<char *> &argv)
+breakup_args (std::string &scratch, std::vector<const char *> &argv)
 {
   for (size_t cur_pos = 0; cur_pos < scratch.size ();)
     {
@@ -62,13 +64,19 @@ breakup_args (const std::string &scratch, std::vector<char *> &argv)
       /* Find the position of the next separator.  */
       std::size_t next_sep = scratch.find_first_of (" \t\n", cur_pos);
 
-      /* No separator found, which means this is the last
-	 argument.  */
       if (next_sep == std::string::npos)
-	next_sep = scratch.size ();
+	{
+	  /* No separator found, which means this is the last
+	     argument.  */
+	  next_sep = scratch.size ();
+	}
+      else
+	{
+	  /* Replace the separator with a terminator.  */
+	  scratch[next_sep++] = '\0';
+	}
 
-      char *arg = savestring (scratch.c_str () + cur_pos, next_sep - cur_pos);
-      argv.push_back (arg);
+      argv.push_back (&scratch[cur_pos]);
 
       cur_pos = next_sep;
     }
@@ -155,7 +163,6 @@ fork_inferior (const char *exec_file_arg, const std::string &allargs,
   static const char *exec_file;
   char **save_our_env;
   int shell = 0;
-  std::vector<char *> argv;
   const char *inferior_io_terminal = get_inferior_io_terminal ();
   struct inferior *inf;
   int i;
@@ -183,21 +190,29 @@ fork_inferior (const char *exec_file_arg, const std::string &allargs,
       shell = 1;
     }
 
+  /* The argument vector.  Holds non-owning pointers.  */
+  std::vector<const char *> c_argv;
+
+  /* These must be live up to the exec call, because the arguments in
+     C_ARGV point inside them.  */
+  std::string broken_up_args;
+  std::string shell_command;
+
   if (!shell)
     {
       /* We're going to call execvp.  Create argument vector.  */
-      argv.push_back (xstrdup (exec_file));
-      breakup_args (allargs, argv);
+      c_argv.push_back (exec_file);
+      broken_up_args = allargs;
+      breakup_args (broken_up_args, c_argv);
     }
   else
     {
       /* We're going to call a shell.  */
-      std::string shell_command;
       const char *p;
       int need_to_quote;
       const int escape_bang = escape_bang_in_quoted_argument (shell_file);
 
-      shell_command = std::string ("exec ");
+      shell_command = "exec ";
 
       /* Add any exec wrapper.  That may be a program name with arguments, so
 	 the user must handle quoting.  */
@@ -265,12 +280,12 @@ fork_inferior (const char *exec_file_arg, const std::string &allargs,
       /* If we decided above to start up with a shell, we exec the
 	 shell, "-c" says to interpret the next arg as a shell command
 	 to execute, and this command is "exec <target-program>
-	 <args>".  We xstrdup all the strings here because they will
-	 be free'd later in the code.  */
-      argv.push_back (xstrdup (shell_file));
-      argv.push_back (xstrdup ("-c"));
-      argv.push_back (xstrdup (shell_command.c_str ()));
-      argv.push_back (NULL);
+	 <args>".  */
+      c_argv.reserve (4);
+      c_argv.push_back (shell_file);
+      c_argv.push_back ("-c");
+      c_argv.push_back (shell_command.c_str ());
+      c_argv.push_back (NULL);
     }
 
   /* Retain a copy of our environment variables, since the child will
@@ -376,6 +391,10 @@ fork_inferior (const char *exec_file_arg, const std::string &allargs,
          path to find $SHELL.  Rich Pixley says so, and I agree.  */
       environ = env;
 
+      /* It is guaranteed that the exec functions do not modify the
+	 arguments, but they nevertheless expect "char **".  */
+      char **argv = const_cast<char **> (&c_argv[0]);
+
       if (exec_fun != NULL)
         (*exec_fun) (argv[0], &argv[0], env);
       else
@@ -393,8 +412,6 @@ fork_inferior (const char *exec_file_arg, const std::string &allargs,
       _exit (0177);
     }
 
-  free_vector_argv (argv);
-
   /* Restore our environment in case a vforked child clob'd it.  */
   environ = save_our_env;
 
-- 
2.5.5


  parent reply	other threads:[~2017-04-12 10:14 UTC|newest]

Thread overview: 155+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2016-12-23  3:39 [PATCH 0/6] Implement the ability to start inferiors with a shell on gdbserver Sergio Durigan Junior
2016-12-23  3:39 ` [PATCH 3/6] Share parts of gdb/inflow.c with gdbserver Sergio Durigan Junior
2016-12-26 21:34   ` Luis Machado
2017-01-03 21:16     ` Sergio Durigan Junior
2016-12-23  3:39 ` [PATCH 1/6] Share gdb/environ.[ch] " Sergio Durigan Junior
2016-12-26 21:34   ` Luis Machado
2016-12-23  3:39 ` [PATCH 2/6] Share parts of gdb/terminal.h " Sergio Durigan Junior
2016-12-26 21:35   ` Luis Machado
2017-01-03 21:14     ` Sergio Durigan Junior
2017-01-03 21:27       ` Luis Machado
2017-01-03 21:38         ` Sergio Durigan Junior
2016-12-23  3:45 ` [PATCH 4/6] Share parts of gdb/gdbthread.h " Sergio Durigan Junior
2016-12-26 21:35   ` Luis Machado
2017-01-03 21:31     ` Sergio Durigan Junior
2016-12-23  3:45 ` [PATCH 5/6] Share fork_inferior et al " Sergio Durigan Junior
2017-01-03 23:32   ` Luis Machado
2017-01-05 20:11     ` Sergio Durigan Junior
2018-02-21  3:58   ` [RFC] "gdbserver ... BASENAME_EXE" no longer works (was: "[PATCH 5/6] Share fork_inferior et al with gdbserver") Joel Brobecker
2018-02-21  6:15     ` [RFC] "gdbserver ... BASENAME_EXE" no longer works Sergio Durigan Junior
2018-02-21  7:37       ` Joel Brobecker
2016-12-23  3:49 ` [PATCH 6/6] Implement proper "startup-with-shell" support on gdbserver Sergio Durigan Junior
2016-12-23  8:07   ` Eli Zaretskii
2017-01-03 20:48     ` Sergio Durigan Junior
2017-01-04 16:08       ` Eli Zaretskii
2017-01-05 20:12         ` Sergio Durigan Junior
2016-12-26 21:34   ` Luis Machado
2017-01-03 21:35     ` Sergio Durigan Junior
2016-12-27  0:26   ` Tom Tromey
2017-01-03 21:32     ` Sergio Durigan Junior
2016-12-23  7:50 ` [PATCH 0/6] Implement the ability to start inferiors with a shell " Eli Zaretskii
2017-01-03 20:23   ` Sergio Durigan Junior
2017-01-18 15:36 ` [PATCH v2] " Sergio Durigan Junior
2017-01-18 15:36   ` [PATCH v2 2/6] Share parts of gdb/terminal.h with gdbserver Sergio Durigan Junior
2017-02-01 18:37     ` Luis Machado
2017-02-07 22:39       ` Sergio Durigan Junior
2017-01-18 15:36   ` [PATCH v2 1/6] Share gdb/environ.[ch] " Sergio Durigan Junior
2017-02-01 20:35     ` Luis Machado
2017-01-18 15:36   ` [PATCH v2 6/6] Implement proper "startup-with-shell" support on gdbserver Sergio Durigan Junior
2017-01-18 16:43     ` Eli Zaretskii
2017-02-01 19:07     ` Luis Machado
2017-01-18 15:36   ` [PATCH v2 3/6] Share parts of gdb/inflow.c with gdbserver Sergio Durigan Junior
2017-02-01 18:41     ` Luis Machado
2017-01-18 15:42   ` [PATCH v2 4/6] Share parts of gdb/gdbthread.h " Sergio Durigan Junior
2017-02-01 18:54     ` Luis Machado
2017-02-07 22:42       ` Sergio Durigan Junior
2017-02-08  9:07         ` Luis Machado
2017-01-18 15:44   ` [PATCH v2 5/6] Share fork_inferior et al " Sergio Durigan Junior
2017-02-01 21:39     ` Luis Machado
2017-02-07 22:23       ` Sergio Durigan Junior
2017-01-26 22:47   ` [PATCH v2] Implement the ability to start inferiors with a shell on gdbserver Sergio Durigan Junior
2017-01-27  7:45     ` Eli Zaretskii
2017-01-27 17:59       ` Sergio Durigan Junior
2017-02-08  3:25   ` [PATCH v3 0/6] " Sergio Durigan Junior
2017-02-08  3:25     ` [PATCH v3 1/6] Share gdb/environ.[ch] with gdbserver Sergio Durigan Junior
2017-02-15 15:36       ` Pedro Alves
2017-03-07 20:50         ` Sergio Durigan Junior
2017-02-08  3:25     ` [PATCH v3 2/6] Share parts of gdb/terminal.h " Sergio Durigan Junior
2017-02-15 15:54       ` Pedro Alves
2017-02-16 21:37         ` Sergio Durigan Junior
2017-02-08  3:25     ` [PATCH v3 3/6] Share parts of gdb/inflow.c " Sergio Durigan Junior
2017-02-15 16:02       ` Pedro Alves
2017-02-16 22:06         ` Sergio Durigan Junior
2017-02-08  3:32     ` [PATCH v3 5/6] Share fork_inferior et al " Sergio Durigan Junior
2017-02-15 17:28       ` Pedro Alves
2017-02-16 12:23         ` Philipp Rudo
2017-02-16 12:26           ` Pedro Alves
2017-02-16 12:37             ` Philipp Rudo
     [not found]         ` <87bmtcg91v.fsf@redhat.com>
2017-03-13 15:34           ` Pedro Alves
2017-02-08  3:33     ` [PATCH v3 6/6] Implement proper "startup-with-shell" support on gdbserver Sergio Durigan Junior
2017-02-08 17:34       ` Eli Zaretskii
2017-02-09  0:02         ` Sergio Durigan Junior
2017-02-17 16:05       ` Pedro Alves
2017-02-17 16:27         ` Eli Zaretskii
2017-03-07 20:59         ` Sergio Durigan Junior
2017-03-13 15:12           ` Pedro Alves
2017-02-08  3:33     ` [PATCH v3 4/6] Share parts of gdb/gdbthread.h with gdbserver Sergio Durigan Junior
2017-02-15 16:15       ` Pedro Alves
2017-02-21 21:27         ` Sergio Durigan Junior
2017-02-13 19:50     ` [PATCH v3 0/6] Implement the ability to start inferiors with a shell on gdbserver Sergio Durigan Junior
2017-03-08  5:29     ` [PATCH v4 0/5] " Sergio Durigan Junior
2017-03-08  5:29       ` [PATCH v4 4/5] Share fork_inferior et al with gdbserver Sergio Durigan Junior
2017-03-13 17:04         ` Pedro Alves
2017-03-17  1:02           ` Sergio Durigan Junior
2017-03-17 10:27             ` Pedro Alves
2017-03-08  5:29       ` [PATCH v4 2/5] Share parts of gdb/inflow.c " Sergio Durigan Junior
2017-03-08  5:29       ` [PATCH v4 5/5] Implement proper "startup-with-shell" support on gdbserver Sergio Durigan Junior
2017-03-08 15:49         ` Eli Zaretskii
2017-03-13 17:26         ` Pedro Alves
2017-03-08  5:29       ` [PATCH v4 3/5] Share parts of gdb/gdbthread.h with gdbserver Sergio Durigan Junior
2017-03-08  5:29       ` [PATCH v4 1/5] Share parts of gdb/terminal.h " Sergio Durigan Junior
2017-03-30  1:50 ` [PATCH v5 0/5] Implement the ability to start inferiors with a shell on gdbserver Sergio Durigan Junior
2017-03-30  1:50   ` [PATCH v5 2/5] Share parts of gdb/gdbthread.h with gdbserver Sergio Durigan Junior
2017-03-31 17:15     ` Pedro Alves
2017-04-07  2:53       ` Sergio Durigan Junior
2017-03-30  1:50   ` [PATCH v5 1/5] Move parts of inferior job control to common/ Sergio Durigan Junior
2017-03-31 17:11     ` Pedro Alves
2017-03-31 17:31       ` Sergio Durigan Junior
2017-03-31 18:21         ` Pedro Alves
2017-03-31 21:20           ` Sergio Durigan Junior
2017-04-07 17:51             ` Pedro Alves
2017-04-12  0:25               ` Sergio Durigan Junior
2017-04-12  1:17                 ` [PATCH] Create gdb_termios.h (and cleanup gdb/{,gdbserver/}terminal.h) Sergio Durigan Junior
2017-04-12 10:28                   ` Pedro Alves
2017-04-12 22:00                     ` Sergio Durigan Junior
2017-03-30  1:50   ` [PATCH v5 3/5] C++-fy and prepare for sharing fork_inferior Sergio Durigan Junior
2017-04-07 18:30     ` Pedro Alves
2017-04-12  0:24       ` Sergio Durigan Junior
2017-04-12  5:04         ` Sergio Durigan Junior
2017-04-12  5:19           ` [obv/commit] Fix build breakage from last commit (window-nat.c:windows_create_inferior) Sergio Durigan Junior
2017-04-12 10:14           ` Pedro Alves [this message]
2017-04-12 22:26             ` [PATCH] fork-child.c: Avoid unnecessary heap-allocation / string copying (Re: [PATCH v5 3/5] C++-fy and prepare for sharing fork_inferior) Sergio Durigan Junior
2017-04-13  3:42               ` Pedro Alves
2017-04-13  4:33                 ` Sergio Durigan Junior
2017-04-13 10:51                   ` Pedro Alves
2017-04-13 18:30                     ` Sergio Durigan Junior
2017-04-14  1:03           ` [obv/commit] Fix build breakage on Cygwin (PR gdb/21385) Sergio Durigan Junior
2017-03-30  1:55   ` [PATCH v5 4/5] Share fork_inferior et al with gdbserver Sergio Durigan Junior
2017-03-30  1:55   ` [PATCH v5 5/5] Implement proper "startup-with-shell" support on gdbserver Sergio Durigan Junior
2017-05-04  5:31 ` [PATCH v6 0/4] Implement the ability to start inferiors with a shell " Sergio Durigan Junior
2017-05-04  5:32   ` [PATCH v6 3/4] Share fork_inferior et al with gdbserver Sergio Durigan Junior
2017-05-05 19:05     ` Pedro Alves
2017-05-31  3:43       ` Sergio Durigan Junior
2017-06-07 10:16         ` Pedro Alves
2017-06-07 12:23           ` Pedro Alves
2017-06-07 21:01             ` Sergio Durigan Junior
2017-06-07 21:06               ` Pedro Alves
2017-06-07 21:00           ` Sergio Durigan Junior
2017-05-04  5:32   ` [PATCH v6 1/4] Move parts of inferior job control to common/ Sergio Durigan Junior
2017-05-04  5:32   ` [PATCH v6 2/4] Share parts of gdb/gdbthread.h with gdbserver Sergio Durigan Junior
2017-05-05 19:04     ` Pedro Alves
2017-05-06 14:15       ` Sergio Durigan Junior
2017-05-04  5:38   ` [PATCH v6 4/4] Implement proper "startup-with-shell" support on gdbserver Sergio Durigan Junior
2017-05-05 19:21     ` Pedro Alves
2017-06-04 22:18 ` [PATCH v7 0/4] Implement the ability to start inferiors with a shell " Sergio Durigan Junior
2017-06-04 22:18   ` [PATCH v7 4/4] Implement proper "startup-with-shell" support " Sergio Durigan Junior
2017-06-05  2:31     ` Eli Zaretskii
2017-06-04 22:18   ` [PATCH v7 3/4] Share fork_inferior et al with gdbserver Sergio Durigan Junior
2017-06-07 12:29     ` Pedro Alves
2017-06-07 21:06       ` Sergio Durigan Junior
2017-06-07 21:41         ` Sergio Durigan Junior
2017-06-07 22:05           ` Pedro Alves
2017-06-07 22:08             ` Sergio Durigan Junior
2017-06-07 22:14               ` Pedro Alves
2017-06-07 22:15         ` Sergio Durigan Junior
2017-06-07 22:29           ` Pedro Alves
2017-06-08  0:00             ` Sergio Durigan Junior
2019-02-14 15:38               ` Thomas Schwinge
2017-06-08 16:40     ` Yao Qi
2017-06-08 18:49       ` Sergio Durigan Junior
2017-06-08 21:02       ` [commit/obvious] Fix possible bug when no args have been provided to the executable Sergio Durigan Junior
2017-06-09 22:19       ` [commit/obvious] Include <signal.h> on gdbserver/fork-child.c (and fix regressions) Sergio Durigan Junior
2017-06-21 17:01     ` [PATCH v7 3/4] Share fork_inferior et al with gdbserver Simon Marchi
2017-06-21 17:19       ` Sergio Durigan Junior
2017-06-04 22:18   ` [PATCH v7 2/4] Share parts of gdb/gdbthread.h " Sergio Durigan Junior
2017-06-04 22:18   ` [PATCH v7 1/4] Move parts of inferior job control to common/ Sergio Durigan Junior

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=36f28afa-1174-df6a-cb54-fdcf129fa816@redhat.com \
    --to=palves@redhat.com \
    --cc=gdb-patches@sourceware.org \
    --cc=sergiodj@redhat.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox