From patchwork Tue Apr 21 15:44:23 2015 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Joel Brobecker X-Patchwork-Id: 6345 Received: (qmail 42082 invoked by alias); 21 Apr 2015 15:44:41 -0000 Mailing-List: contact gdb-patches-help@sourceware.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Subscribe: List-Archive: List-Post: List-Help: , Sender: gdb-patches-owner@sourceware.org Delivered-To: mailing list gdb-patches@sourceware.org Received: (qmail 42033 invoked by uid 89); 21 Apr 2015 15:44:40 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=-1.8 required=5.0 tests=AWL, BAYES_00, SPF_PASS, T_RP_MATCHES_RCVD autolearn=ham version=3.3.2 X-HELO: rock.gnat.com Received: from rock.gnat.com (HELO rock.gnat.com) (205.232.38.15) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with (AES256-SHA encrypted) ESMTPS; Tue, 21 Apr 2015 15:44:39 +0000 Received: from localhost (localhost.localdomain [127.0.0.1]) by filtered-rock.gnat.com (Postfix) with ESMTP id 0A645116535 for ; Tue, 21 Apr 2015 11:44:38 -0400 (EDT) Received: from rock.gnat.com ([127.0.0.1]) by localhost (rock.gnat.com [127.0.0.1]) (amavisd-new, port 10024) with LMTP id fW+sYBPx1DPo for ; Tue, 21 Apr 2015 11:44:37 -0400 (EDT) Received: from joel.gnat.com (localhost.localdomain [127.0.0.1]) by rock.gnat.com (Postfix) with ESMTP id D010611648E for ; Tue, 21 Apr 2015 11:44:37 -0400 (EDT) Received: by joel.gnat.com (Postfix, from userid 1000) id DCBE240EAD; Tue, 21 Apr 2015 08:44:37 -0700 (PDT) From: Joel Brobecker To: gdb-patches@sourceware.org Subject: [FYI 5/6] GDB crash trying to subscript array of variant record. Date: Tue, 21 Apr 2015 08:44:23 -0700 Message-Id: <1429631064-4196-6-git-send-email-brobecker@adacore.com> In-Reply-To: <1429631064-4196-1-git-send-email-brobecker@adacore.com> References: <1429631064-4196-1-git-send-email-brobecker@adacore.com> Consider the following declarations: subtype Small_Type is Integer range 0 .. 10; type Record_Type (I : Small_Type := 0) is record S : String (1 .. I); end record; A2 : Array_Type := (1 => (I => 2, S => "AB"), 2 => (I => 1, S => "A"), 3 => (I => 0, S => <>)); Compiled with -fgnat-encodings=minimal, and trying to print one element of our array, valgrind reports an invalid memory access. On certain GNU/Linux boxes, malloc even reports it as well, and causes GDB to crash. (gdb) print a2(1) *** glibc detected *** /[...]/gdb: malloc(): memory corruption: 0x0a30ba48 *** [crash] The invalid memory access occurs because of a simple buffer overflow in ada_value_primitive_packed_val. When this function is called, it is given a bit_size of 128 (or 16 bytes), which corresponds to the stride of our array. But the actual size of each element depends on its value. In particular, A2(1) is a record whose size is only 6 bytes. What happens in our example is that we start building a new value (v) where the element is to be unpacked, with any of its dynamic properties getting resolved as well. We then unpack the data into this value's buffer: unpacked = (unsigned char *) value_contents (v); [...] nsrc = len; [...] while (nsrc > 0) { [...] unpacked[targ] = accum & ~(~0L << HOST_CHAR_BIT); [...] targ += delta; [...] nsrc -= 1; [...] } In the loop above, targ starts at zero (for LE architectures), and len is 16. With delta being +1, we end up iterating 16 times, writing 16 bytes into a 6-bytes buffer. This patch fixes the issue by adjusting BIT_SIZE and recomputing LEN after having resolved our type if the resolved type turns out to be smaller than bit_size. gdb/ChangeLog: * ada-lang.c (ada_value_primitive_packed_val): Recompute BIT_SIZE and LEN if the size of the resolved type is smaller than BIT_SIZE * HOST_CHAR_BIT. --- gdb/ada-lang.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/gdb/ada-lang.c b/gdb/ada-lang.c index d71a243..bbc1732 100644 --- a/gdb/ada-lang.c +++ b/gdb/ada-lang.c @@ -2419,6 +2419,17 @@ ada_value_primitive_packed_val (struct value *obj, const gdb_byte *valaddr, { v = value_at (type, value_address (obj) + offset); type = value_type (v); + if (TYPE_LENGTH (type) * HOST_CHAR_BIT < bit_size) + { + /* This can happen in the case of an array of dynamic objects, + where the size of each element changes from element to element. + In that case, we're initially given the array stride, but + after resolving the element type, we find that its size is + less than this stride. In that case, adjust bit_size to + match TYPE's length, and recompute LEN accordingly. */ + bit_size = TYPE_LENGTH (type) * HOST_CHAR_BIT; + len = TYPE_LENGTH (type) + (bit_offset + HOST_CHAR_BIT - 1) / 8; + } bytes = (unsigned char *) alloca (len); read_memory (value_address (v), bytes, len); }