From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from simark.ca by simark.ca with LMTP id +Ob9HZ2RiWG5MAAAWB0awg (envelope-from ) for ; Mon, 08 Nov 2021 16:07:41 -0500 Received: by simark.ca (Postfix, from userid 112) id 764001F0C7; Mon, 8 Nov 2021 16:07:41 -0500 (EST) X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) on simark.ca X-Spam-Level: X-Spam-Status: No, score=-3.0 required=5.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,MAILING_LIST_MULTI,URIBL_BLOCKED autolearn=unavailable autolearn_force=no version=3.4.2 Received: from sourceware.org (server2.sourceware.org [8.43.85.97]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by simark.ca (Postfix) with ESMTPS id 1E2AF1E813 for ; Mon, 8 Nov 2021 16:07:40 -0500 (EST) Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id B6DFC3858406 for ; Mon, 8 Nov 2021 21:07:39 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org B6DFC3858406 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=sourceware.org; s=default; t=1636405659; bh=xRFmGgxsUxUHq56rlroXszNBOPs8gnnfjZgYXrtkEo0=; h=To:Subject:Date:In-Reply-To:References:List-Id:List-Unsubscribe: List-Archive:List-Post:List-Help:List-Subscribe:From:Reply-To: From; b=yNplkfZcAxTQc5/vDC8OR5lsNOTHbw64jQS++DLCd66vAn5Er3LNSpCo2jb9w4Ccw 9SMjx5O0aiIJCOXT1fX+/C5sj+0DT/C32jovrenhKN5Vc4FuvYl0e6yiWLqFyBM/D+ ADTMtPPirFza5zyanhgB15E2Dg3uuWK/9wWqlBRk= Received: from barracuda.ebox.ca (barracuda.ebox.ca [96.127.255.19]) by sourceware.org (Postfix) with ESMTPS id 1AA2E3858418 for ; Mon, 8 Nov 2021 21:06:20 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.1 sourceware.org 1AA2E3858418 X-ASG-Debug-ID: 1636405570-0c856e038895abc0001-fS2M51 Received: from smtp.ebox.ca (smtp.ebox.ca [96.127.255.82]) by barracuda.ebox.ca with ESMTP id CTrdwePPEXGzHhjn (version=TLSv1 cipher=DHE-RSA-AES256-SHA bits=256 verify=NO); Mon, 08 Nov 2021 16:06:10 -0500 (EST) X-Barracuda-Envelope-From: simon.marchi@efficios.com X-Barracuda-RBL-Trusted-Forwarder: 96.127.255.82 Received: from epycamd.internal.efficios.com (192-222-180-24.qc.cable.ebox.net [192.222.180.24]) by smtp.ebox.ca (Postfix) with ESMTP id 7BE28441D67; Mon, 8 Nov 2021 16:06:10 -0500 (EST) X-Barracuda-RBL-IP: 192.222.180.24 X-Barracuda-Effective-Source-IP: 192-222-180-24.qc.cable.ebox.net[192.222.180.24] X-Barracuda-Apparent-Source-IP: 192.222.180.24 To: gdb-patches@sourceware.org Subject: [PATCH 2/4] gdbsupport: add array_view copy function Date: Mon, 8 Nov 2021 16:06:07 -0500 X-ASG-Orig-Subj: [PATCH 2/4] gdbsupport: add array_view copy function Message-Id: <20211108210609.353208-2-simon.marchi@efficios.com> X-Mailer: git-send-email 2.33.0 In-Reply-To: <20211108210609.353208-1-simon.marchi@efficios.com> References: <20211108210609.353208-1-simon.marchi@efficios.com> MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Barracuda-Connect: smtp.ebox.ca[96.127.255.82] X-Barracuda-Start-Time: 1636405570 X-Barracuda-Encrypted: DHE-RSA-AES256-SHA X-Barracuda-URL: https://96.127.255.19:443/cgi-mod/mark.cgi X-Barracuda-BRTS-Status: 1 X-Virus-Scanned: by bsmtpd at ebox.ca X-Barracuda-Scan-Msg-Size: 16252 X-Barracuda-Spam-Score: 0.50 X-Barracuda-Spam-Status: No, SCORE=0.50 using global scores of TAG_LEVEL=1000.0 QUARANTINE_LEVEL=1000.0 KILL_LEVEL=8.0 tests=BSF_RULE_7582B X-Barracuda-Spam-Report: Code version 3.2, rules version 3.2.3.93830 Rule breakdown below pts rule name description ---- ---------------------- -------------------------------------------------- 0.50 BSF_RULE_7582B Custom Rule 7582B X-BeenThere: gdb-patches@sourceware.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Gdb-patches mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , From: Simon Marchi via Gdb-patches Reply-To: Simon Marchi Errors-To: gdb-patches-bounces+public-inbox=simark.ca@sourceware.org Sender: "Gdb-patches" From: Simon Marchi 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 this safety. To address this, add a `copy` free function that copies data from an array view to another. It ensures that the destination and source array views have the same size and element size, which prevents any kind of overflow in the source and in the destination. I have chosen to allow the array views to have different types, because I am thinking we might want to copy arrays of bfd_byte into arrays of gdb_byte, for example. Change a few randomly selected spots to use the new function, to show how it can be used. Change-Id: Ibeaca04e0028410fd44ce82f72e60058d6230a03 --- gdb/ada-lang.c | 17 +++++--------- gdb/dwarf2/expr.c | 4 ++-- gdb/frame.c | 4 ++-- gdb/valarith.c | 49 +++++++++++++++++++++++------------------ gdb/valops.c | 44 ++++++++++++++++++++---------------- gdb/value.c | 22 +++++++++--------- gdbsupport/array-view.h | 15 +++++++++++++ 7 files changed, 88 insertions(+), 67 deletions(-) diff --git a/gdb/ada-lang.c b/gdb/ada-lang.c index d964dae42cf..9458f7a9cf7 100644 --- a/gdb/ada-lang.c +++ b/gdb/ada-lang.c @@ -2586,9 +2586,7 @@ ada_value_assign (struct value *toval, struct value *fromval) write_memory_with_notification (to_addr, buffer, len); val = value_copy (toval); - memcpy (value_contents_raw (val).data (), - value_contents (fromval).data (), - TYPE_LENGTH (type)); + copy (value_contents_raw (val), value_contents (fromval)); deprecated_set_value_type (val, type); return val; @@ -4184,9 +4182,7 @@ ada_convert_actual (struct value *actual, struct type *formal_type0) actual_type = ada_check_typedef (value_type (actual)); val = allocate_value (actual_type); - memcpy ((char *) value_contents_raw (val).data (), - (char *) value_contents (actual).data (), - TYPE_LENGTH (actual_type)); + copy (value_contents_raw (val), value_contents (actual)); actual = ensure_lval (val); } result = value_addr (actual); @@ -8898,7 +8894,6 @@ ada_promote_array_of_integrals (struct type *type, struct value *val) { struct type *elt_type = TYPE_TARGET_TYPE (type); LONGEST lo, hi; - struct value *res; LONGEST i; /* Verify that both val and type are arrays of scalars, and @@ -8914,16 +8909,16 @@ ada_promote_array_of_integrals (struct type *type, struct value *val) if (!get_array_bounds (type, &lo, &hi)) error (_("unable to determine array bounds")); - res = allocate_value (type); + value *res = allocate_value (type); + gdb::array_view res_contents = value_contents_writeable (res); /* Promote each array element. */ for (i = 0; i < hi - lo + 1; i++) { struct value *elt = value_cast (elt_type, value_subscript (val, lo + i)); + int elt_len = TYPE_LENGTH (elt_type); - memcpy ((value_contents_writeable (res).data () - + (i * TYPE_LENGTH (elt_type))), - value_contents_all (elt).data (), TYPE_LENGTH (elt_type)); + copy (res_contents.slice (elt_len * i, elt_len), value_contents_all (elt)); } return res; diff --git a/gdb/dwarf2/expr.c b/gdb/dwarf2/expr.c index 652161955d5..e00a620406f 100644 --- a/gdb/dwarf2/expr.c +++ b/gdb/dwarf2/expr.c @@ -1037,8 +1037,8 @@ dwarf_expr_context::fetch_result (struct type *type, struct type *subobj_type, if (gdbarch_byte_order (arch) == BFD_ENDIAN_BIG) subobj_offset += n - max; - memcpy (value_contents_raw (retval).data (), - value_contents_all (val).data () + subobj_offset, len); + copy (value_contents_raw (retval), + value_contents_all (val).slice (subobj_offset, len)); } break; diff --git a/gdb/frame.c b/gdb/frame.c index 2a899fc494f..70b1247d15e 100644 --- a/gdb/frame.c +++ b/gdb/frame.c @@ -1362,9 +1362,9 @@ read_frame_register_unsigned (frame_info *frame, int regnum, { struct gdbarch *gdbarch = get_frame_arch (frame); enum bfd_endian byte_order = gdbarch_byte_order (gdbarch); - int size = register_size (gdbarch, VALUE_REGNUM (regval)); - *val = extract_unsigned_integer (value_contents (regval).data (), size, + gdb::array_view contents = value_contents (regval); + *val = extract_unsigned_integer (contents.data (), contents.size (), byte_order); return true; } diff --git a/gdb/valarith.c b/gdb/valarith.c index 140ef448137..ebf394df437 100644 --- a/gdb/valarith.c +++ b/gdb/valarith.c @@ -1531,7 +1531,7 @@ value_vector_widen (struct value *scalar_value, struct type *vector_type) { /* Widen the scalar to a vector. */ struct type *eltype, *scalar_type; - struct value *val, *elval; + struct value *elval; LONGEST low_bound, high_bound; int i; @@ -1554,11 +1554,14 @@ value_vector_widen (struct value *scalar_value, struct type *vector_type) && !value_equal (elval, scalar_value)) error (_("conversion of scalar to vector involves truncation")); - val = allocate_value (vector_type); + value *val = allocate_value (vector_type); + gdb::array_view val_contents = value_contents_writeable (val); + int elt_len = TYPE_LENGTH (eltype); + for (i = 0; i < high_bound - low_bound + 1; i++) /* Duplicate the contents of elval into the destination vector. */ - memcpy (value_contents_writeable (val).data () + (i * TYPE_LENGTH (eltype)), - value_contents_all (elval).data (), TYPE_LENGTH (eltype)); + copy (val_contents.slice (i * elt_len, elt_len), + value_contents_all (elval)); return val; } @@ -1569,7 +1572,6 @@ value_vector_widen (struct value *scalar_value, struct type *vector_type) static struct value * vector_binop (struct value *val1, struct value *val2, enum exp_opcode op) { - struct value *val, *tmp, *mark; struct type *type1, *type2, *eltype1, *eltype2; int t1_is_vec, t2_is_vec, elsize, i; LONGEST low_bound1, high_bound1, low_bound2, high_bound2; @@ -1599,15 +1601,15 @@ vector_binop (struct value *val1, struct value *val2, enum exp_opcode op) || low_bound1 != low_bound2 || high_bound1 != high_bound2) error (_("Cannot perform operation on vectors with different types")); - val = allocate_value (type1); - mark = value_mark (); + value *val = allocate_value (type1); + gdb::array_view val_contents = value_contents_writeable (val); + value *mark = value_mark (); for (i = 0; i < high_bound1 - low_bound1 + 1; i++) { - tmp = value_binop (value_subscript (val1, i), - value_subscript (val2, i), op); - memcpy (value_contents_writeable (val).data () + i * elsize, - value_contents_all (tmp).data (), - elsize); + value *tmp = value_binop (value_subscript (val1, i), + value_subscript (val2, i), op); + copy (val_contents.slice (i * elsize, elsize), + value_contents_all (tmp)); } value_free_to_mark (mark); @@ -1888,7 +1890,7 @@ value_neg (struct value *arg1) return value_binop (value_zero (type, not_lval), arg1, BINOP_SUB); else if (type->code () == TYPE_CODE_ARRAY && type->is_vector ()) { - struct value *tmp, *val = allocate_value (type); + struct value *val = allocate_value (type); struct type *eltype = check_typedef (TYPE_TARGET_TYPE (type)); int i; LONGEST low_bound, high_bound; @@ -1896,12 +1898,14 @@ value_neg (struct value *arg1) if (!get_array_bounds (type, &low_bound, &high_bound)) error (_("Could not determine the vector bounds")); + gdb::array_view val_contents = value_contents_writeable (val); + int elt_len = TYPE_LENGTH (eltype); + for (i = 0; i < high_bound - low_bound + 1; i++) { - tmp = value_neg (value_subscript (arg1, i)); - memcpy ((value_contents_writeable (val).data () - + i * TYPE_LENGTH (eltype)), - value_contents_all (tmp).data (), TYPE_LENGTH (eltype)); + value *tmp = value_neg (value_subscript (arg1, i)); + copy (val_contents.slice (i * elt_len, elt_len), + value_contents_all (tmp)); } return val; } @@ -1931,7 +1935,6 @@ value_complement (struct value *arg1) val = value_from_longest (type, ~value_as_long (arg1)); else if (type->code () == TYPE_CODE_ARRAY && type->is_vector ()) { - struct value *tmp; struct type *eltype = check_typedef (TYPE_TARGET_TYPE (type)); int i; LONGEST low_bound, high_bound; @@ -1940,12 +1943,14 @@ value_complement (struct value *arg1) error (_("Could not determine the vector bounds")); val = allocate_value (type); + gdb::array_view val_contents = value_contents_writeable (val); + int elt_len = TYPE_LENGTH (eltype); + for (i = 0; i < high_bound - low_bound + 1; i++) { - tmp = value_complement (value_subscript (arg1, i)); - memcpy ((value_contents_writeable (val).data () - + i * TYPE_LENGTH (eltype)), - value_contents_all (tmp).data (), TYPE_LENGTH (eltype)); + value *tmp = value_complement (value_subscript (arg1, i)); + copy (val_contents.slice (i * elt_len, elt_len), + value_contents_all (tmp)); } } else if (type->code () == TYPE_CODE_COMPLEX) diff --git a/gdb/valops.c b/gdb/valops.c index 9787cdbb513..106e12d3234 100644 --- a/gdb/valops.c +++ b/gdb/valops.c @@ -586,9 +586,12 @@ value_cast (struct type *type, struct value *arg2) sees a cast as a simple reinterpretation of the pointer's bits. */ if (code2 == TYPE_CODE_PTR) - longest = extract_unsigned_integer - (value_contents (arg2).data (), TYPE_LENGTH (type2), - type_byte_order (type2)); + { + gdb::array_view contents = value_contents (arg2); + longest = extract_unsigned_integer (contents.data (), + contents.size (), + type_byte_order (type2)); + } else longest = value_as_long (arg2); return value_from_longest (to_type, convert_to_boolean ? @@ -954,18 +957,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 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 (val_contents.slice (i * elt_len, elt_len), + value_contents_all (tmp)); } } else @@ -1342,8 +1346,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_raw (val), value_contents (fromval)); /* We copy over the enclosing type and pointed-to offset from FROMVAL in the case of pointer types. For object types, the enclosing type @@ -4030,10 +4033,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_raw (val).slice (0, len), + value_contents (arg1)); + copy (value_contents_raw (val).slice (len, len), + value_contents (arg2)); + return val; } @@ -4074,12 +4080,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_raw (re_val), + value_contents (val).slice (0, len)); + copy (value_contents_raw (im_val), + value_contents (val).slice (len, len)); return value_literal_complex (re_val, im_val, type); } diff --git a/gdb/value.c b/gdb/value.c index 8669ad8fe70..7c86e7e13ca 100644 --- a/gdb/value.c +++ b/gdb/value.c @@ -1343,9 +1343,13 @@ value_contents_copy_raw (struct value *dst, LONGEST dst_offset, TARGET_CHAR_BIT * length)); /* Copy the data. */ - memcpy (value_contents_all_raw (dst).data () + dst_offset * unit_size, - value_contents_all_raw (src).data () + src_offset * unit_size, - length * unit_size); + gdb::array_view dst_contents + = value_contents_all_raw (dst).slice (dst_offset * unit_size, + length * unit_size); + gdb::array_view src_contents + = value_contents_all_raw (src).slice (src_offset * unit_size, + length * unit_size); + copy (dst_contents, src_contents); /* Copy the meta-data, adjusted. */ src_bit_offset = src_offset * unit_size * HOST_CHAR_BIT; @@ -1720,13 +1724,11 @@ value_copy (struct value *arg) val->stack = arg->stack; val->is_zero = arg->is_zero; val->initialized = arg->initialized; + if (!value_lazy (val)) - { - memcpy (value_contents_all_raw (val).data (), - value_contents_all_raw (arg).data (), - TYPE_LENGTH (value_enclosing_type (arg))); + copy (value_contents_all_raw (val), + value_contents_all_raw (arg)); - } val->unavailable = arg->unavailable; val->optimized_out = arg->optimized_out; val->parent = arg->parent; @@ -1771,9 +1773,7 @@ value_non_lval (struct value *arg) struct type *enc_type = value_enclosing_type (arg); struct value *val = allocate_value (enc_type); - memcpy (value_contents_all_raw (val).data (), - value_contents_all (arg).data (), - TYPE_LENGTH (enc_type)); + copy (value_contents_all_raw (val), value_contents_all (arg)); val->type = arg->type; set_value_embedded_offset (val, value_embedded_offset (arg)); set_value_pointed_to_offset (val, value_pointed_to_offset (arg)); diff --git a/gdbsupport/array-view.h b/gdbsupport/array-view.h index ab1d032c60e..5b2aee7ad25 100644 --- a/gdbsupport/array-view.h +++ b/gdbsupport/array-view.h @@ -205,6 +205,21 @@ class array_view size_type m_size; }; +/* Copy the contents referenced by the array view SRC to the array view DEST. + + The two array views must have the same length and element size. + + The copy is done using memcpy, so both element types must be trivially + copyable (this is checked by poison.h). */ + +template +void copy (gdb::array_view dest, gdb::array_view src) +{ + gdb_static_assert (sizeof (T) == sizeof (U)); + gdb_assert (dest.size () == src.size ()); + memcpy (dest.data (), src.data (), src.size () * sizeof (T)); +} + /* Compare LHS and RHS for (deep) equality. That is, whether LHS and RHS have the same sizes, and whether each pair of elements of LHS and RHS at the same position compares equal. */ -- 2.33.0