aboutsummaryrefslogtreecommitdiff
path: root/gdb/valops.c
diff options
context:
space:
mode:
authorSimon Marchi <simon.marchi@polymtl.ca>2021-11-08 16:06:07 -0500
committerSimon Marchi <simon.marchi@polymtl.ca>2021-12-03 16:37:36 -0500
commit4bce7cdaf481901edbc5ee47d953ea7e8efb56ca (patch)
treef085df5b718a9438b5d5174b5e3c9be15e2cea7c /gdb/valops.c
parent7509b82979550970342a4494d727b3fb06bffd65 (diff)
downloadgdb-4bce7cdaf481901edbc5ee47d953ea7e8efb56ca.zip
gdb-4bce7cdaf481901edbc5ee47d953ea7e8efb56ca.tar.gz
gdb-4bce7cdaf481901edbc5ee47d953ea7e8efb56ca.tar.bz2
gdbsupport: add array_view copy function
An assertion was recently added to array_view::operator[] to ensure we don't do out of bounds accesses. However, when the array_view is copied to or from using memcpy, it bypasses that safety. To address this, add a `copy` free function that copies data from an array view to another, ensuring that the destination and source array views have the same size. When copying to or from parts of an array_view, we are expected to use gdb::array_view::slice, which does its own bounds check. With all that, any copy operation that goes out of bounds should be caught by an assertion at runtime. copy is implemented using std::copy and std::copy_backward, which, at least on libstdc++, appears to pick memmove when copying trivial data. So in the end there shouldn't be much difference vs using a bare memcpy, as we do right now. When copying non-trivial data, std::copy and std::copy_backward assigns each element in a loop. To properly support overlapping ranges, we must use std::copy or std::copy_backward, depending on whether the destination is before the source or vice-versa. std::copy and std::copy_backward don't support copying exactly overlapping ranges (where the source range is equal to the destination range). But in this case, no copy is needed anyway, so we do nothing. The order of parameters of the new copy function is based on std::copy and std::copy_backward, where the source comes before the destination. Change a few randomly selected spots to use the new function, to show how it can be used. Add a test for the new function, testing both with arrays of a trivial type (int) and of a non-trivial type (foo). Test non-overlapping ranges as well as three kinds of overlapping ranges: source before dest, dest before source, and dest == source. Change-Id: Ibeaca04e0028410fd44ce82f72e60058d6230a03
Diffstat (limited to 'gdb/valops.c')
-rw-r--r--gdb/valops.c35
1 files changed, 19 insertions, 16 deletions
diff --git a/gdb/valops.c b/gdb/valops.c
index c552e82..ca71c12 100644
--- a/gdb/valops.c
+++ b/gdb/valops.c
@@ -954,18 +954,19 @@ value_one (struct type *type)
struct type *eltype = check_typedef (TYPE_TARGET_TYPE (type1));
int i;
LONGEST low_bound, high_bound;
- struct value *tmp;
if (!get_array_bounds (type1, &low_bound, &high_bound))
error (_("Could not determine the vector bounds"));
val = allocate_value (type);
+ gdb::array_view<gdb_byte> val_contents = value_contents_writeable (val);
+ int elt_len = TYPE_LENGTH (eltype);
+
for (i = 0; i < high_bound - low_bound + 1; i++)
{
- tmp = value_one (eltype);
- memcpy ((value_contents_writeable (val).data ()
- + i * TYPE_LENGTH (eltype)),
- value_contents_all (tmp).data (), TYPE_LENGTH (eltype));
+ value *tmp = value_one (eltype);
+ copy (value_contents_all (tmp),
+ val_contents.slice (i * elt_len, elt_len));
}
}
else
@@ -1342,8 +1343,7 @@ value_assign (struct value *toval, struct value *fromval)
implies the returned value is not lazy, even if TOVAL was. */
val = value_copy (toval);
set_value_lazy (val, 0);
- memcpy (value_contents_raw (val).data (), value_contents (fromval).data (),
- TYPE_LENGTH (type));
+ copy (value_contents (fromval), value_contents_raw (val));
/* We copy over the enclosing type and pointed-to offset from FROMVAL
in the case of pointer types. For object types, the enclosing type
@@ -4058,10 +4058,13 @@ value_literal_complex (struct value *arg1,
arg1 = value_cast (real_type, arg1);
arg2 = value_cast (real_type, arg2);
- memcpy (value_contents_raw (val).data (),
- value_contents (arg1).data (), TYPE_LENGTH (real_type));
- memcpy (value_contents_raw (val).data () + TYPE_LENGTH (real_type),
- value_contents (arg2).data (), TYPE_LENGTH (real_type));
+ int len = TYPE_LENGTH (real_type);
+
+ copy (value_contents (arg1),
+ value_contents_raw (val).slice (0, len));
+ copy (value_contents (arg2),
+ value_contents_raw (val).slice (len, len));
+
return val;
}
@@ -4102,12 +4105,12 @@ cast_into_complex (struct type *type, struct value *val)
struct type *val_real_type = TYPE_TARGET_TYPE (value_type (val));
struct value *re_val = allocate_value (val_real_type);
struct value *im_val = allocate_value (val_real_type);
+ int len = TYPE_LENGTH (val_real_type);
- memcpy (value_contents_raw (re_val).data (),
- value_contents (val).data (), TYPE_LENGTH (val_real_type));
- memcpy (value_contents_raw (im_val).data (),
- value_contents (val).data () + TYPE_LENGTH (val_real_type),
- TYPE_LENGTH (val_real_type));
+ copy (value_contents (val).slice (0, len),
+ value_contents_raw (re_val));
+ copy (value_contents (val).slice (len, len),
+ value_contents_raw (im_val));
return value_literal_complex (re_val, im_val, type);
}