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>,
	Simon Marchi <simon.marchi@polymtl.ca>
Subject: Re: [PATCH v4] C++ify gdb/common/environ.c
Date: Fri, 16 Jun 2017 18:23:00 -0000	[thread overview]
Message-ID: <a2ee9fc7-00ed-975a-ed15-4ed5dccb9379@redhat.com> (raw)
In-Reply-To: <87vanv3j71.fsf@redhat.com>

On 06/16/2017 07:01 PM, Sergio Durigan Junior wrote:
> On Friday, June 16 2017, Pedro Alves wrote:
> 
>> On 06/14/2017 08:22 PM, Sergio Durigan Junior wrote:
>>
>>> diff --git a/gdb/Makefile.in b/gdb/Makefile.in
>>> index 5e5fcaa..133db1a 100644
>>> --- a/gdb/Makefile.in
>>> +++ b/gdb/Makefile.in
>>> @@ -530,14 +530,16 @@ SUBDIR_UNITTESTS_SRCS = \
>>>  	unittests/offset-type-selftests.c \
>>>  	unittests/optional-selftests.c \
>>>  	unittests/ptid-selftests.c \
>>> -	unittests/scoped_restore-selftests.c
>>> +	unittests/scoped_restore-selftests.c \
>>> +	unittests/environ-selftests.c
>>
>> Please keep the list sorted.
>>
>> (I'm guilty of missing that before too.)
> 
> Done.
> 
>>>  
>>>  SUBDIR_UNITTESTS_OBS = \
>>>  	function-view-selftests.o \
>>>  	offset-type-selftests.o \
>>>  	optional-selftests.o \
>>>  	ptid-selftests.o \
>>> -	scoped_restore-selftests.o
>>> +	scoped_restore-selftests.o \
>>> +	environ-selftests.o
>>
>> Ditto.
> 
> Done.
> 
>>> diff --git a/gdb/common/environ.c b/gdb/common/environ.c
>>> index 3145d01..657f2e0 100644
>>> --- a/gdb/common/environ.c
>>> +++ b/gdb/common/environ.c
>>> @@ -18,165 +18,102 @@
>>>  #include "common-defs.h"
>>>  #include "environ.h"
>>>  #include <algorithm>
>>> -\f
>>> +#include <utility>
>>>  
>>> -/* Return a new environment object.  */
>>> +/* See common/environ.h.  */
>>>  
>>> -struct gdb_environ *
>>> -make_environ (void)
>>> +gdb_environ::gdb_environ ()
>>>  {
>>> -  struct gdb_environ *e;
>>> +}
>>>  
>>> -  e = XNEW (struct gdb_environ);
>>> +/* See common/environ.h.  */
>>>  
>>> -  e->allocated = 10;
>>> -  e->vector = (char **) xmalloc ((e->allocated + 1) * sizeof (char *));
>>> -  e->vector[0] = 0;
>>> -  return e;
>>> +gdb_environ::~gdb_environ ()
>>> +{
>>> +  clear ();
>>>  }
>>>  
>>> -/* Free an environment and all the strings in it.  */
>>> +/* See common/environ.h.  */
>>>  
>>> -void
>>> -free_environ (struct gdb_environ *e)
>>> +gdb_environ::gdb_environ (gdb_environ &&e)
>>> +  : m_environ_vector (std::move (e.m_environ_vector))
>>>  {
>>> -  char **vector = e->vector;
>>> +}
>>>  
>>> -  while (*vector)
>>> -    xfree (*vector++);
>>> +/* See common/environ.h.  */
>>>  
>>> -  xfree (e->vector);
>>> -  xfree (e);
>>> +gdb_environ &
>>> +gdb_environ::operator= (gdb_environ &&e)
>>> +{
>>> +  clear ();
>>> +  m_environ_vector = std::move (e.m_environ_vector);
>>> +  return *this;
>>>  }
>>>  
>>> -/* Copy the environment given to this process into E.
>>> -   Also copies all the strings in it, so we can be sure
>>> -   that all strings in these environments are safe to free.  */
>>> +/* See common/environ.h.  */
>>>  
>>>  void
>>> -init_environ (struct gdb_environ *e)
>>> +gdb_environ::clear ()
>>>  {
>>> -  extern char **environ;
>>> -  int i;
>>> -
>>> -  if (environ == NULL)
>>> -    return;
>>> -
>>> -  for (i = 0; environ[i]; i++) /*EMPTY */ ;
>>> +  for (char *v : m_environ_vector)
>>> +    xfree (v);
>>> +  m_environ_vector.clear ();
>>> +}
>>>  
>>> -  if (e->allocated < i)
>>> -    {
>>> -      e->allocated = std::max (i, e->allocated + 10);
>>> -      e->vector = (char **) xrealloc ((char *) e->vector,
>>> -				      (e->allocated + 1) * sizeof (char *));
>>> -    }
>>> +/* See common/environ.h.  */
>>>  
>>> -  memcpy (e->vector, environ, (i + 1) * sizeof (char *));
>>> +const char *
>>> +gdb_environ::get (const std::string &var) const
>>> +{
>>
>> Does this need to be a std::string instead of "const char *"?
>> Callers always pass a string literal down, so this is going to
>> force a deep string dup for no good reason, AFAICS.
> 
> It doesn't.  Changed to const char *.
> 
>>
>>> +  size_t len = var.size ();
>>> +  const char *var_str = var.c_str ();
>>>  
>>> -  while (--i >= 0)
>>> -    {
>>> -      int len = strlen (e->vector[i]);
>>> -      char *newobj = (char *) xmalloc (len + 1);
>>> +  for (char *el : m_environ_vector)
>>> +    if (el != NULL && strncmp (el, var_str, len) == 0 && el[len] == '=')
>>> +      return &el[len + 1];
>>>  
>>> -      memcpy (newobj, e->vector[i], len + 1);
>>> -      e->vector[i] = newobj;
>>> -    }
>>> +  return NULL;
>>>  }
>>
>>> -char *
>>> -get_in_environ (const struct gdb_environ *e, const char *var)
>>> +void
>>> +gdb_environ::set (const std::string &var, const std::string &value)
>>
>> Ditto.
> 
> Likewise.
> 
>>>  {
>>> -  int len = strlen (var);
>>> -  char **vector = e->vector;
>>> -  char *s;
>>> -
>>> -  for (; (s = *vector) != NULL; vector++)
>>> -    if (strncmp (s, var, len) == 0 && s[len] == '=')
>>> -      return &s[len + 1];
>>> +  /* We have to unset the variable in the vector if it exists.  */
>>> +  unset (var);
>>>  
>>> -  return 0;
>>> +  /* Insert the element before the last one, which is always NULL.  */
>>> +  m_environ_vector.insert (m_environ_vector.end () - 1,
>>> +			   concat (var.c_str (), "=",
>>> +				   value.c_str (), NULL));
>>>  }
>>>  
>>> -/* Store the value in E of VAR as VALUE.  */
>>> +/* See common/environ.h.  */
>>>  
>>>  void
>>> -set_in_environ (struct gdb_environ *e, const char *var, const char *value)
>>> +gdb_environ::unset (const std::string &var)
>>
>> Ditto.
> 
> Likewise.
> 
>>
>>> -
>>> -  return;
>>> +  std::string match = var + '=';
>>> +  const char *match_str = match.c_str ();
>>> +
>>> +  /* We iterate until '.cend () - 1' because the last element is
>>> +     always NULL.  */
>>> +  for (std::vector<char *>::const_iterator el = m_environ_vector.cbegin ();
>>> +       el != m_environ_vector.cend () - 1;
>>> +       ++el)
>>> +    if (startswith (*el, match_str))
>>
>> In gdb_environ::set you used:
> 
> I assume you meant gdb_environ::get, right?

Maybe, (I don't have the patch handy anymore.)  Whatever the
other code that looped over all vars.

>> Nit: I find it a bit odd that the ctors/dtors are short but 
>> defined out of line, while this function is defined inline.
>> If I was looking at controlling what the compiler could inline,
>> then I'd do it the other way around -- small ctor/dtor in
>> the header, and this larger function out of line in the .c file.
> 
> Question: if I define a method inside the class, does this implicitly
> tell the compiler that I want to inline it, as oppose to defining the
> method outside?

It's not about inside vs outside.  It's about the compiler seeing the
body when compiling a foo.c file that includes the gdb_environ.h header.
The compiler is invoked on a per-compilation-unit base.  If you put the
method's definition outside the class but still in the gdb_environ.h header,
then the compiler would still be able to inline the method's body in the
foo.c compilation unit if it so chooses.  Of course, then you'd run into
multiple definition problems at link time.  So you can then mark
the definition as inline explicitly.  But that's no different from putting a
free function's definition in a header.

If you put the method instead in gdb_environ.c instead, then when the compiler
is compiling compilation unit foo.c, it has no idea what the body of
the method is, so it can't inline it.  Unless you build with -flto,
of course.

>> So we either always add a NULL to the vector, or we
>> change gdb_environ::get_char_vector instead, like:
>>
>>  char **
>>  gdb_environ::get_char_vector () const
>>  {
>>    if (m_environ_vector.empty ())
>>      {
>>        static const char *const empty_envp[1] = { NULL };
>>        return const_cast<char **> (empty_envp);
>>      }
>>    return const_cast<char **> (&m_environ_vector[0]);
>>  }
>>
>> This is OK because execve etc. are garanteed to never change
>> the envp they're passed.
> 
> Oh, good catch.  I prefer to just initialize the vector with a NULL
> value in the ctor; will do that now.

I'd prefer the other option.  Because then constructing gdb_environ
is dirt cheap and doesn't require heap memory.  We're constructing one
environ per inferior, even if we end up not setting any variable
[now thinking ahead to when we make this work with remote].

Thanks,
Pedro Alves


  reply	other threads:[~2017-06-16 18:23 UTC|newest]

Thread overview: 47+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2017-04-13  4:05 [PATCH] " Sergio Durigan Junior
2017-04-15 18:51 ` [PATCH v2] " Sergio Durigan Junior
2017-04-15 21:22   ` Simon Marchi
2017-04-18  2:49     ` Sergio Durigan Junior
2017-04-16  5:09   ` Simon Marchi
2017-04-16 17:32     ` Sergio Durigan Junior
2017-04-18  3:03 ` [PATCH v3] " Sergio Durigan Junior
2017-04-19  4:56   ` Simon Marchi
2017-04-19 16:30     ` Pedro Alves
2017-04-19 18:14   ` Pedro Alves
2017-05-01  2:22     ` Sergio Durigan Junior
2017-05-04 15:30       ` Pedro Alves
2017-06-14 19:22 ` [PATCH v4] " Sergio Durigan Junior
2017-06-16 15:45   ` Pedro Alves
2017-06-16 18:01     ` Sergio Durigan Junior
2017-06-16 18:23       ` Pedro Alves [this message]
2017-06-16 21:59         ` Sergio Durigan Junior
2017-06-16 22:23 ` [PATCH v5] " Sergio Durigan Junior
2017-06-17  8:54   ` Simon Marchi
2017-06-19  4:19     ` Sergio Durigan Junior
2017-06-19 13:40       ` Pedro Alves
2017-06-19 16:19         ` Sergio Durigan Junior
2017-06-19 12:13     ` Pedro Alves
2017-06-20 14:02       ` Pedro Alves
2017-06-19  4:36 ` [PATCH v6] " Sergio Durigan Junior
2017-06-19  4:51   ` Sergio Durigan Junior
2017-06-19  7:18     ` Simon Marchi
2017-06-19 14:26       ` Pedro Alves
2017-06-19 15:30         ` Simon Marchi
2017-06-19 15:44           ` Pedro Alves
2017-06-19 15:47             ` Pedro Alves
2017-06-19 16:26             ` Simon Marchi
2017-06-19 16:55               ` Pedro Alves
2017-06-19 17:59                 ` Sergio Durigan Junior
2017-06-19 18:09                   ` Pedro Alves
2017-06-19 18:23                     ` Sergio Durigan Junior
2017-06-19 18:36                       ` Pedro Alves
2017-06-19 18:38                         ` Pedro Alves
2017-06-19 14:26   ` Pedro Alves
2017-06-19 16:13     ` Sergio Durigan Junior
2017-06-19 16:38       ` Pedro Alves
2017-06-19 16:46         ` Sergio Durigan Junior
2017-06-19 18:27 ` [PATCH v7] " Sergio Durigan Junior
2017-06-20  3:27 ` [PATCH v8] " Sergio Durigan Junior
2017-06-20 12:13   ` Pedro Alves
2017-06-20 12:46   ` Simon Marchi
2017-06-20 13:00     ` 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=a2ee9fc7-00ed-975a-ed15-4ed5dccb9379@redhat.com \
    --to=palves@redhat.com \
    --cc=gdb-patches@sourceware.org \
    --cc=sergiodj@redhat.com \
    --cc=simon.marchi@polymtl.ca \
    /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