Fix regression: cannot start with LD_PRELOAD=libSegFault.so (PR gdb/18653#c7)
[deliverable/binutils-gdb.git] / gdb / common / environ.c
index 3145d01afa5aedf06937e4dc25b40a36401fed30..1a668bf449d55a0571d293f52118eb06ec70ad78 100644 (file)
@@ -1,6 +1,6 @@
 /* environ.c -- library for manipulating environments for GNU.
 
-   Copyright (C) 1986-2017 Free Software Foundation, Inc.
+   Copyright (C) 1986-2018 Free Software Foundation, Inc.
 
    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
 #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::operator= (gdb_environ &&e)
 {
-  struct gdb_environ *e;
-
-  e = XNEW (struct gdb_environ);
-
-  e->allocated = 10;
-  e->vector = (char **) xmalloc ((e->allocated + 1) * sizeof (char *));
-  e->vector[0] = 0;
-  return e;
+  /* Are we self-moving?  */
+  if (&e == this)
+    return *this;
+
+  m_environ_vector = std::move (e.m_environ_vector);
+  m_user_set_env = std::move (e.m_user_set_env);
+  m_user_unset_env = std::move (e.m_user_unset_env);
+  e.m_environ_vector.clear ();
+  e.m_environ_vector.push_back (NULL);
+  e.m_user_set_env.clear ();
+  e.m_user_unset_env.clear ();
+  return *this;
 }
 
-/* Free an environment and all the strings in it.  */
+/* See common/environ.h.  */
 
-void
-free_environ (struct gdb_environ *e)
+gdb_environ gdb_environ::from_host_environ ()
 {
-  char **vector = e->vector;
+  extern char **environ;
+  gdb_environ e;
 
-  while (*vector)
-    xfree (*vector++);
+  if (environ == NULL)
+    return e;
 
-  xfree (e->vector);
-  xfree (e);
+  for (int i = 0; environ[i] != NULL; ++i)
+    {
+      /* Make sure we add the element before the last (NULL).  */
+      e.m_environ_vector.insert (e.m_environ_vector.end () - 1,
+                                xstrdup (environ[i]));
+    }
+
+  return e;
 }
 
-/* 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;
+  for (char *v : m_environ_vector)
+    xfree (v);
+  m_environ_vector.clear ();
+  /* Always add the NULL element.  */
+  m_environ_vector.push_back (NULL);
+  m_user_set_env.clear ();
+  m_user_unset_env.clear ();
+}
 
-  if (environ == NULL)
-    return;
+/* Helper function to check if STRING contains an environment variable
+   assignment of VAR, i.e., if STRING starts with 'VAR='.  Return true
+   if it contains, false otherwise.  */
 
-  for (i = 0; environ[i]; i++) /*EMPTY */ ;
+static bool
+match_var_in_string (const char *string, const char *var, size_t var_len)
+{
+  if (strncmp (string, var, var_len) == 0 && string[var_len] == '=')
+    return true;
 
-  if (e->allocated < i)
-    {
-      e->allocated = std::max (i, e->allocated + 10);
-      e->vector = (char **) xrealloc ((char *) e->vector,
-                                     (e->allocated + 1) * sizeof (char *));
-    }
+  return false;
+}
 
-  memcpy (e->vector, environ, (i + 1) * sizeof (char *));
+/* See common/environ.h.  */
 
-  while (--i >= 0)
-    {
-      int len = strlen (e->vector[i]);
-      char *newobj = (char *) xmalloc (len + 1);
+const char *
+gdb_environ::get (const char *var) const
+{
+  size_t len = strlen (var);
 
-      memcpy (newobj, e->vector[i], len + 1);
-      e->vector[i] = newobj;
-    }
+  for (char *el : m_environ_vector)
+    if (el != NULL && match_var_in_string (el, var, len))
+      return &el[len + 1];
+
+  return NULL;
 }
 
-/* Return the vector of environment E.
-   This is used to get something to pass to execve.  */
+/* See common/environ.h.  */
 
-char **
-environ_vector (struct gdb_environ *e)
+void
+gdb_environ::set (const char *var, const char *value)
 {
-  return e->vector;
-}
-\f
-/* Return the value in environment E of variable VAR.  */
+  char *fullvar = concat (var, "=", value, NULL);
 
-char *
-get_in_environ (const struct gdb_environ *e, const char *var)
-{
-  int len = strlen (var);
-  char **vector = e->vector;
-  char *s;
+  /* We have to unset the variable in the vector if it exists.  */
+  unset (var, false);
+
+  /* Insert the element before the last one, which is always NULL.  */
+  m_environ_vector.insert (m_environ_vector.end () - 1, fullvar);
 
-  for (; (s = *vector) != NULL; vector++)
-    if (strncmp (s, var, len) == 0 && s[len] == '=')
-      return &s[len + 1];
+  /* Mark this environment variable as having been set by the user.
+     This will be useful when we deal with setting environment
+     variables on the remote target.  */
+  m_user_set_env.insert (std::string (fullvar));
 
-  return 0;
+  /* If this environment variable is marked as unset by the user, then
+     remove it from the list, because now the user wants to set
+     it.  */
+  m_user_unset_env.erase (std::string (var));
 }
 
-/* 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 char *var, bool update_unset_list)
 {
-  int i;
-  int len = strlen (var);
-  char **vector = e->vector;
-  char *s;
-
-  for (i = 0; (s = vector[i]) != NULL; i++)
-    if (strncmp (s, var, len) == 0 && s[len] == '=')
+  size_t len = strlen (var);
+  std::vector<char *>::iterator it_env;
+
+  /* We iterate until '.end () - 1' because the last element is
+     always NULL.  */
+  for (it_env = m_environ_vector.begin ();
+       it_env != m_environ_vector.end () - 1;
+       ++it_env)
+    if (match_var_in_string (*it_env, var, len))
       break;
 
-  if (s == 0)
+  if (it_env != m_environ_vector.end () - 1)
     {
-      if (i == e->allocated)
-       {
-         e->allocated += 10;
-         vector = (char **) xrealloc ((char *) vector,
-                                      (e->allocated + 1) * sizeof (char *));
-         e->vector = vector;
-       }
-      vector[i + 1] = 0;
+      m_user_set_env.erase (std::string (*it_env));
+      xfree (*it_env);
+
+      m_environ_vector.erase (it_env);
     }
-  else
-    xfree (s);
-
-  s = (char *) xmalloc (len + strlen (value) + 2);
-  strcpy (s, var);
-  strcat (s, "=");
-  strcat (s, value);
-  vector[i] = s;
-
-  /* This used to handle setting the PATH and GNUTARGET variables
-     specially.  The latter has been replaced by "set gnutarget"
-     (which has worked since GDB 4.11).  The former affects searching
-     the PATH to find SHELL, and searching the PATH to find the
-     argument of "symbol-file" or "exec-file".  Maybe we should have
-     some kind of "set exec-path" for that.  But in any event, having
-     "set env" affect anything besides the inferior is a bad idea.
-     What if we want to change the environment we pass to the program
-     without afecting GDB's behavior?  */
-
-  return;
+
+  if (update_unset_list)
+    m_user_unset_env.insert (std::string (var));
 }
 
-/* Remove the setting for variable VAR from environment E.  */
+/* See common/environ.h.  */
 
 void
-unset_in_environ (struct gdb_environ *e, const char *var)
+gdb_environ::unset (const char *var)
 {
-  int len = strlen (var);
-  char **vector = e->vector;
-  char *s;
+  unset (var, true);
+}
 
-  for (; (s = *vector) != NULL; vector++)
-    {
-      if (strncmp (s, var, len) == 0 && s[len] == '=')
-       {
-         xfree (s);
-         /* Walk through the vector, shuffling args down by one, including
-            the NULL terminator.  Can't use memcpy() here since the regions
-            overlap, and memmove() might not be available.  */
-         while ((vector[0] = vector[1]) != NULL)
-           {
-             vector++;
-           }
-         break;
-       }
-    }
+/* See common/environ.h.  */
+
+char **
+gdb_environ::envp () const
+{
+  return const_cast<char **> (&m_environ_vector[0]);
+}
+
+/* See common/environ.h.  */
+
+const std::set<std::string> &
+gdb_environ::user_set_env () const
+{
+  return m_user_set_env;
+}
+
+const std::set<std::string> &
+gdb_environ::user_unset_env () const
+{
+  return m_user_unset_env;
 }
This page took 0.028032 seconds and 4 git commands to generate.