+2017-06-20  Sergio Durigan Junior  <sergiodj@redhat.com>
+
+       * Makefile.in (SUBDIR_UNITTESTS_SRCS): Add
+       'unittests/environ-selftests.c'.
+       (SUBDIR_UNITTESTS_OBS): Add 'environ-selftests.o'.
+       * charset.c (find_charset_names): Declare object 'iconv_env'.
+       Update code to use 'iconv_env' object.  Remove call to
+       'free_environ'.
+       * common/environ.c: Include <utility>.
+       (make_environ): Delete function.
+       (free_environ): Delete function.
+       (gdb_environ::clear): New function.
+       (gdb_environ::operator=): New function.
+       (gdb_environ::get): Likewise.
+       (environ_vector): Delete function.
+       (set_in_environ): Delete function.
+       (gdb_environ::set): New function.
+       (unset_in_environ): Delete function.
+       (gdb_environ::unset): New function.
+       (gdb_environ::envp): Likewise.
+       * common/environ.h: Include <vector>.
+       (struct gdb_environ): Delete; transform into...
+       (class gdb_environ): ... this class.
+       (free_environ): Delete prototype.
+       (init_environ, get_in_environ, set_in_environ, unset_in_environ,
+       environ_vector): Likewise.
+       * infcmd.c (run_command_1): Update code to call
+       'envp' from 'gdb_environ' class.
+       (environment_info): Update code to call methods from 'gdb_environ'
+       class.
+       (unset_environment_command): Likewise.
+       (path_info): Likewise.
+       (path_command): Likewise.
+       * inferior.c (inferior::~inferior): Delete call to 'free_environ'.
+       (inferior::inferior): Initialize 'environment' using the host's
+       information.
+       * inferior.h: Remove forward declaration of 'struct gdb_environ'.
+       Include "environ.h".
+       (class inferior) <environment>: Change type from 'struct
+       gdb_environ' to 'gdb_environ'.
+       * mi/mi-cmd-env.c (mi_cmd_env_path): Update code to call
+       methods from 'gdb_environ' class.
+       * solib.c (solib_find_1): Likewise
+       * unittests/environ-selftests.c: New file.
+
 2017-06-20  Yao Qi  <yao.qi@linaro.org>
 
        * features/i386/i386-linux.xml: Exchange the order of including
 
 SUBDIR_PYTHON_CFLAGS =
 
 SUBDIR_UNITTESTS_SRCS = \
+       unittests/environ-selftests.c \
        unittests/function-view-selftests.c \
        unittests/offset-type-selftests.c \
        unittests/optional-selftests.c \
        unittests/scoped_restore-selftests.c
 
 SUBDIR_UNITTESTS_OBS = \
+       environ-selftests.o \
        function-view-selftests.o \
        offset-type-selftests.o \
        optional-selftests.o \
 
   int err, status;
   int fail = 1;
   int flags;
-  struct gdb_environ *iconv_env;
+  gdb_environ iconv_env = gdb_environ::from_host_environ ();
   char *iconv_program;
 
   /* Older iconvs, e.g. 2.2.2, don't omit the intro text if stdout is
      not a tty.  We need to recognize it and ignore it.  This text is
      subject to translation, so force LANGUAGE=C.  */
-  iconv_env = make_environ ();
-  init_environ (iconv_env);
-  set_in_environ (iconv_env, "LANGUAGE", "C");
-  set_in_environ (iconv_env, "LC_ALL", "C");
+  iconv_env.set ("LANGUAGE", "C");
+  iconv_env.set ("LC_ALL", "C");
 
   child = pex_init (PEX_USE_PIPES, "iconv", NULL);
 
   /* Note that we simply ignore errors here.  */
   if (!pex_run_in_environment (child, flags,
                               args[0], const_cast<char **> (args),
-                              environ_vector (iconv_env),
+                              iconv_env.envp (),
                               NULL, NULL, &err))
     {
       FILE *in = pex_read_output (child, 0);
 
   xfree (iconv_program);
   pex_free (child);
-  free_environ (iconv_env);
 
   if (fail)
     {
 
 #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);
+  e.m_environ_vector.clear ();
+  e.m_environ_vector.push_back (NULL);
+  return *this;
 }
 
-/* Free an environment and all the strings in it.  */
+/* See common/environ.h.  */
 
-void
-free_environ (struct gdb_environ *e)
-{
-  char **vector = e->vector;
-
-  while (*vector)
-    xfree (*vector++);
-
-  xfree (e->vector);
-  xfree (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.  */
-
-void
-init_environ (struct gdb_environ *e)
+gdb_environ gdb_environ::from_host_environ ()
 {
   extern char **environ;
-  int i;
+  gdb_environ e;
 
   if (environ == NULL)
-    return;
-
-  for (i = 0; environ[i]; i++) /*EMPTY */ ;
+    return e;
 
-  if (e->allocated < i)
+  for (int i = 0; environ[i] != NULL; ++i)
     {
-      e->allocated = std::max (i, e->allocated + 10);
-      e->vector = (char **) xrealloc ((char *) e->vector,
-                                     (e->allocated + 1) * sizeof (char *));
+      /* Make sure we add the element before the last (NULL).  */
+      e.m_environ_vector.insert (e.m_environ_vector.end () - 1,
+                                xstrdup (environ[i]));
     }
 
-  memcpy (e->vector, environ, (i + 1) * sizeof (char *));
+  return e;
+}
 
-  while (--i >= 0)
-    {
-      int len = strlen (e->vector[i]);
-      char *newobj = (char *) xmalloc (len + 1);
+/* See common/environ.h.  */
 
-      memcpy (newobj, e->vector[i], len + 1);
-      e->vector[i] = newobj;
-    }
+void
+gdb_environ::clear ()
+{
+  for (char *v : m_environ_vector)
+    xfree (v);
+  m_environ_vector.clear ();
+  /* Always add the NULL element.  */
+  m_environ_vector.push_back (NULL);
 }
 
-/* Return the vector of environment E.
-   This is used to get something to pass to execve.  */
+/* 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.  */
 
-char **
-environ_vector (struct gdb_environ *e)
+static bool
+match_var_in_string (char *string, const char *var, size_t var_len)
 {
-  return e->vector;
+  if (strncmp (string, var, var_len) == 0 && string[var_len] == '=')
+    return true;
+
+  return false;
 }
-\f
-/* Return the value in environment E of variable VAR.  */
 
-char *
-get_in_environ (const struct gdb_environ *e, const char *var)
+/* See common/environ.h.  */
+
+const char *
+gdb_environ::get (const char *var) const
 {
-  int len = strlen (var);
-  char **vector = e->vector;
-  char *s;
+  size_t len = strlen (var);
 
-  for (; (s = *vector) != NULL; vector++)
-    if (strncmp (s, var, len) == 0 && s[len] == '=')
-      return &s[len + 1];
+  for (char *el : m_environ_vector)
+    if (el != NULL && match_var_in_string (el, var, len))
+      return &el[len + 1];
 
-  return 0;
+  return 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::set (const char *var, const char *value)
 {
-  int i;
-  int len = strlen (var);
-  char **vector = e->vector;
-  char *s;
+  /* We have to unset the variable in the vector if it exists.  */
+  unset (var);
 
-  for (i = 0; (s = vector[i]) != NULL; i++)
-    if (strncmp (s, var, len) == 0 && s[len] == '=')
-      break;
-
-  if (s == 0)
-    {
-      if (i == e->allocated)
-       {
-         e->allocated += 10;
-         vector = (char **) xrealloc ((char *) vector,
-                                      (e->allocated + 1) * sizeof (char *));
-         e->vector = vector;
-       }
-      vector[i + 1] = 0;
-    }
-  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;
+  /* Insert the element before the last one, which is always NULL.  */
+  m_environ_vector.insert (m_environ_vector.end () - 1,
+                          concat (var, "=", value, NULL));
 }
 
-/* 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;
+  size_t len = strlen (var);
+
+  /* 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 (match_var_in_string (*el, var, len))
+      {
+       xfree (*el);
+       m_environ_vector.erase (el);
+       break;
+      }
+}
 
-  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]);
 }
 
 #if !defined (ENVIRON_H)
 #define ENVIRON_H 1
 
-/* We manipulate environments represented as these structures.  */
+#include <vector>
 
-struct gdb_environ
+/* Class that represents the environment variables as seen by the
+   inferior.  */
+
+class gdb_environ
+{
+public:
+  /* Regular constructor and destructor.  */
+  gdb_environ ()
+  {
+    /* Make sure that the vector contains at least a NULL element.
+       If/when we add more variables to it, NULL will always be the
+       last element.  */
+    m_environ_vector.push_back (NULL);
+  }
+
+  ~gdb_environ ()
   {
-    /* Number of usable slots allocated in VECTOR.
-       VECTOR always has one slot not counted here,
-       to hold the terminating zero.  */
-    int allocated;
-    /* A vector of slots, ALLOCATED + 1 of them.
-       The first few slots contain strings "VAR=VALUE"
-       and the next one contains zero.
-       Then come some unused slots.  */
-    char **vector;
-  };
+    clear ();
+  }
+
+  /* Move constructor.  */
+  gdb_environ (gdb_environ &&e)
+    : m_environ_vector (std::move (e.m_environ_vector))
+  {
+    /* Make sure that the moved-from vector is left at a valid
+       state (only one NULL element).  */
+    e.m_environ_vector.clear ();
+    e.m_environ_vector.push_back (NULL);
+  }
+
+  /* Move assignment.  */
+  gdb_environ &operator= (gdb_environ &&e);
 
-extern struct gdb_environ *make_environ (void);
+  /* Create a gdb_environ object using the host's environment
+     variables.  */
+  static gdb_environ from_host_environ ();
 
-extern void free_environ (struct gdb_environ *);
+  /* Clear the environment variables stored in the object.  */
+  void clear ();
 
-extern void init_environ (struct gdb_environ *);
+  /* Return the value in the environment for the variable VAR.  The
+     returned pointer is only valid as long as the gdb_environ object
+     is not modified.  */
+  const char *get (const char *var) const;
 
-extern char *get_in_environ (const struct gdb_environ *, const char *);
+  /* Store VAR=VALUE in the environment.  */
+  void set (const char *var, const char *value);
 
-extern void set_in_environ (struct gdb_environ *, const char *, const char *);
+  /* Unset VAR in environment.  */
+  void unset (const char *var);
 
-extern void unset_in_environ (struct gdb_environ *, const char *);
+  /* Return the environment vector represented as a 'char **'.  */
+  char **envp () const;
 
-extern char **environ_vector (struct gdb_environ *);
+private:
+  /* A vector containing the environment variables.  */
+  std::vector<char *> m_environ_vector;
+};
 
 #endif /* defined (ENVIRON_H) */
 
+2017-06-20  Sergio Durigan Junior  <sergiodj@redhat.com>
+
+       * linux-low.c (linux_create_inferior): Adjust code to access the
+       environment information via 'gdb_environ' class.
+       * lynx-low.c (lynx_create_inferior): Likewise.
+       * server.c (our_environ): Make it an instance of 'gdb_environ'.
+       (get_environ): Return a pointer to 'our_environ'.
+       (captured_main): Initialize 'our_environ'.
+       * server.h (get_environ): Adjust prototype.
+       * spu-low.c (spu_create_inferior): Adjust code to access the
+       environment information via 'gdb_environ' class.
+
 2017-06-17  Simon Marchi  <simon.marchi@ericsson.com>
 
        * linux-low.c (linux_read_memory, linux_write_memory): Remove
 
 
   pid = fork_inferior (program,
                       str_program_args.c_str (),
-                      environ_vector (get_environ ()), linux_ptrace_fun,
+                      get_environ ()->envp (), linux_ptrace_fun,
                       NULL, NULL, NULL, NULL);
 
   do_cleanups (restore_personality);
 
 
   pid = fork_inferior (program,
                       str_program_args.c_str (),
-                      environ_vector (get_environ ()), lynx_ptrace_fun,
+                      get_environ ()->envp (), lynx_ptrace_fun,
                       NULL, NULL, NULL, NULL);
 
   post_fork_inferior (pid, program);
 
 
 /* The environment to pass to the inferior when creating it.  */
 
-struct gdb_environ *our_environ = NULL;
+static gdb_environ our_environ;
 
 /* Start the inferior using a shell.  */
 
 
 /* See server.h.  */
 
-struct gdb_environ *
+gdb_environ *
 get_environ ()
 {
-  return our_environ;
+  return &our_environ;
 }
 
 static int
     }
 
   /* Gather information about the environment.  */
-  our_environ = make_environ ();
-  init_environ (our_environ);
+  our_environ = gdb_environ::from_host_environ ();
 
   initialize_async_io ();
   initialize_low ();
 
 #include "mem-break.h"
 #include "gdbthread.h"
 #include "inferiors.h"
+#include "environ.h"
 
 /* Target-specific functions */
 
    inferior and PROGRAM is its name.  */
 extern void post_fork_inferior (int pid, const char *program);
 
-/* Get the 'struct gdb_environ *' being used in the current
-   session.  */
-extern struct gdb_environ *get_environ ();
+/* Get the gdb_environ being used in the current session.  */
+extern gdb_environ *get_environ ();
 
 extern target_waitstatus last_status;
 extern ptid_t last_ptid;
 
 
   pid = fork_inferior (program,
                       str_program_args.c_str (),
-                      environ_vector (get_environ ()), spu_ptrace_fun,
+                      get_environ ()->envp (), spu_ptrace_fun,
                       NULL, NULL, NULL, NULL);
 
   post_fork_inferior (pid, program);
 
      the value now.  */
   run_target->to_create_inferior (run_target, exec_file,
                                  std::string (get_inferior_args ()),
-                                 environ_vector (current_inferior ()->environment),
+                                 current_inferior ()->environment.envp (),
                                  from_tty);
   /* to_create_inferior should push the target, so after this point we
      shouldn't refer to run_target again.  */
 {
   if (var)
     {
-      char *val = get_in_environ (current_inferior ()->environment, var);
+      const char *val = current_inferior ()->environment.get (var);
 
       if (val)
        {
     }
   else
     {
-      char **vector = environ_vector (current_inferior ()->environment);
+      char **envp = current_inferior ()->environment.envp ();
 
-      while (*vector)
+      for (int idx = 0; envp[idx] != NULL; ++idx)
        {
-         puts_filtered (*vector++);
+         puts_filtered (envp[idx]);
          puts_filtered ("\n");
        }
     }
       printf_filtered (_("Setting environment variable "
                         "\"%s\" to null value.\n"),
                       var);
-      set_in_environ (current_inferior ()->environment, var, "");
+      current_inferior ()->environment.set (var, "");
     }
   else
-    set_in_environ (current_inferior ()->environment, var, val);
+    current_inferior ()->environment.set (var, val);
   xfree (var);
 }
 
       /* If there is no argument, delete all environment variables.
          Ask for confirmation if reading from the terminal.  */
       if (!from_tty || query (_("Delete all environment variables? ")))
-       {
-         free_environ (current_inferior ()->environment);
-         current_inferior ()->environment = make_environ ();
-       }
+       current_inferior ()->environment = gdb_environ::from_host_environ ();
     }
   else
-    unset_in_environ (current_inferior ()->environment, var);
+    current_inferior ()->environment.unset (var);
 }
 
 /* Handle the execution path (PATH variable).  */
 path_info (char *args, int from_tty)
 {
   puts_filtered ("Executable and object file path: ");
-  puts_filtered (get_in_environ (current_inferior ()->environment,
-                                path_var_name));
+  puts_filtered (current_inferior ()->environment.get (path_var_name));
   puts_filtered ("\n");
 }
 
   const char *env;
 
   dont_repeat ();
-  env = get_in_environ (current_inferior ()->environment, path_var_name);
+  env = current_inferior ()->environment.get (path_var_name);
   /* Can be null if path is not set.  */
   if (!env)
     env = "";
   exec_path = xstrdup (env);
   mod_path (dirname, &exec_path);
-  set_in_environ (current_inferior ()->environment, path_var_name, exec_path);
+  current_inferior ()->environment.set (path_var_name, exec_path);
   xfree (exec_path);
   if (from_tty)
     path_info ((char *) NULL, from_tty);
 
   inferior_free_data (inf);
   xfree (inf->args);
   xfree (inf->terminal);
-  free_environ (inf->environment);
   target_desc_info_free (inf->tdesc_info);
   xfree (inf->priv);
 }
 inferior::inferior (int pid_)
   : num (++highest_inferior_num),
     pid (pid_),
-    environment (make_environ ()),
+    environment (gdb_environ::from_host_environ ()),
     registry_data ()
 {
-  init_environ (this->environment);
   inferior_alloc_data (this);
 }
 
 
 struct ui_out;
 struct terminal_info;
 struct target_desc_info;
-struct gdb_environ;
 struct continuation;
 struct inferior;
 
 /* For struct frame_id.  */
 #include "frame.h"
 
+/* For gdb_environ.  */
+#include "environ.h"
+
 #include "progspace.h"
 #include "registry.h"
 
 
   /* Environment to use for running inferior,
      in format described in environ.h.  */
-  gdb_environ *environment = NULL;
+  gdb_environ environment;
 
   /* True if this child process was attached rather than forked.  */
   bool attach_flag = false;
 
   else
     {
       /* Otherwise, get current path to modify.  */
-      env = get_in_environ (current_inferior ()->environment, path_var_name);
+      env = current_inferior ()->environment.get (path_var_name);
 
       /* Can be null if path is not set.  */
       if (!env)
   for (i = argc - 1; i >= 0; --i)
     env_mod_path (argv[i], &exec_path);
 
-  set_in_environ (current_inferior ()->environment, path_var_name, exec_path);
+  current_inferior ()->environment.set (path_var_name, exec_path);
   xfree (exec_path);
-  env = get_in_environ (current_inferior ()->environment, path_var_name);
+  env = current_inferior ()->environment.get (path_var_name);
   uiout->field_string ("path", env);
 }
 
 
 
   /* If not found, next search the inferior's $PATH environment variable.  */
   if (found_file < 0 && sysroot == NULL)
-    found_file = openp (get_in_environ (current_inferior ()->environment,
-                                       "PATH"),
+    found_file = openp (current_inferior ()->environment.get ("PATH"),
                        OPF_TRY_CWD_FIRST | OPF_RETURN_REALPATH, in_pathname,
                        O_RDONLY | O_BINARY, &temp_pathname);
 
   /* If not found, and we're looking for a solib, next search the
      inferior's $LD_LIBRARY_PATH environment variable.  */
   if (is_solib && found_file < 0 && sysroot == NULL)
-    found_file = openp (get_in_environ (current_inferior ()->environment,
-                                       "LD_LIBRARY_PATH"),
+    found_file = openp (current_inferior ()->environment.get
+                       ("LD_LIBRARY_PATH"),
                        OPF_TRY_CWD_FIRST | OPF_RETURN_REALPATH, in_pathname,
                        O_RDONLY | O_BINARY, &temp_pathname);
 
 
--- /dev/null
+/* Self tests for gdb_environ for GDB, the GNU debugger.
+
+   Copyright (C) 2017 Free Software Foundation, Inc.
+
+   This file is part of GDB.
+
+   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
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+#include "defs.h"
+#include "selftest.h"
+#include "common/environ.h"
+
+namespace selftests {
+namespace gdb_environ_tests {
+
+static void
+run_tests ()
+{
+  /* Set a test environment variable.  This will be unset at the end
+     of this function.  */
+  if (setenv ("GDB_SELFTEST_ENVIRON", "1", 1) != 0)
+    error (_("Could not set environment variable for testing."));
+
+  gdb_environ env;
+
+  /* When the vector is initialized, there should always be one NULL
+     element in it.  */
+  SELF_CHECK (env.envp ()[0] == NULL);
+
+  /* Make sure that there is no other element.  */
+  SELF_CHECK (env.get ("PWD") == NULL);
+
+  /* Check if unset followed by a set in an empty vector works.  */
+  env.set ("PWD", "test");
+  SELF_CHECK (strcmp (env.get ("PWD"), "test") == 0);
+  /* The second element must be NULL.  */
+  SELF_CHECK (env.envp ()[1] == NULL);
+  env.unset ("PWD");
+  SELF_CHECK (env.envp ()[0] == NULL);
+
+  /* Initialize the environment vector using the host's environ.  */
+  env = gdb_environ::from_host_environ ();
+
+  /* Our test environment variable should be present at the
+     vector.  */
+  SELF_CHECK (strcmp (env.get ("GDB_SELFTEST_ENVIRON"), "1") == 0);
+
+  /* Set our test variable to another value.  */
+  env.set ("GDB_SELFTEST_ENVIRON", "test");
+  SELF_CHECK (strcmp (env.get ("GDB_SELFTEST_ENVIRON"), "test") == 0);
+
+  /* And unset our test variable.  The variable still exists in the
+     host's environment, but doesn't exist in our vector.  */
+  env.unset ("GDB_SELFTEST_ENVIRON");
+  SELF_CHECK (env.get ("GDB_SELFTEST_ENVIRON") == NULL);
+
+  /* Re-set the test variable.  */
+  env.set ("GDB_SELFTEST_ENVIRON", "1");
+  SELF_CHECK (strcmp (env.get ("GDB_SELFTEST_ENVIRON"), "1") == 0);
+
+  /* When we clear our environ vector, there should be only one
+     element on it (NULL), and we shouldn't be able to get our test
+     variable.  */
+  env.clear ();
+  SELF_CHECK (env.envp ()[0] == NULL);
+  SELF_CHECK (env.get ("GDB_SELFTEST_ENVIRON") == NULL);
+
+  /* Reinitialize our environ vector using the host environ.  We
+     should be able to see one (and only one) instance of the test
+     variable.  */
+  env = gdb_environ::from_host_environ ();
+  char **envp = env.envp ();
+  int num_found = 0;
+
+  for (size_t i = 0; envp[i] != NULL; ++i)
+    if (strcmp (envp[i], "GDB_SELFTEST_ENVIRON=1") == 0)
+      ++num_found;
+  SELF_CHECK (num_found == 1);
+
+  /* Get rid of our test variable.  */
+  unsetenv ("GDB_SELFTEST_ENVIRON");
+
+  /* Test the case when we set a variable A, then set a variable B,
+     then unset A, and make sure that we cannot find A in the environ
+     vector, but can still find B.  */
+  env.set ("GDB_SELFTEST_ENVIRON_1", "aaa");
+  SELF_CHECK (strcmp (env.get ("GDB_SELFTEST_ENVIRON_1"), "aaa") == 0);
+
+  env.set ("GDB_SELFTEST_ENVIRON_2", "bbb");
+  SELF_CHECK (strcmp (env.get ("GDB_SELFTEST_ENVIRON_2"), "bbb") == 0);
+
+  env.unset ("GDB_SELFTEST_ENVIRON_1");
+  SELF_CHECK (env.get ("GDB_SELFTEST_ENVIRON_1") == NULL);
+  SELF_CHECK (strcmp (env.get ("GDB_SELFTEST_ENVIRON_2"), "bbb") == 0);
+
+  env.clear ();
+
+  /* Test that after a std::move the moved-from object is left at a
+     valid state (i.e., its only element is NULL).  */
+  env.set ("A", "1");
+  SELF_CHECK (strcmp (env.get ("A"), "1") == 0);
+  gdb_environ env2;
+  env2 = std::move (env);
+  SELF_CHECK (env.envp ()[0] == NULL);
+  SELF_CHECK (strcmp (env2.get ("A"), "1") == 0);
+  SELF_CHECK (env2.envp ()[1] == NULL);
+  env.set ("B", "2");
+  SELF_CHECK (strcmp (env.get ("B"), "2") == 0);
+  SELF_CHECK (env.envp ()[1] == NULL);
+
+  /* Test that the move constructor leaves everything at a valid
+     state.  */
+  env.clear ();
+  env.set ("A", "1");
+  SELF_CHECK (strcmp (env.get ("A"), "1") == 0);
+  gdb_environ env3 = std::move (env);
+  SELF_CHECK (env.envp ()[0] == NULL);
+  SELF_CHECK (strcmp (env3.get ("A"), "1") == 0);
+  SELF_CHECK (env3.envp ()[1] == NULL);
+  env.set ("B", "2");
+  SELF_CHECK (strcmp (env.get ("B"), "2") == 0);
+  SELF_CHECK (env.envp ()[1] == NULL);
+
+  /* Test self-move.  */
+  env.clear ();
+  env.set ("A", "1");
+  SELF_CHECK (strcmp (env.get ("A"), "1") == 0);
+  env = std::move (env);
+  SELF_CHECK (strcmp (env.get ("A"), "1") == 0);
+  SELF_CHECK (strcmp (env.envp ()[0], "A=1") == 0);
+  SELF_CHECK (env.envp ()[1] == NULL);
+}
+} /* namespace gdb_environ */
+} /* namespace selftests */
+
+void
+_initialize_environ_selftests ()
+{
+  register_self_test (selftests::gdb_environ_tests::run_tests);
+}