[1/5] Make delim_string_to_char_ptr_vec return an std::vector

Message ID 20180225163247.20157-1-simon.marchi@polymtl.ca
State New
Headers show
Series
  • [1/5] Make delim_string_to_char_ptr_vec return an std::vector
Related show

Commit Message

Simon Marchi Feb. 25, 2018, 4:32 p.m.
This patch makes delim_string_to_char_ptr_vec and all related functions
use std::vector of gdb::unique_xmalloc_ptr.  This allows getting rid of
make_cleanup_free_char_ptr_vec.  Returning a vector of
unique_xmalloc_ptr instead of std::string allows to minimize the impacts
on the calling code.  We can evaluate later whether we could/should
return a vector of std::strings instead.

gdb/ChangeLog:

	* common/gdb_vecs.h (make_cleanup_free_char_ptr_vec): Remove.
	(delim_string_to_char_ptr_vec): Return std::vector of
	gdb::unique_xmalloc_ptr.
	(dirnames_to_char_ptr_vec_append): Take std::vector of
	gdb::unique_xmalloc_ptr.
	(dirnames_to_char_ptr_vec): Return std::vector of
	gdb::unique_xmalloc_ptr.
	* common/gdb_vecs.c (delim_string_to_char_ptr_vec_append):
	Take std::vector of gdb::unique_xmalloc_ptr, adjust the code.
	(delim_string_to_char_ptr_vec): Return an std::vector of
	gdb::unique_xmalloc_ptr, adjust the code.
	(dirnames_to_char_ptr_vec_append): Take an std::vector of
	gdb::unique_xmalloc_ptr, adjust the code.
	(dirnames_to_char_ptr_vec): Return an std::vector of
	gdb::unique_xmalloc_ptr, adjust the code.
	* auto-load.c (auto_load_safe_path_vec): Change type to
	std::vector of gdb::unique_xmalloc_ptr.
	(auto_load_expand_dir_vars): Return an std::vector of
	gdb::unique_xmalloc_ptr, adjust the code.
	(auto_load_safe_path_vec_update): Adjust.
	(filename_is_in_auto_load_safe_path_vec): Adjust.
	(auto_load_objfile_script_1): Adjust.
	* build-id.c (build_id_to_debug_bfd): Adjust.
	* linux-thread-db.c (thread_db_load_search): Adjust.
	* source.c (add_path): Adjust.
	(openp): Adjust.
	* symfile.c (find_separate_debug_file): Adjust.
	* utils.c (do_free_char_ptr_vec): Remove.
	(make_cleanup_free_char_ptr_vec): Remove.

gdb/gdbserver/ChangeLog:

	* server.c (parse_debug_format_options): Adjust to
	delim_string_to_char_ptr_vec changes.
	* thread-db.c (thread_db_load_search): Adjust to
	dirnames_to_char_ptr_vec changes.
---
 gdb/auto-load.c           | 81 ++++++++++++++++++++++-------------------------
 gdb/build-id.c            | 13 +++-----
 gdb/common/gdb_vecs.c     | 36 ++++++++-------------
 gdb/common/gdb_vecs.h     | 24 ++++++++++----
 gdb/gdbserver/server.c    | 29 ++++++-----------
 gdb/gdbserver/thread-db.c | 11 +++----
 gdb/linux-thread-db.c     | 13 +++-----
 gdb/source.c              | 24 ++++++--------
 gdb/symfile.c             | 25 ++++-----------
 gdb/utils.c               | 24 --------------
 10 files changed, 109 insertions(+), 171 deletions(-)

-- 
2.16.1

Comments

Simon Marchi March 3, 2018, 4:23 a.m. | #1
On 2018-02-25 11:32 AM, Simon Marchi wrote:
> This patch makes delim_string_to_char_ptr_vec and all related functions

> use std::vector of gdb::unique_xmalloc_ptr.  This allows getting rid of

> make_cleanup_free_char_ptr_vec.  Returning a vector of

> unique_xmalloc_ptr instead of std::string allows to minimize the impacts

> on the calling code.  We can evaluate later whether we could/should

> return a vector of std::strings instead.


This series is now pushed.

Simon
Jan Kratochvil April 10, 2018, 7:58 p.m. | #2
Hi,

commit e80aaf6183c6692ecc167bf26cbdc53f8f1a55f0 (HEAD)
Author: Simon Marchi <simon.marchi@polymtl.ca>
Date:   Fri Mar 2 23:22:06 2018 -0500
    Make delim_string_to_char_ptr_vec return an std::vector

/usr/include/c++/7/debug/safe_iterator.h:297:
Error: attempt to increment a singular iterator.
Objects involved in the operation:
    iterator "this" @ 0x0x7fffffffd140 {
      type = __gnu_debug::_Safe_iterator<__gnu_cxx::__normal_iterator<std::unique_ptr<char, gdb::xfree_deleter<char> >*, std::__cxx1998::vector<std::unique_ptr<char, gdb::xfree_deleter<char> >, std::allocator<std::unique_ptr<char, gdb::xfree_deleter<char> > > > >, std::__debug::vector<std::unique_ptr<char, gdb::xfree_deleter<char> >, std::allocator<std::unique_ptr<char, gdb::xfree_deleter<char> > > > > (mutable iterator);
      state = singular;
      references sequence with type 'std::__debug::vector<std::unique_ptr<char, gdb::xfree_deleter<char> >, std::allocator<std::unique_ptr<char, gdb::xfree_deleter<char> > > >' @ 0x0x265db40
    }
#4  0x000000000078f893 in auto_load_safe_path_vec_update () at auto-load.c:212


On Sun, 25 Feb 2018 17:32:43 +0100, Simon Marchi wrote:
>    /* Apply tilde_expand and gdb_realpath to each AUTO_LOAD_SAFE_PATH_VEC

>       element.  */

> -  for (ix = 0; ix < len; ix++)

> +  for (gdb::unique_xmalloc_ptr<char> &in_vec : auto_load_safe_path_vec)

>      {

...
> -	  VEC_safe_push (char_ptr, auto_load_safe_path_vec,

> -			 real_path.release ());

> +	  auto_load_safe_path_vec.push_back (std::move (real_path));

>  	}

>      }

>  }


The iterator breaks when moving its std::vector data underneath it.
This is why the original C code did not use a pointer there.


Jan
Simon Marchi April 10, 2018, 8:32 p.m. | #3
On 2018-04-10 03:58 PM, Jan Kratochvil wrote:
> Hi,

> 

> commit e80aaf6183c6692ecc167bf26cbdc53f8f1a55f0 (HEAD)

> Author: Simon Marchi <simon.marchi@polymtl.ca>

> Date:   Fri Mar 2 23:22:06 2018 -0500

>     Make delim_string_to_char_ptr_vec return an std::vector

> 

> /usr/include/c++/7/debug/safe_iterator.h:297:

> Error: attempt to increment a singular iterator.

> Objects involved in the operation:

>     iterator "this" @ 0x0x7fffffffd140 {

>       type = __gnu_debug::_Safe_iterator<__gnu_cxx::__normal_iterator<std::unique_ptr<char, gdb::xfree_deleter<char> >*, std::__cxx1998::vector<std::unique_ptr<char, gdb::xfree_deleter<char> >, std::allocator<std::unique_ptr<char, gdb::xfree_deleter<char> > > > >, std::__debug::vector<std::unique_ptr<char, gdb::xfree_deleter<char> >, std::allocator<std::unique_ptr<char, gdb::xfree_deleter<char> > > > > (mutable iterator);

>       state = singular;

>       references sequence with type 'std::__debug::vector<std::unique_ptr<char, gdb::xfree_deleter<char> >, std::allocator<std::unique_ptr<char, gdb::xfree_deleter<char> > > >' @ 0x0x265db40

>     }

> #4  0x000000000078f893 in auto_load_safe_path_vec_update () at auto-load.c:212

> 

> 

> On Sun, 25 Feb 2018 17:32:43 +0100, Simon Marchi wrote:

>>    /* Apply tilde_expand and gdb_realpath to each AUTO_LOAD_SAFE_PATH_VEC

>>       element.  */

>> -  for (ix = 0; ix < len; ix++)

>> +  for (gdb::unique_xmalloc_ptr<char> &in_vec : auto_load_safe_path_vec)

>>      {

> ...

>> -	  VEC_safe_push (char_ptr, auto_load_safe_path_vec,

>> -			 real_path.release ());

>> +	  auto_load_safe_path_vec.push_back (std::move (real_path));

>>  	}

>>      }

>>  }

> 

> The iterator breaks when moving its std::vector data underneath it.

> This is why the original C code did not use a pointer there.

> 

> 

> Jan

> 


Of course, thanks for reporting.  Does this fix it?

From fddee555819b2631920bf4a86854bb0d76ac121f Mon Sep 17 00:00:00 2001
From: Simon Marchi <simon.marchi@ericsson.com>

Date: Tue, 10 Apr 2018 16:31:52 -0400
Subject: [PATCH] Iterate by index

---
 gdb/auto-load.c | 7 +++----
 1 file changed, 3 insertions(+), 4 deletions(-)

diff --git a/gdb/auto-load.c b/gdb/auto-load.c
index e426468..33d282a 100644
--- a/gdb/auto-load.c
+++ b/gdb/auto-load.c
@@ -197,20 +197,19 @@ auto_load_expand_dir_vars (const char *string)
 static void
 auto_load_safe_path_vec_update (void)
 {
-  unsigned len;
-  int ix;
-
   if (debug_auto_load)
     fprintf_unfiltered (gdb_stdlog,
 			_("auto-load: Updating directories of \"%s\".\n"),
 			auto_load_safe_path);

   auto_load_safe_path_vec = auto_load_expand_dir_vars (auto_load_safe_path);
+  size_t len = auto_load_safe_path_vec.size ();

   /* Apply tilde_expand and gdb_realpath to each AUTO_LOAD_SAFE_PATH_VEC
      element.  */
-  for (gdb::unique_xmalloc_ptr<char> &in_vec : auto_load_safe_path_vec)
+  for (size_t i = 0; i < len; i++)
     {
+      gdb::unique_xmalloc_ptr<char> &in_vec = auto_load_safe_path_vec[i];
       gdb::unique_xmalloc_ptr<char> expanded (tilde_expand (in_vec.get ()));
       gdb::unique_xmalloc_ptr<char> real_path = gdb_realpath (expanded.get ());

-- 
2.7.4
Jan Kratochvil April 10, 2018, 8:39 p.m. | #4
On Tue, 10 Apr 2018 22:32:46 +0200, Simon Marchi wrote:
> Of course, thanks for reporting.  Does this fix it?

> 

> >From fddee555819b2631920bf4a86854bb0d76ac121f Mon Sep 17 00:00:00 2001

> From: Simon Marchi <simon.marchi@ericsson.com>

> Date: Tue, 10 Apr 2018 16:31:52 -0400

> Subject: [PATCH] Iterate by index


Yes.


Jan
Simon Marchi April 10, 2018, 8:52 p.m. | #5
On 2018-04-10 04:39 PM, Jan Kratochvil wrote:
> On Tue, 10 Apr 2018 22:32:46 +0200, Simon Marchi wrote:

>> Of course, thanks for reporting.  Does this fix it?

>>

>> >From fddee555819b2631920bf4a86854bb0d76ac121f Mon Sep 17 00:00:00 2001

>> From: Simon Marchi <simon.marchi@ericsson.com>

>> Date: Tue, 10 Apr 2018 16:31:52 -0400

>> Subject: [PATCH] Iterate by index

> 

> Yes.


Thanks, here's what I pushed:

From 6e22e10d63addd60f39114cef81ade290b15b2c8 Mon Sep 17 00:00:00 2001
From: Simon Marchi <simon.marchi@ericsson.com>

Date: Tue, 10 Apr 2018 16:50:59 -0400
Subject: [PATCH] Iterate by index in auto_load_safe_path_vec_update

As reported by Jan, we get this error when building with -D_GLIBCXX_DEBUG:

/usr/include/c++/7/debug/safe_iterator.h:297:
Error: attempt to increment a singular iterator.
Objects involved in the operation:
    iterator "this" @ 0x0x7fffffffd140 {
      type = __gnu_debug::_Safe_iterator<__gnu_cxx::__normal_iterator<std::unique_ptr<char, gdb::xfree_deleter<char> >*, std::__cxx1998::vector<std::unique_ptr<char, gdb::xfree_deleter<char> >, std::allocator<std::unique_ptr<char, gdb::xfree_deleter<char> > > > >, std::__debug::vector<std::unique_ptr<char, gdb::xfree_deleter<char> >, std::allocator<std::unique_ptr<char, gdb::xfree_deleter<char> > > > > (mutable iterator);
      state = singular;
      references sequence with type 'std::__debug::vector<std::unique_ptr<char, gdb::xfree_deleter<char> >, std::allocator<std::unique_ptr<char, gdb::xfree_deleter<char> > > >' @ 0x0x265db40
    }

The bug was introduced by commit

commit e80aaf6183c6692ecc167bf26cbdc53f8f1a55f0
Author: Simon Marchi <simon.marchi@polymtl.ca>
Date:   Fri Mar 2 23:22:06 2018 -0500
Make delim_string_to_char_ptr_vec return an std::vector

The problem is that we iterate using a range-based for on a vector to
which we push in the loop.  Pushing to the vector invalidates the
iterator used in the loop.  Instead, change the code to iterate by index
as was done in the previous code.

gdb/ChangeLog:

	* auto-load.c (auto_load_safe_path_vec_update): Iterate by
	index.
---
 gdb/ChangeLog   | 5 +++++
 gdb/auto-load.c | 7 +++----
 2 files changed, 8 insertions(+), 4 deletions(-)

diff --git a/gdb/ChangeLog b/gdb/ChangeLog
index d46ecdd..6ed9d6c 100644
--- a/gdb/ChangeLog
+++ b/gdb/ChangeLog
@@ -1,3 +1,8 @@
+2018-04-10  Simon Marchi  <simon.marchi@ericsson.com>
+
+	* auto-load.c (auto_load_safe_path_vec_update): Iterate by
+	index.
+
 2018-04-10  Pedro Alves  <palves@redhat.com>

 	* gdbthread.h (finish_thread_state_cleanup): Delete declaration.
diff --git a/gdb/auto-load.c b/gdb/auto-load.c
index e426468..33d282a 100644
--- a/gdb/auto-load.c
+++ b/gdb/auto-load.c
@@ -197,20 +197,19 @@ auto_load_expand_dir_vars (const char *string)
 static void
 auto_load_safe_path_vec_update (void)
 {
-  unsigned len;
-  int ix;
-
   if (debug_auto_load)
     fprintf_unfiltered (gdb_stdlog,
 			_("auto-load: Updating directories of \"%s\".\n"),
 			auto_load_safe_path);

   auto_load_safe_path_vec = auto_load_expand_dir_vars (auto_load_safe_path);
+  size_t len = auto_load_safe_path_vec.size ();

   /* Apply tilde_expand and gdb_realpath to each AUTO_LOAD_SAFE_PATH_VEC
      element.  */
-  for (gdb::unique_xmalloc_ptr<char> &in_vec : auto_load_safe_path_vec)
+  for (size_t i = 0; i < len; i++)
     {
+      gdb::unique_xmalloc_ptr<char> &in_vec = auto_load_safe_path_vec[i];
       gdb::unique_xmalloc_ptr<char> expanded (tilde_expand (in_vec.get ()));
       gdb::unique_xmalloc_ptr<char> real_path = gdb_realpath (expanded.get ());

-- 
2.7.4

Patch

diff --git a/gdb/auto-load.c b/gdb/auto-load.c
index b79341faf6..b0fd626d91 100644
--- a/gdb/auto-load.c
+++ b/gdb/auto-load.c
@@ -168,19 +168,15 @@  static char *auto_load_safe_path;
 /* Vector of directory elements of AUTO_LOAD_SAFE_PATH with each one normalized
    by tilde_expand and possibly each entries has added its gdb_realpath
    counterpart.  */
-static VEC (char_ptr) *auto_load_safe_path_vec;
+std::vector<gdb::unique_xmalloc_ptr<char>> auto_load_safe_path_vec;
 
 /* Expand $datadir and $debugdir in STRING according to the rules of
-   substitute_path_component.  Return vector from dirnames_to_char_ptr_vec,
-   this vector must be freed by free_char_ptr_vec by the caller.  */
+   substitute_path_component.  */
 
-static VEC (char_ptr) *
+static std::vector<gdb::unique_xmalloc_ptr<char>>
 auto_load_expand_dir_vars (const char *string)
 {
-  VEC (char_ptr) *dir_vec;
-  char *s;
-
-  s = xstrdup (string);
+  char *s = xstrdup (string);
   substitute_path_component (&s, "$datadir", gdb_datadir);
   substitute_path_component (&s, "$debugdir", debug_file_directory);
 
@@ -188,7 +184,8 @@  auto_load_expand_dir_vars (const char *string)
     fprintf_unfiltered (gdb_stdlog,
 			_("auto-load: Expanded $-variables to \"%s\".\n"), s);
 
-  dir_vec = dirnames_to_char_ptr_vec (s);
+  std::vector<gdb::unique_xmalloc_ptr<char>> dir_vec
+    = dirnames_to_char_ptr_vec (s);
   xfree(s);
 
   return dir_vec;
@@ -207,46 +204,42 @@  auto_load_safe_path_vec_update (void)
 			_("auto-load: Updating directories of \"%s\".\n"),
 			auto_load_safe_path);
 
-  free_char_ptr_vec (auto_load_safe_path_vec);
-
   auto_load_safe_path_vec = auto_load_expand_dir_vars (auto_load_safe_path);
-  len = VEC_length (char_ptr, auto_load_safe_path_vec);
 
   /* Apply tilde_expand and gdb_realpath to each AUTO_LOAD_SAFE_PATH_VEC
      element.  */
-  for (ix = 0; ix < len; ix++)
+  for (gdb::unique_xmalloc_ptr<char> &in_vec : auto_load_safe_path_vec)
     {
-      char *dir = VEC_index (char_ptr, auto_load_safe_path_vec, ix);
-      char *expanded = tilde_expand (dir);
-      gdb::unique_xmalloc_ptr<char> real_path = gdb_realpath (expanded);
+      gdb::unique_xmalloc_ptr<char> expanded (tilde_expand (in_vec.get ()));
+      gdb::unique_xmalloc_ptr<char> real_path = gdb_realpath (expanded.get ());
 
-      /* Ensure the current entry is at least tilde_expand-ed.  */
-      VEC_replace (char_ptr, auto_load_safe_path_vec, ix, expanded);
+      /* Ensure the current entry is at least tilde_expand-ed.  ORIGINAL makes
+	 sure we free the original string.  */
+      gdb::unique_xmalloc_ptr<char> original = std::move (in_vec);
+      in_vec = std::move (expanded);
 
       if (debug_auto_load)
 	{
-	  if (strcmp (expanded, dir) == 0)
+	  if (strcmp (in_vec.get (), original.get ()) == 0)
 	    fprintf_unfiltered (gdb_stdlog,
 				_("auto-load: Using directory \"%s\".\n"),
-				expanded);
+				in_vec.get ());
 	  else
 	    fprintf_unfiltered (gdb_stdlog,
 				_("auto-load: Resolved directory \"%s\" "
 				  "as \"%s\".\n"),
-				dir, expanded);
+				original.get (), in_vec.get ());
 	}
-      xfree (dir);
 
       /* If gdb_realpath returns a different content, append it.  */
-      if (strcmp (real_path.get (), expanded) != 0)
+      if (strcmp (real_path.get (), in_vec.get ()) != 0)
 	{
 	  if (debug_auto_load)
 	    fprintf_unfiltered (gdb_stdlog,
 				_("auto-load: And canonicalized as \"%s\".\n"),
 				real_path.get ());
 
-	  VEC_safe_push (char_ptr, auto_load_safe_path_vec,
-			 real_path.release ());
+	  auto_load_safe_path_vec.push_back (std::move (real_path));
 	}
     }
 }
@@ -425,13 +418,14 @@  static int
 filename_is_in_auto_load_safe_path_vec (const char *filename,
 					gdb::unique_xmalloc_ptr<char> *filename_realp)
 {
-  char *pattern;
-  int ix;
+  const char *pattern = NULL;
 
-  for (ix = 0; VEC_iterate (char_ptr, auto_load_safe_path_vec, ix, pattern);
-       ++ix)
-    if (*filename_realp == NULL && filename_is_in_pattern (filename, pattern))
-      break;
+  for (const gdb::unique_xmalloc_ptr<char> &p : auto_load_safe_path_vec)
+    if (*filename_realp == NULL && filename_is_in_pattern (filename, p.get ()))
+      {
+	pattern = p.get ();
+	break;
+      }
   
   if (pattern == NULL)
     {
@@ -446,10 +440,12 @@  filename_is_in_auto_load_safe_path_vec (const char *filename,
 	}
 
       if (strcmp (filename_realp->get (), filename) != 0)
-	for (ix = 0;
-	     VEC_iterate (char_ptr, auto_load_safe_path_vec, ix, pattern); ++ix)
-	  if (filename_is_in_pattern (filename_realp->get (), pattern))
-	    break;
+	for (const gdb::unique_xmalloc_ptr<char> &p : auto_load_safe_path_vec)
+	  if (filename_is_in_pattern (filename_realp->get (), p.get ()))
+	    {
+	      pattern = p.get ();
+	      break;
+	    }
     }
 
   if (pattern != NULL)
@@ -792,25 +788,22 @@  auto_load_objfile_script_1 (struct objfile *objfile, const char *realname,
 
   if (!input)
     {
-      VEC (char_ptr) *vec;
-      int ix;
-      char *dir;
-
       /* Also try the same file in a subdirectory of gdb's data
 	 directory.  */
 
-      vec = auto_load_expand_dir_vars (auto_load_dir);
-      make_cleanup_free_char_ptr_vec (vec);
+      std::vector<gdb::unique_xmalloc_ptr<char>> vec
+	= auto_load_expand_dir_vars (auto_load_dir);
 
       if (debug_auto_load)
 	fprintf_unfiltered (gdb_stdlog, _("auto-load: Searching 'set auto-load "
 					  "scripts-directory' path \"%s\".\n"),
 			    auto_load_dir);
 
-      for (ix = 0; VEC_iterate (char_ptr, vec, ix, dir); ++ix)
+      for (const gdb::unique_xmalloc_ptr<char> &dir : vec)
 	{
-	  debugfile = (char *) xmalloc (strlen (dir) + strlen (filename) + 1);
-	  strcpy (debugfile, dir);
+	  debugfile = (char *) xmalloc (strlen (dir.get ())
+					+ strlen (filename) + 1);
+	  strcpy (debugfile, dir.get ());
 
 	  /* FILENAME is absolute, so we don't need a "/" here.  */
 	  strcat (debugfile, filename);
diff --git a/gdb/build-id.c b/gdb/build-id.c
index 685a2b0370..57d98c9618 100644
--- a/gdb/build-id.c
+++ b/gdb/build-id.c
@@ -71,8 +71,6 @@  gdb_bfd_ref_ptr
 build_id_to_debug_bfd (size_t build_id_len, const bfd_byte *build_id)
 {
   char *link, *debugdir;
-  VEC (char_ptr) *debugdir_vec;
-  struct cleanup *back_to;
   int ix;
   gdb_bfd_ref_ptr abfd;
   int alloc_len;
@@ -86,17 +84,17 @@  build_id_to_debug_bfd (size_t build_id_len, const bfd_byte *build_id)
   /* Keep backward compatibility so that DEBUG_FILE_DIRECTORY being "" will
      cause "/.build-id/..." lookups.  */
 
-  debugdir_vec = dirnames_to_char_ptr_vec (debug_file_directory);
-  back_to = make_cleanup_free_char_ptr_vec (debugdir_vec);
+  std::vector<gdb::unique_xmalloc_ptr<char>> debugdir_vec
+    = dirnames_to_char_ptr_vec (debug_file_directory);
 
-  for (ix = 0; VEC_iterate (char_ptr, debugdir_vec, ix, debugdir); ++ix)
+  for (const gdb::unique_xmalloc_ptr<char> &debugdir : debugdir_vec)
     {
-      size_t debugdir_len = strlen (debugdir);
+      size_t debugdir_len = strlen (debugdir.get ());
       const gdb_byte *data = build_id;
       size_t size = build_id_len;
       char *s;
 
-      memcpy (link, debugdir, debugdir_len);
+      memcpy (link, debugdir.get (), debugdir_len);
       s = &link[debugdir_len];
       s += sprintf (s, "/.build-id/");
       if (size > 0)
@@ -133,7 +131,6 @@  build_id_to_debug_bfd (size_t build_id_len, const bfd_byte *build_id)
       abfd.release ();
     }
 
-  do_cleanups (back_to);
   return abfd;
 }
 
diff --git a/gdb/common/gdb_vecs.c b/gdb/common/gdb_vecs.c
index a221460625..a19d238b3e 100644
--- a/gdb/common/gdb_vecs.c
+++ b/gdb/common/gdb_vecs.c
@@ -40,11 +40,12 @@  free_char_ptr_vec (VEC (char_ptr) *char_ptr_vec)
 }
 
 /* Worker function to split character delimiter separated string of fields
-   STR into a CHAR_PTR_VEC.  */
+   STR into a char pointer vector.  */
 
 static void
-delim_string_to_char_ptr_vec_append (VEC (char_ptr) **vecp,
-				     const char *str, char delimiter)
+delim_string_to_char_ptr_vec_append
+  (std::vector<gdb::unique_xmalloc_ptr<char>> *vecp, const char *str,
+   char delimiter)
 {
   do
     {
@@ -64,49 +65,40 @@  delim_string_to_char_ptr_vec_append (VEC (char_ptr) **vecp,
       this_field = (char *) xmalloc (this_len + 1);
       memcpy (this_field, str, this_len);
       this_field[this_len] = '\0';
-      VEC_safe_push (char_ptr, *vecp, this_field);
+      vecp->emplace_back (this_field);
 
       str = next_field;
     }
   while (str != NULL);
 }
 
-/* Split STR, a list of DELIMITER-separated fields, into a CHAR_PTR_VEC.
+/* See gdb_vecs.h.  */
 
-   You may modify the returned strings.
-   Read free_char_ptr_vec for its cleanup.  */
-
-VEC (char_ptr) *
+std::vector<gdb::unique_xmalloc_ptr<char>>
 delim_string_to_char_ptr_vec (const char *str, char delimiter)
 {
-  VEC (char_ptr) *retval = NULL;
+  std::vector<gdb::unique_xmalloc_ptr<char>> retval;
   
   delim_string_to_char_ptr_vec_append (&retval, str, delimiter);
 
   return retval;
 }
 
-/* Extended version of dirnames_to_char_ptr_vec - additionally if *VECP is
-   non-NULL the new list elements from DIRNAMES are appended to the existing
-   *VECP list of entries.  *VECP address will be updated by this call.  */
+/* See gdb_vecs.h.  */
 
 void
-dirnames_to_char_ptr_vec_append (VEC (char_ptr) **vecp, const char *dirnames)
+dirnames_to_char_ptr_vec_append
+  (std::vector<gdb::unique_xmalloc_ptr<char>> *vecp, const char *dirnames)
 {
   delim_string_to_char_ptr_vec_append (vecp, dirnames, DIRNAME_SEPARATOR);
 }
 
-/* Split DIRNAMES by DIRNAME_SEPARATOR delimiter and return a list of all the
-   elements in their original order.  For empty string ("") DIRNAMES return
-   list of one empty string ("") element.
-   
-   You may modify the returned strings.
-   Read free_char_ptr_vec for its cleanup.  */
+/* See gdb_vecs.h.  */
 
-VEC (char_ptr) *
+std::vector<gdb::unique_xmalloc_ptr<char>>
 dirnames_to_char_ptr_vec (const char *dirnames)
 {
-  VEC (char_ptr) *retval = NULL;
+  std::vector<gdb::unique_xmalloc_ptr<char>> retval;
   
   dirnames_to_char_ptr_vec_append (&retval, dirnames);
 
diff --git a/gdb/common/gdb_vecs.h b/gdb/common/gdb_vecs.h
index 75caf59c00..17ed06c253 100644
--- a/gdb/common/gdb_vecs.h
+++ b/gdb/common/gdb_vecs.h
@@ -31,15 +31,25 @@  DEF_VEC_P (const_char_ptr);
 
 extern void free_char_ptr_vec (VEC (char_ptr) *char_ptr_vec);
 
-extern struct cleanup *
-  make_cleanup_free_char_ptr_vec (VEC (char_ptr) *char_ptr_vec);
+/* Split STR, a list of DELIMITER-separated fields, into a char pointer vector.
 
-extern VEC (char_ptr) *delim_string_to_char_ptr_vec (const char *str,
-						     char delimiter);
+   You may modify the returned strings.  */
 
-extern void dirnames_to_char_ptr_vec_append (VEC (char_ptr) **vecp,
-					     const char *dirnames);
+extern std::vector<gdb::unique_xmalloc_ptr<char>>
+  delim_string_to_char_ptr_vec (const char *str, char delimiter);
 
-extern VEC (char_ptr) *dirnames_to_char_ptr_vec (const char *dirnames);
+/* Like dirnames_to_char_ptr_vec, but append the directories to *VECP.  */
+
+extern void dirnames_to_char_ptr_vec_append
+  (std::vector<gdb::unique_xmalloc_ptr<char>> *vecp, const char *dirnames);
+
+/* Split DIRNAMES by DIRNAME_SEPARATOR delimiter and return a list of all the
+   elements in their original order.  For empty string ("") DIRNAMES return
+   list of one empty string ("") element.
+
+   You may modify the returned strings.  */
+
+extern std::vector<gdb::unique_xmalloc_ptr<char>>
+  dirnames_to_char_ptr_vec (const char *dirnames);
 
 #endif /* GDB_VECS_H */
diff --git a/gdb/gdbserver/server.c b/gdb/gdbserver/server.c
index cb02b58507..bfb639570f 100644
--- a/gdb/gdbserver/server.c
+++ b/gdb/gdbserver/server.c
@@ -1275,8 +1275,8 @@  handle_detach (char *own_buf)
    ARG is the text after "--debug-format=" or "monitor set debug-format".
    IS_MONITOR is non-zero if we're invoked via "monitor set debug-format".
    This triggers calls to monitor_output.
-   The result is NULL if all options were parsed ok, otherwise an error
-   message which the caller must free.
+   The result is an empty string if all options were parsed ok, otherwise an
+   error message which the caller must free.
 
    N.B. These commands affect all debug format settings, they are not
    cumulative.  If a format is not specified, it is turned off.
@@ -1291,10 +1291,6 @@  handle_detach (char *own_buf)
 static std::string
 parse_debug_format_options (const char *arg, int is_monitor)
 {
-  VEC (char_ptr) *options;
-  int ix;
-  char *option;
-
   /* First turn all debug format options off.  */
   debug_timestamp = 0;
 
@@ -1302,23 +1298,24 @@  parse_debug_format_options (const char *arg, int is_monitor)
   while (isspace (*arg))
     ++arg;
 
-  options = delim_string_to_char_ptr_vec (arg, ',');
+  std::vector<gdb::unique_xmalloc_ptr<char>> options
+    = delim_string_to_char_ptr_vec (arg, ',');
 
-  for (ix = 0; VEC_iterate (char_ptr, options, ix, option); ++ix)
+  for (const gdb::unique_xmalloc_ptr<char> &option : options)
     {
-      if (strcmp (option, "all") == 0)
+      if (strcmp (option.get (), "all") == 0)
 	{
 	  debug_timestamp = 1;
 	  if (is_monitor)
 	    monitor_output ("All extra debug format options enabled.\n");
 	}
-      else if (strcmp (option, "none") == 0)
+      else if (strcmp (option.get (), "none") == 0)
 	{
 	  debug_timestamp = 0;
 	  if (is_monitor)
 	    monitor_output ("All extra debug format options disabled.\n");
 	}
-      else if (strcmp (option, "timestamp") == 0)
+      else if (strcmp (option.get (), "timestamp") == 0)
 	{
 	  debug_timestamp = 1;
 	  if (is_monitor)
@@ -1330,16 +1327,10 @@  parse_debug_format_options (const char *arg, int is_monitor)
 	  continue;
 	}
       else
-	{
-	  std::string msg
-	    = string_printf ("Unknown debug-format argument: \"%s\"\n", option);
-
-	  free_char_ptr_vec (options);
-	  return msg;
-	}
+	return string_printf ("Unknown debug-format argument: \"%s\"\n",
+			      option.get ());
     }
 
-  free_char_ptr_vec (options);
   return std::string ();
 }
 
diff --git a/gdb/gdbserver/thread-db.c b/gdb/gdbserver/thread-db.c
index 812aa0f61f..7dda2edba0 100644
--- a/gdb/gdbserver/thread-db.c
+++ b/gdb/gdbserver/thread-db.c
@@ -683,17 +683,17 @@  try_thread_db_load_from_dir (const char *dir, size_t dir_len)
 static int
 thread_db_load_search (void)
 {
-  VEC (char_ptr) *dir_vec;
-  char *this_dir;
-  int i, rc = 0;
+  int rc = 0;
 
   if (libthread_db_search_path == NULL)
     libthread_db_search_path = xstrdup (LIBTHREAD_DB_SEARCH_PATH);
 
-  dir_vec = dirnames_to_char_ptr_vec (libthread_db_search_path);
+  std::vector<gdb::unique_xmalloc_ptr<char>> dir_vec
+    = dirnames_to_char_ptr_vec (libthread_db_search_path);
 
-  for (i = 0; VEC_iterate (char_ptr, dir_vec, i, this_dir); ++i)
+  for (const gdb::unique_xmalloc_ptr<char> &this_dir_up : dir_vec)
     {
+      char *this_dir = this_dir_up.get ();
       const int pdir_len = sizeof ("$pdir") - 1;
       size_t this_dir_len;
 
@@ -725,7 +725,6 @@  thread_db_load_search (void)
 	}
     }
 
-  free_char_ptr_vec (dir_vec);
   if (debug_threads)
     debug_printf ("thread_db_load_search returning %d\n", rc);
   return rc;
diff --git a/gdb/linux-thread-db.c b/gdb/linux-thread-db.c
index 5ba4c03df6..8217201fe5 100644
--- a/gdb/linux-thread-db.c
+++ b/gdb/linux-thread-db.c
@@ -803,16 +803,14 @@  try_thread_db_load_from_dir (const char *dir, size_t dir_len)
 static int
 thread_db_load_search (void)
 {
-  VEC (char_ptr) *dir_vec;
-  struct cleanup *cleanups;
-  char *this_dir;
-  int i, rc = 0;
+  int rc = 0;
 
-  dir_vec = dirnames_to_char_ptr_vec (libthread_db_search_path);
-  cleanups = make_cleanup_free_char_ptr_vec (dir_vec);
+  std::vector<gdb::unique_xmalloc_ptr<char>> dir_vec
+    = dirnames_to_char_ptr_vec (libthread_db_search_path);
 
-  for (i = 0; VEC_iterate (char_ptr, dir_vec, i, this_dir); ++i)
+  for (const gdb::unique_xmalloc_ptr<char> &this_dir_up : dir_vec)
     {
+      const char *this_dir = this_dir_up.get ();
       const int pdir_len = sizeof ("$pdir") - 1;
       size_t this_dir_len;
 
@@ -852,7 +850,6 @@  thread_db_load_search (void)
 	}
     }
 
-  do_cleanups (cleanups);
   if (libthread_db_debug)
     fprintf_unfiltered (gdb_stdlog,
 			_("thread_db_load_search returning %d\n"), rc);
diff --git a/gdb/source.c b/gdb/source.c
index 8a27b2e666..cea613cb31 100644
--- a/gdb/source.c
+++ b/gdb/source.c
@@ -461,10 +461,7 @@  add_path (const char *dirname, char **which_path, int parse_separators)
 {
   char *old = *which_path;
   int prefix = 0;
-  VEC (char_ptr) *dir_vec = NULL;
-  struct cleanup *back_to;
-  int ix;
-  char *name;
+  std::vector<gdb::unique_xmalloc_ptr<char>> dir_vec;
 
   if (dirname == 0)
     return;
@@ -479,11 +476,13 @@  add_path (const char *dirname, char **which_path, int parse_separators)
 	dirnames_to_char_ptr_vec_append (&dir_vec, arg);
     }
   else
-    VEC_safe_push (char_ptr, dir_vec, xstrdup (dirname));
-  back_to = make_cleanup_free_char_ptr_vec (dir_vec);
+    dir_vec.emplace_back (xstrdup (dirname));
 
-  for (ix = 0; VEC_iterate (char_ptr, dir_vec, ix, name); ++ix)
+  struct cleanup *back_to = make_cleanup (null_cleanup, NULL);
+
+  for (const gdb::unique_xmalloc_ptr<char> &name_up : dir_vec)
     {
+      char *name = name_up.get ();
       char *p;
       struct stat st;
 
@@ -742,13 +741,10 @@  openp (const char *path, openp_flags opts, const char *string,
   int fd;
   char *filename;
   int alloclen;
-  VEC (char_ptr) *dir_vec;
-  struct cleanup *back_to;
-  int ix;
-  char *dir;
   /* The errno set for the last name we tried to open (and
      failed).  */
   int last_errno = 0;
+  std::vector<gdb::unique_xmalloc_ptr<char>> dir_vec;
 
   /* The open syscall MODE parameter is not specified.  */
   gdb_assert ((mode & O_CREAT) == 0);
@@ -816,10 +812,10 @@  openp (const char *path, openp_flags opts, const char *string,
   last_errno = ENOENT;
 
   dir_vec = dirnames_to_char_ptr_vec (path);
-  back_to = make_cleanup_free_char_ptr_vec (dir_vec);
 
-  for (ix = 0; VEC_iterate (char_ptr, dir_vec, ix, dir); ++ix)
+  for (const gdb::unique_xmalloc_ptr<char> &dir_up : dir_vec)
     {
+      char *dir = dir_up.get ();
       size_t len = strlen (dir);
       int reg_file_errno;
 
@@ -889,8 +885,6 @@  openp (const char *path, openp_flags opts, const char *string,
 	last_errno = reg_file_errno;
     }
 
-  do_cleanups (back_to);
-
 done:
   if (filename_opened)
     {
diff --git a/gdb/symfile.c b/gdb/symfile.c
index 699d9e6fe0..866e533723 100644
--- a/gdb/symfile.c
+++ b/gdb/symfile.c
@@ -1439,12 +1439,8 @@  find_separate_debug_file (const char *dir,
 			  const char *debuglink,
 			  unsigned long crc32, struct objfile *objfile)
 {
-  char *debugdir;
   char *debugfile;
   int i;
-  VEC (char_ptr) *debugdir_vec;
-  struct cleanup *back_to;
-  int ix;
 
   if (separate_debug_file_debug)
     printf_unfiltered (_("\nLooking for separate debug info (debug link) for "
@@ -1484,21 +1480,18 @@  find_separate_debug_file (const char *dir,
      Keep backward compatibility so that DEBUG_FILE_DIRECTORY being "" will
      cause "/..." lookups.  */
 
-  debugdir_vec = dirnames_to_char_ptr_vec (debug_file_directory);
-  back_to = make_cleanup_free_char_ptr_vec (debugdir_vec);
+  std::vector<gdb::unique_xmalloc_ptr<char>> debugdir_vec
+    = dirnames_to_char_ptr_vec (debug_file_directory);
 
-  for (ix = 0; VEC_iterate (char_ptr, debugdir_vec, ix, debugdir); ++ix)
+  for (const gdb::unique_xmalloc_ptr<char> &debugdir : debugdir_vec)
     {
-      strcpy (debugfile, debugdir);
+      strcpy (debugfile, debugdir.get ());
       strcat (debugfile, "/");
       strcat (debugfile, dir);
       strcat (debugfile, debuglink);
 
       if (separate_debug_file_exists (debugfile, crc32, objfile))
-	{
-	  do_cleanups (back_to);
-	  return debugfile;
-	}
+	return debugfile;
 
       /* If the file is in the sysroot, try using its base path in the
 	 global debugfile directory.  */
@@ -1507,20 +1500,16 @@  find_separate_debug_file (const char *dir,
 			    strlen (gdb_sysroot)) == 0
 	  && IS_DIR_SEPARATOR (canon_dir[strlen (gdb_sysroot)]))
 	{
-	  strcpy (debugfile, debugdir);
+	  strcpy (debugfile, debugdir.get ());
 	  strcat (debugfile, canon_dir + strlen (gdb_sysroot));
 	  strcat (debugfile, "/");
 	  strcat (debugfile, debuglink);
 
 	  if (separate_debug_file_exists (debugfile, crc32, objfile))
-	    {
-	      do_cleanups (back_to);
-	      return debugfile;
-	    }
+	    return debugfile;
 	}
     }
 
-  do_cleanups (back_to);
   xfree (debugfile);
   return NULL;
 }
diff --git a/gdb/utils.c b/gdb/utils.c
index c531748fe4..269b8803d1 100644
--- a/gdb/utils.c
+++ b/gdb/utils.c
@@ -3170,30 +3170,6 @@  make_bpstat_clear_actions_cleanup (void)
   return make_cleanup (do_bpstat_clear_actions_cleanup, NULL);
 }
 
-
-/* Helper for make_cleanup_free_char_ptr_vec.  */
-
-static void
-do_free_char_ptr_vec (void *arg)
-{
-  VEC (char_ptr) *char_ptr_vec = (VEC (char_ptr) *) arg;
-
-  free_char_ptr_vec (char_ptr_vec);
-}
-
-/* Make cleanup handler calling xfree for each element of CHAR_PTR_VEC and
-   final VEC_free for CHAR_PTR_VEC itself.
-
-   You must not modify CHAR_PTR_VEC after this cleanup registration as the
-   CHAR_PTR_VEC base address may change on its updates.  Contrary to VEC_free
-   this function does not (cannot) clear the pointer.  */
-
-struct cleanup *
-make_cleanup_free_char_ptr_vec (VEC (char_ptr) *char_ptr_vec)
-{
-  return make_cleanup (do_free_char_ptr_vec, char_ptr_vec);
-}
-
 /* Substitute all occurences of string FROM by string TO in *STRINGP.  *STRINGP
    must come from xrealloc-compatible allocator and it may be updated.  FROM
    needs to be delimited by IS_DIR_SEPARATOR or DIRNAME_SEPARATOR (or be