diff options
author | Joel Brobecker <brobecker@adacore.com> | 2017-12-17 22:09:27 -0500 |
---|---|---|
committer | Joel Brobecker <brobecker@adacore.com> | 2017-12-17 22:11:40 -0500 |
commit | 0e2da9f01334a01d1a6e224ecd592d6fbbb22515 (patch) | |
tree | 494b8c5c0bb84d498c89e46d85be0313adda550c /gdb/ada-lang.c | |
parent | cb923fcc23e07fe3dfb3837f47249aba79cdee6f (diff) | |
download | gdb-0e2da9f01334a01d1a6e224ecd592d6fbbb22515.zip gdb-0e2da9f01334a01d1a6e224ecd592d6fbbb22515.tar.gz gdb-0e2da9f01334a01d1a6e224ecd592d6fbbb22515.tar.bz2 |
(Ada) crash assigning to record component which is an array
Consider the following code, which declares a variabled called "input"
of type "parameter", which is a record with one component called "u2",
where the type of that component is a simple 3-element array of
floating point values:
type Float_Array_3 is array (1 .. 3) of Float;
type parameters is record
u2 : Float_Array_3;
end record;
input : parameters;
Trying to assign a value to input.u2 causes GDB to crash:
(gdb) p input.u2 := (0.25,0.5,0.75)
[1] 20228 segmentation fault (core dumped) [...]/gdb
The crash occurs because input.u2 is described in the debugging
info as a typedef of an array. Indeed, input's type is:
<1><ae9>: Abbrev Number: 7 (DW_TAG_structure_type)
<aea> DW_AT_name : (indirect string, offset: 0x1045): target_wrapper__parameters
[...]
<2><af5>: Abbrev Number: 8 (DW_TAG_member)
<af6> DW_AT_name : u2
[...]
<afb> DW_AT_type : <0xaca>
and, looking at DIE 0xaca to get input.u2's type, we see:
<1><aca>: Abbrev Number: 4 (DW_TAG_typedef)
<acb> DW_AT_name : (indirect string, offset: 0x1060): target_wrapper__float_array_3
[...]
<ad1> DW_AT_type : <0xad5>
We can also confirm, following the DW_AT_type attribute (0xad5), that
it's a typedef of our array:
<1><ad5>: Abbrev Number: 5 (DW_TAG_array_type)
<ad6> DW_AT_name : (indirect string, offset: 0x1060): target_wrapper__float_array_3
[...]
In fact, this scenario uncovered 2 areas where typedef handling
is missing, thus causing a crash. The first happens inside
assign_aggregate:
if (ada_is_direct_array_type (lhs_type))
{
lhs = ada_coerce_to_simple_array (lhs);
lhs_type = value_type (lhs);
low_index = TYPE_ARRAY_LOWER_BOUND_VALUE (lhs_type);
high_index = TYPE_ARRAY_UPPER_BOUND_VALUE (lhs_type);
}
Here, lhs_type is a TYPE_CODE_TYPEDEF. ada_is_direct_array_type
knows how to handle it, but TYPE_ARRAY_LOWER_BOUND_VALUE assumes
that the given type is a TYPE_CODE_ARRAY. As such, it ends up
accessing some fields in lhs_type which it shouldn't, and kaboom.
We fixed this issue by making sure that the TYPE_CODE_TYPEDEF
layer gets stripped.
Once this is done, we hit a different kind of error, also leading to
a SEGV, this time in assign_component. The code looks like this:
if (TYPE_CODE (value_type (lhs)) == TYPE_CODE_ARRAY)
[...]
else
[...]
Because once again lhs is a TYPE_CODE_TYPEDEF, the check fail,
and we end up assuming that lhs is a struct, executing the "else"
block, which is:
else
{
elt = ada_index_struct_field (index, lhs, 0, value_type (lhs));
elt = ada_to_fixed_value (elt);
}
Since lhs is not a struct, ada_index_struct_field returns NULL,
which ada_to_fixed_value does not handle well, hence another crash.
This patch fixes this other issue the same way, by stripping
TYPE_CODE_TYPEDEF layers.
gdb/ChangeLog:
* ada-lang.c (assign_component): Strip any TYPE_CODE_TYPEDEF
layer from lhs' type.
(assign_aggregate): Likewise.
gdb/testsuite:
* gdb.ada/assign_arr: New testcase.
Tested on x86_64-linux.
Diffstat (limited to 'gdb/ada-lang.c')
-rw-r--r-- | gdb/ada-lang.c | 7 |
1 files changed, 4 insertions, 3 deletions
diff --git a/gdb/ada-lang.c b/gdb/ada-lang.c index 8a0423e..14a0bd6 100644 --- a/gdb/ada-lang.c +++ b/gdb/ada-lang.c @@ -9960,8 +9960,9 @@ assign_component (struct value *container, struct value *lhs, LONGEST index, { struct value *mark = value_mark (); struct value *elt; + struct type *lhs_type = check_typedef (value_type (lhs)); - if (TYPE_CODE (value_type (lhs)) == TYPE_CODE_ARRAY) + if (TYPE_CODE (lhs_type) == TYPE_CODE_ARRAY) { struct type *index_type = builtin_type (exp->gdbarch)->builtin_int; struct value *index_val = value_from_longest (index_type, index); @@ -10020,11 +10021,11 @@ assign_aggregate (struct value *container, if (!deprecated_value_modifiable (lhs)) error (_("Left operand of assignment is not a modifiable lvalue.")); - lhs_type = value_type (lhs); + lhs_type = check_typedef (value_type (lhs)); if (ada_is_direct_array_type (lhs_type)) { lhs = ada_coerce_to_simple_array (lhs); - lhs_type = value_type (lhs); + lhs_type = check_typedef (value_type (lhs)); low_index = TYPE_ARRAY_LOWER_BOUND_VALUE (lhs_type); high_index = TYPE_ARRAY_UPPER_BOUND_VALUE (lhs_type); } |