Introduce gdb::byte_vector, add allocator that default-initializes
authorPedro Alves <palves@redhat.com>
Wed, 14 Jun 2017 10:08:52 +0000 (11:08 +0100)
committerPedro Alves <palves@redhat.com>
Wed, 14 Jun 2017 10:08:52 +0000 (11:08 +0100)
In some cases we've been replacing heap-allocated gdb_byte buffers
managed with xmalloc/make_cleanup(xfree) with gdb::vector<gdb_byte>.
That usually pessimizes the code a little bit because std::vector
value-initializes elements (which for gdb_byte means
zero-initialization), while if you're creating a temporary buffer,
you're most certaintly going to fill it in with some data.  An
alternative is to use

  unique_ptr<gdb_byte[]> buf (new gdb_byte[size]);

but it looks like that's not very popular.

Recently, a use of obstacks in dwarf2read.c was replaced with
std::vector<gdb_byte> and that as well introduced a pessimization for
always memsetting the buffer when it's garanteed that the zeros will
be overwritten immediately.  (see dwarf2read.c change in this patch to
find it.)

So here's a different take at addressing this issue "by design":

#1 - Introduce default_init_allocator<T>

I.e., a custom allocator that does default construction using default
initialization, meaning, no more zero initialization.  That's the
default_init_allocation<T> class added in this patch.

See "Notes" at
<http://en.cppreference.com/w/cpp/container/vector/resize>.

#2 - Introduce def_vector<T>

I.e., a convenience typedef, because typing the allocator is annoying:

  using def_vector<T> = std::vector<T, gdb::default_init_allocator<T>>;

#3 - Introduce byte_vector

Because gdb_byte vectors will be the common thing, add a convenience
"byte_vector" typedef:

  using byte_vector = def_vector<gdb_byte>;

which is really the same as:

  std::vector<gdb_byte, gdb::default_init_allocator<gdb_byte>>;

The intent then is to make "gdb::byte_vector" be the go-to for dynamic
byte buffers.  So the less friction, the better.

#4 - Adjust current code to use it.

To set the example going forward.  Replace std::vector uses and also
unique_ptr<byte[]> uses.

One nice thing is that with this allocator, for changes like these:

  -std::unique_ptr<byte[]> buf (new gdb_byte[some_size]);
  +gdb::byte_vector buf (some_size);
   fill_with_data (buf.data (), buf.size ());

the generated code is the same as before.  I.e., the compiler
de-structures the vector and gets rid of the unused "reserved vs size"
related fields.

The other nice thing is that it's easier to write
  gdb::byte_vector buf (size);
than
  std::unique_ptr<gdb_byte[]> buf (new gdb_byte[size]);
or even (C++14):
  auto buf = std::make_unique<gdb_byte[]> (size); // zero-initializes...

#5 - Suggest s/std::vector<gdb_byte>/gdb::byte_vector/ going forward.

Note that this commit actually fixes a couple of bugs where the current
code is incorrectly using "std::vector::reserve(new_size)" and then
accessing the vector's internal buffer beyond the vector's size: see
dwarf2loc.c and charset.c.  That's undefined behavior and may trigger
debug mode assertion failures.  With default_init_allocator,
"resize()" behaves like "reserve()" performance wise, in that it
leaves new elements with unspecified values, but, it does that safely
without triggering undefined behavior when you access those values.

gdb/ChangeLog:
2017-06-14  Pedro Alves  <palves@redhat.com>

* ada-lang.c: Include "common/byte-vector.h".
(ada_value_primitive_packed_val): Use gdb::byte_vector.
* charset.c (wchar_iterator::iterate): Resize the vector instead
of reserving it.
* common/byte-vector.h: Include "common/def-vector.h".
(wchar_iterator::m_out): Now a gdb::def_vector<gdb_wchar_t>.
* cli/cli-dump.c: Include "common/byte-vector.h".
(dump_memory_to_file, restore_binary_file): Use gdb::byte_vector.
* common/byte-vector.h: New file.
* common/def-vector.h: New file.
* common/default-init-alloc.h: New file.
* dwarf2loc.c: Include "common/byte-vector.h".
(rw_pieced_value): Use gdb::byte_vector, and resize the vector
instead of reserving it.
* dwarf2read.c: Include "common/byte-vector.h".
(data_buf::m_vec): Now a gdb::byte_vector.
* gdb_regex.c: Include "common/def-vector.h".
(compiled_regex::compiled_regex): Use gdb::def_vector<char>.
* mi/mi-main.c: Include "common/byte-vector.h".
(mi_cmd_data_read_memory): Use gdb::byte_vector.
* printcmd.c: Include "common/byte-vector.h".
(print_scalar_formatted): Use gdb::byte_vector.
* valprint.c: Include "common/byte-vector.h".
(maybe_negate_by_bytes, print_decimal_chars): Use
gdb::byte_vector.

14 files changed:
gdb/ChangeLog
gdb/ada-lang.c
gdb/charset.c
gdb/charset.h
gdb/cli/cli-dump.c
gdb/common/byte-vector.h [new file with mode: 0644]
gdb/common/def-vector.h [new file with mode: 0644]
gdb/common/default-init-alloc.h [new file with mode: 0644]
gdb/dwarf2loc.c
gdb/dwarf2read.c
gdb/gdb_regex.c
gdb/mi/mi-main.c
gdb/printcmd.c
gdb/valprint.c

index 8eb9e06a32e0df018c69b325e3872e870b4a7584..07862c8a91bf3d1091e5f258fe7b3148418e4190 100644 (file)
@@ -1,3 +1,31 @@
+2017-06-14  Pedro Alves  <palves@redhat.com>
+
+       * ada-lang.c: Include "common/byte-vector.h".
+       (ada_value_primitive_packed_val): Use gdb::byte_vector.
+       * charset.c (wchar_iterator::iterate): Resize the vector instead
+       of reserving it.
+       * common/byte-vector.h: Include "common/def-vector.h".
+       (wchar_iterator::m_out): Now a gdb::def_vector<gdb_wchar_t>.
+       * cli/cli-dump.c: Include "common/byte-vector.h".
+       (dump_memory_to_file, restore_binary_file): Use gdb::byte_vector.
+       * common/byte-vector.h: New file.
+       * common/def-vector.h: New file.
+       * common/default-init-alloc.h: New file.
+       * dwarf2loc.c: Include "common/byte-vector.h".
+       (rw_pieced_value): Use gdb::byte_vector, and resize the vector
+       instead of reserving it.
+       * dwarf2read.c: Include "common/byte-vector.h".
+       (data_buf::m_vec): Now a gdb::byte_vector.
+       * gdb_regex.c: Include "common/def-vector.h".
+       (compiled_regex::compiled_regex): Use gdb::def_vector<char>.
+       * mi/mi-main.c: Include "common/byte-vector.h".
+       (mi_cmd_data_read_memory): Use gdb::byte_vector.
+       * printcmd.c: Include "common/byte-vector.h".
+       (print_scalar_formatted): Use gdb::byte_vector.
+       * valprint.c: Include "common/byte-vector.h".
+       (maybe_negate_by_bytes, print_decimal_chars): Use
+       gdb::byte_vector.
+
 2017-06-13  Simon Marchi  <simon.marchi@ericsson.com>
 
        * darwin-nat.c: Include "nat/fork-inferior.h".
index 57c670e8d6163bc98448640abdbba5ea4cf51a85..ea60df20e7cd37b770c0bd311ac4532015b24059 100644 (file)
@@ -61,6 +61,7 @@
 #include "arch-utils.h"
 #include "cli/cli-utils.h"
 #include "common/function-view.h"
+#include "common/byte-vector.h"
 
 /* Define whether or not the C operator '/' truncates towards zero for
    differently signed operands (truncation direction is undefined in C).
@@ -2567,8 +2568,7 @@ ada_value_primitive_packed_val (struct value *obj, const gdb_byte *valaddr,
   gdb_byte *unpacked;
   const int is_scalar = is_scalar_type (type);
   const int is_big_endian = gdbarch_bits_big_endian (get_type_arch (type));
-  std::unique_ptr<gdb_byte[]> staging;
-  int staging_len = 0;
+  gdb::byte_vector staging;
 
   type = ada_check_typedef (type);
 
@@ -2586,14 +2586,14 @@ ada_value_primitive_packed_val (struct value *obj, const gdb_byte *valaddr,
         packed, and therefore maybe not at a byte boundary.  So, what
         we do, is unpack the data into a byte-aligned buffer, and then
         use that buffer as our object's value for resolving the type.  */
-      staging_len = (bit_size + HOST_CHAR_BIT - 1) / HOST_CHAR_BIT;
-      staging.reset (new gdb_byte[staging_len]);
+      int staging_len = (bit_size + HOST_CHAR_BIT - 1) / HOST_CHAR_BIT;
+      staging.resize (staging_len);
 
       ada_unpack_from_contents (src, bit_offset, bit_size,
-                               staging.get (), staging_len,
+                               staging.data (), staging.size (),
                                is_big_endian, has_negatives (type),
                                is_scalar);
-      type = resolve_dynamic_type (type, staging.get (), 0);
+      type = resolve_dynamic_type (type, staging.data (), 0);
       if (TYPE_LENGTH (type) < (bit_size + HOST_CHAR_BIT - 1) / HOST_CHAR_BIT)
        {
          /* This happens when the length of the object is dynamic,
@@ -2656,12 +2656,12 @@ ada_value_primitive_packed_val (struct value *obj, const gdb_byte *valaddr,
       return v;
     }
 
-  if (staging != NULL && staging_len == TYPE_LENGTH (type))
+  if (staging.size () == TYPE_LENGTH (type))
     {
       /* Small short-cut: If we've unpacked the data into a buffer
         of the same size as TYPE's length, then we can reuse that,
         instead of doing the unpacking again.  */
-      memcpy (unpacked, staging.get (), staging_len);
+      memcpy (unpacked, staging.data (), staging.size ());
     }
   else
     ada_unpack_from_contents (src, bit_offset, bit_size,
index f55e482b24b8e4f869b54295a119b020605f41d7..dbe46a46a9356a6c8f0230aa74b3f9e01506acce 100644 (file)
@@ -673,7 +673,7 @@ wchar_iterator::iterate (enum wchar_iterate_result *out_result,
 
              ++out_request;
              if (out_request > m_out.size ())
-               m_out.reserve (out_request);
+               m_out.resize (out_request);
              continue;
 
            case EINVAL:
index 51180e3babb1ec91db2b8cb40a1cae0e678a6e7e..821974a718190c1817f5396938adbda832417736 100644 (file)
@@ -19,7 +19,7 @@
 #ifndef CHARSET_H
 #define CHARSET_H
 
-#include <vector>
+#include "common/def-vector.h"
 
 /* If the target program uses a different character set than the host,
    GDB has some support for translating between the two; GDB converts
@@ -144,7 +144,7 @@ class wchar_iterator
   size_t m_width;
 
   /* The output buffer.  */
-  std::vector<gdb_wchar_t> m_out;
+  gdb::def_vector<gdb_wchar_t> m_out;
 };
 
 \f
index 213622d8f35d5354cf9e164b712b56ba7ab179a5..d6d4aab345d396c05950a758360040211d1e269c 100644 (file)
@@ -31,7 +31,7 @@
 #include "cli/cli-utils.h"
 #include "gdb_bfd.h"
 #include "filestuff.h"
-
+#include "common/byte-vector.h"
 
 static const char *
 scan_expression_with_cleanup (const char **cmd, const char *def)
@@ -230,17 +230,17 @@ dump_memory_to_file (const char *cmd, const char *mode, const char *file_format)
 
   /* FIXME: Should use read_memory_partial() and a magic blocking
      value.  */
-  std::unique_ptr<gdb_byte[]> buf (new gdb_byte[count]);
-  read_memory (lo, buf.get (), count);
+  gdb::byte_vector buf (count);
+  read_memory (lo, buf.data (), count);
   
   /* Have everything.  Open/write the data.  */
   if (file_format == NULL || strcmp (file_format, "binary") == 0)
     {
-      dump_binary_file (filename, mode, buf.get (), count);
+      dump_binary_file (filename, mode, buf.data (), count);
     }
   else
     {
-      dump_bfd_file (filename, mode, file_format, lo, buf.get (), count);
+      dump_bfd_file (filename, mode, file_format, lo, buf.data (), count);
     }
 
   do_cleanups (old_cleanups);
@@ -545,13 +545,13 @@ restore_binary_file (const char *filename, struct callback_data *data)
     perror_with_name (filename);
 
   /* Now allocate a buffer and read the file contents.  */
-  std::unique_ptr<gdb_byte[]> buf (new gdb_byte[len]);
-  if (fread (buf.get (), 1, len, file) != len)
+  gdb::byte_vector buf (len);
+  if (fread (buf.data (), 1, len, file) != len)
     perror_with_name (filename);
 
   /* Now write the buffer into target memory.  */
   len = target_write_memory (data->load_start + data->load_offset,
-                            buf.get (), len);
+                            buf.data (), len);
   if (len != 0)
     warning (_("restore: memory write failed (%s)."), safe_strerror (len));
   do_cleanups (cleanup);
diff --git a/gdb/common/byte-vector.h b/gdb/common/byte-vector.h
new file mode 100644 (file)
index 0000000..c17b14d
--- /dev/null
@@ -0,0 +1,62 @@
+/* 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/>.  */
+
+#ifndef COMMON_BYTE_VECTOR_H
+#define COMMON_BYTE_VECTOR_H
+
+#include "common/def-vector.h"
+
+namespace gdb {
+
+/* byte_vector is a gdb_byte std::vector with a custom allocator that
+   unlike std::vector<gdb_byte> does not zero-initialize new elements
+   by default when the vector is created/resized.  This is what you
+   usually want when working with byte buffers, since if you're
+   creating or growing a buffer you'll most surely want to fill it in
+   with data, in which case zero-initialization would be a
+   pessimization.  For example:
+
+     gdb::byte_vector buf (some_large_size);
+     fill_with_data (buf.data (), buf.size ());
+
+   On the odd case you do need zero initialization, then you can still
+   call the overloads that specify an explicit value, like:
+
+     gdb::byte_vector buf (some_initial_size, 0);
+     buf.resize (a_bigger_size, 0);
+
+   (Or use std::vector<gdb_byte> instead.)
+
+   Note that unlike std::vector<gdb_byte>, function local
+   gdb::byte_vector objects constructed with an initial size like:
+
+     gdb::byte_vector buf (some_size);
+     fill_with_data (buf.data (), buf.size ());
+
+   usually compile down to the exact same as:
+
+     std::unique_ptr<byte[]> buf (new gdb_byte[some_size]);
+     fill_with_data (buf.get (), some_size);
+
+   with the former having the advantage of being a bit more readable,
+   and providing the whole std::vector API, if you end up needing it.
+*/
+using byte_vector = gdb::def_vector<gdb_byte>;
+
+} /* namespace gdb */
+
+#endif /* COMMON_DEF_VECTOR_H */
diff --git a/gdb/common/def-vector.h b/gdb/common/def-vector.h
new file mode 100644 (file)
index 0000000..ab9331f
--- /dev/null
@@ -0,0 +1,36 @@
+/* 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/>.  */
+
+#ifndef COMMON_DEF_VECTOR_H
+#define COMMON_DEF_VECTOR_H
+
+#include <vector>
+#include "common/default-init-alloc.h"
+
+namespace gdb {
+
+/* A vector that uses an allocator that default constructs using
+   default-initialization rather than value-initialization.  The idea
+   is to use this when you don't want zero-initialization of elements
+   of vectors of trivial types.  E.g., byte buffers.  */
+
+template<typename T> using def_vector
+  = std::vector<T, gdb::default_init_allocator<T>>;
+
+} /* namespace gdb */
+
+#endif /* COMMON_DEF_VECTOR_H */
diff --git a/gdb/common/default-init-alloc.h b/gdb/common/default-init-alloc.h
new file mode 100644 (file)
index 0000000..4fb852f
--- /dev/null
@@ -0,0 +1,67 @@
+/* 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/>.  */
+
+#ifndef COMMON_DEFAULT_INIT_ALLOC_H
+#define COMMON_DEFAULT_INIT_ALLOC_H
+
+namespace gdb {
+
+/* An allocator that default constructs using default-initialization
+   rather than value-initialization.  The idea is to use this when you
+   don't want to default construct elements of containers of trivial
+   types using zero-initialization.  */
+
+/* Mostly as implementation convenience, this is implemented as an
+   adapter that given an allocator A, overrides 'A::construct()'.  'A'
+   defaults to std::allocator<T>.  */
+
+template<typename T, typename A = std::allocator<T>>
+class default_init_allocator : public A
+{
+public:
+  /* Pull in A's ctors.  */
+  using A::A;
+
+  /* Override rebind.  */
+  template<typename U>
+  struct rebind
+  {
+    /* A couple helpers just to make it a bit more readable.  */
+    typedef std::allocator_traits<A> traits_;
+    typedef typename traits_::template rebind_alloc<U> alloc_;
+
+    /* This is what we're after.  */
+    typedef default_init_allocator<U, alloc_> other;
+  };
+
+  /* Make the base allocator's construct method(s) visible.  */
+  using A::construct;
+
+  /* .. and provide an override/overload for the case of default
+     construction (i.e., no arguments).  This is where we construct
+     with default-init.  */
+  template <typename U>
+  void construct (U *ptr)
+    noexcept (std::is_nothrow_default_constructible<U>::value)
+  {
+    ::new ((void *) ptr) U; /* default-init */
+  }
+};
+
+} /* namespace gdb */
+
+#endif /* COMMON_DEFAULT_INIT_ALLOC_H */
index 059fcfeb6139466633dc0e850e2d2579cf9cad3e..08b0aa2ccce7dd60e47e845669231bfb4164d51a 100644 (file)
@@ -43,6 +43,7 @@
 #include <vector>
 #include <unordered_set>
 #include "common/underlying.h"
+#include "common/byte-vector.h"
 
 extern int dwarf_always_disassemble;
 
@@ -1776,7 +1777,7 @@ rw_pieced_value (struct value *v, struct value *from)
   const gdb_byte *from_contents;
   struct piece_closure *c
     = (struct piece_closure *) value_computed_closure (v);
-  std::vector<gdb_byte> buffer;
+  gdb::byte_vector buffer;
   int bits_big_endian
     = gdbarch_bits_big_endian (get_type_arch (value_type (v)));
 
@@ -1847,7 +1848,7 @@ rw_pieced_value (struct value *v, struct value *from)
              bits_to_skip += p->offset;
 
            this_size = bits_to_bytes (bits_to_skip, this_size_bits);
-           buffer.reserve (this_size);
+           buffer.resize (this_size);
 
            if (from == NULL)
              {
@@ -1928,7 +1929,7 @@ rw_pieced_value (struct value *v, struct value *from)
              }
 
            this_size = bits_to_bytes (bits_to_skip, this_size_bits);
-           buffer.reserve (this_size);
+           buffer.resize (this_size);
 
            if (from == NULL)
              {
index 3f872b747834c6de90c37d9978133fa92e8998a2..abe14b25fd37a07c602e1497b5398dd4af9d5dd0 100644 (file)
@@ -73,6 +73,7 @@
 #include "common/function-view.h"
 #include "common/gdb_optional.h"
 #include "common/underlying.h"
+#include "common/byte-vector.h"
 
 #include <fcntl.h>
 #include <sys/types.h>
@@ -23245,7 +23246,7 @@ private:
     return &*m_vec.end () - size;
   }
 
-  std::vector<gdb_byte> m_vec;
+  gdb::byte_vector m_vec;
 };
 
 /* An entry in the symbol table.  */
index 2e376e3869598dca3fd8132c1226fe4175503df9..55c398077b7c6276585dcbfb33365f720d7bd324 100644 (file)
@@ -17,6 +17,7 @@
 
 #include "defs.h"
 #include "gdb_regex.h"
+#include "common/def-vector.h"
 
 compiled_regex::compiled_regex (const char *regex, int cflags,
                                const char *message)
@@ -28,10 +29,10 @@ compiled_regex::compiled_regex (const char *regex, int cflags,
   if (code != 0)
     {
       size_t length = regerror (code, &m_pattern, NULL, 0);
-      std::unique_ptr<char[]> err (new char[length]);
+      gdb::def_vector<char> err (length);
 
-      regerror (code, &m_pattern, err.get (), length);
-      error (("%s: %s"), message, err.get ());
+      regerror (code, &m_pattern, err.data (), length);
+      error (("%s: %s"), message, err.data ());
     }
 }
 
index 755fbabafb692819abcd62f9783e7e31c755e899..53289bb7e975a2be796bb05ed664542a75d2c822 100644 (file)
@@ -55,6 +55,7 @@
 #include "gdbcmd.h"
 #include "observer.h"
 #include "common/gdb_optional.h"
+#include "common/byte-vector.h"
 
 #include <ctype.h>
 #include "run-time-clock.h"
@@ -1466,12 +1467,12 @@ mi_cmd_data_read_memory (const char *command, char **argv, int argc)
   /* Create a buffer and read it in.  */
   total_bytes = word_size * nr_rows * nr_cols;
 
-  std::unique_ptr<gdb_byte[]> mbuf (new gdb_byte[total_bytes]);
+  gdb::byte_vector mbuf (total_bytes);
 
   /* Dispatch memory reads to the topmost target, not the flattened
      current_target.  */
   nr_bytes = target_read (current_target.beneath,
-                         TARGET_OBJECT_MEMORY, NULL, mbuf.get (),
+                         TARGET_OBJECT_MEMORY, NULL, mbuf.data (),
                          addr, total_bytes);
   if (nr_bytes <= 0)
     error (_("Unable to read memory."));
index 152c2c6d7cc57a5a75a2ddf27641931e69c1e5f1..f392e6df0988b088e840cf9ef839ae1d318fea0c 100644 (file)
@@ -48,6 +48,7 @@
 #include "cli/cli-script.h"
 #include "format.h"
 #include "source.h"
+#include "common/byte-vector.h"
 
 #ifdef TUI
 #include "tui/tui.h"           /* For tui_active et al.   */
@@ -407,7 +408,7 @@ print_scalar_formatted (const gdb_byte *valaddr, struct type *type,
   /* Historically gdb has printed floats by first casting them to a
      long, and then printing the long.  PR cli/16242 suggests changing
      this to using C-style hex float format.  */
-  std::vector<gdb_byte> converted_float_bytes;
+  gdb::byte_vector converted_float_bytes;
   if (TYPE_CODE (type) == TYPE_CODE_FLT
       && (options->format == 'o'
          || options->format == 'x'
index e627e859929d0533f6ece993ac36699629c37a8a..c10dade6748ab0ea228abd8952eed1de6f8a1b5d 100644 (file)
@@ -37,6 +37,7 @@
 #include "typeprint.h"
 #include <ctype.h>
 #include <algorithm>
+#include "common/byte-vector.h"
 
 /* Maximum number of wchars returned from wchar_iterate.  */
 #define MAX_WCHARS 4
@@ -1721,7 +1722,7 @@ print_octal_chars (struct ui_file *stream, const gdb_byte *valaddr,
 static bool
 maybe_negate_by_bytes (const gdb_byte *bytes, unsigned len,
                       enum bfd_endian byte_order,
-                      std::vector<gdb_byte> *out_vec)
+                      gdb::byte_vector *out_vec)
 {
   gdb_byte sign_byte;
   if (byte_order == BFD_ENDIAN_BIG)
@@ -1780,7 +1781,7 @@ print_decimal_chars (struct ui_file *stream, const gdb_byte *valaddr,
   int dummy;
   int flip;
 
-  std::vector<gdb_byte> negated_bytes;
+  gdb::byte_vector negated_bytes;
   if (is_signed
       && maybe_negate_by_bytes (valaddr, len, byte_order, &negated_bytes))
     {