diff --git a/gdb/ChangeLog b/gdb/ChangeLog index 3b022c1813f..0e01628c651 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -1,3 +1,13 @@ +2020-12-09 Simon Marchi + + PR 26875, PR 26901 + * gdbtypes.c (get_discrete_low_bound): Make non-static. + (get_discrete_high_bound): Make non-static. + * gdbtypes.h (get_discrete_low_bound): New declaration. + (get_discrete_high_bound): New declaration. + * valarith.c (value_subscript): Only fetch high bound if + necessary. + 2020-12-09 Simon Marchi * gdbtypes.c (get_discrete_bounds): Implement with diff --git a/gdb/gdbtypes.c b/gdb/gdbtypes.c index 367ca5f311c..9a170080d30 100644 --- a/gdb/gdbtypes.c +++ b/gdb/gdbtypes.c @@ -1036,9 +1036,9 @@ has_static_range (const struct range_bounds *bounds) && bounds->stride.kind () == PROP_CONST); } -/* If TYPE's low bound is a known constant, return it, else return nullopt. */ +/* See gdbtypes.h. */ -static gdb::optional +gdb::optional get_discrete_low_bound (struct type *type) { type = check_typedef (type); @@ -1107,9 +1107,9 @@ get_discrete_low_bound (struct type *type) } } -/* If TYPE's high bound is a known constant, return it, else return nullopt. */ +/* See gdbtypes.h. */ -static gdb::optional +gdb::optional get_discrete_high_bound (struct type *type) { type = check_typedef (type); diff --git a/gdb/gdbtypes.h b/gdb/gdbtypes.h index 19d07405d63..02fd8bc839b 100644 --- a/gdb/gdbtypes.h +++ b/gdb/gdbtypes.h @@ -2474,6 +2474,14 @@ extern int get_vptr_fieldno (struct type *, struct type **); extern bool get_discrete_bounds (struct type *type, LONGEST *lowp, LONGEST *highp); +/* If TYPE's low bound is a known constant, return it, else return nullopt. */ + +extern gdb::optional get_discrete_low_bound (struct type *type); + +/* If TYPE's high bound is a known constant, return it, else return nullopt. */ + +extern gdb::optional get_discrete_high_bound (struct type *type); + /* Assuming TYPE is a simple, non-empty array type, compute its upper and lower bound. Save the low bound into LOW_BOUND if not NULL. Save the high bound into HIGH_BOUND if not NULL. diff --git a/gdb/testsuite/ChangeLog b/gdb/testsuite/ChangeLog index dcbb9b273b3..09cd099b13f 100644 --- a/gdb/testsuite/ChangeLog +++ b/gdb/testsuite/ChangeLog @@ -1,3 +1,9 @@ +2020-12-09 Simon Marchi + + PR 26875, PR 26901 + * gdb.base/flexible-array-member.c: New test. + * gdb.base/flexible-array-member.exp: New test. + 2020-12-08 Tom de Vries * gdb.arch/amd64-gs_base.exp: Undo commit 67748e0f66, reimplement diff --git a/gdb/testsuite/gdb.base/flexible-array-member.c b/gdb/testsuite/gdb.base/flexible-array-member.c new file mode 100644 index 00000000000..1d8bb06b514 --- /dev/null +++ b/gdb/testsuite/gdb.base/flexible-array-member.c @@ -0,0 +1,70 @@ +/* This testcase is part of GDB, the GNU debugger. + + Copyright 2020 Free Software Foundation, Inc. + + 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 . */ + +#include + +struct no_size +{ + int n; + int items[]; +}; + +struct zero_size +{ + int n; + int items[0]; +}; + +struct zero_size_only +{ + int items[0]; +}; + +struct no_size *ns; +struct zero_size *zs; +struct zero_size_only *zso; + +static void +break_here (void) +{ +} + +int +main (void) +{ + ns = (struct no_size *) malloc (sizeof (*ns) + 3 * sizeof (int)); + zs = (struct zero_size *) malloc (sizeof (*zs) + 3 * sizeof (int)); + zso = (struct zero_size_only *) malloc (sizeof (*zso) + 3 * sizeof (int)); + + ns->n = 3; + ns->items[0] = 101; + ns->items[1] = 102; + ns->items[2] = 103; + + zs->n = 3; + zs->items[0] = 201; + zs->items[1] = 202; + zs->items[2] = 203; + + zso->items[0] = 301; + zso->items[1] = 302; + zso->items[2] = 303; + + break_here (); + + return 0; +} diff --git a/gdb/testsuite/gdb.base/flexible-array-member.exp b/gdb/testsuite/gdb.base/flexible-array-member.exp new file mode 100644 index 00000000000..973a248c5b6 --- /dev/null +++ b/gdb/testsuite/gdb.base/flexible-array-member.exp @@ -0,0 +1,66 @@ +# Copyright 2020 Free Software Foundation, Inc. + +# 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 . + +# Test printing and subscripting flexible array members. + +standard_testfile + +if { [prepare_for_testing "failed to prepare" \ + ${testfile} ${srcfile}] } { + return +} + +if { ![runto break_here] } { + untested "could not run to break_here" + return +} + +# The various cases are: +# +# - ns: flexible array member with no size +# - zs: flexible array member with size 0 (GNU C extension that predates the +# standardization of the feature, but widely supported) +# - zso: zero-size only, a corner case where the array is the sole member of +# the structure + +# Print the whole structure. + +gdb_test "print *ns" " = {n = 3, items = $hex}" +gdb_test "print *zs" " = {n = 3, items = $hex}" +gdb_test "print *zso" " = {items = $hex}" + +# Print all items. + +gdb_test "print ns->items\[0\]" " = 101" +gdb_test "print ns->items\[1\]" " = 102" +gdb_test "print ns->items\[2\]" " = 103" + +gdb_test "print zs->items\[0\]" " = 201" +gdb_test "print zs->items\[1\]" " = 202" +gdb_test "print zs->items\[2\]" " = 203" + +gdb_test "print zso->items\[0\]" " = 301" +gdb_test "print zso->items\[1\]" " = 302" +gdb_test "print zso->items\[2\]" " = 303" + +# Check taking the address of array elements (how PR 28675 was originally +# reported). + +gdb_test "print ns->items == &ns->items\[0\]" " = 1" +gdb_test "print ns->items + 1 == &ns->items\[1\]" " = 1" +gdb_test "print zs->items == &zs->items\[0\]" " = 1" +gdb_test "print zs->items + 1 == &zs->items\[1\]" " = 1" +gdb_test "print zso->items == &zso->items\[0\]" " = 1" +gdb_test "print zso->items + 1 == &zso->items\[1\]" " = 1" diff --git a/gdb/valarith.c b/gdb/valarith.c index 077bcb41dd8..37988f1dfa7 100644 --- a/gdb/valarith.c +++ b/gdb/valarith.c @@ -150,25 +150,33 @@ value_subscript (struct value *array, LONGEST index) || tarray->code () == TYPE_CODE_STRING) { struct type *range_type = tarray->index_type (); - LONGEST lowerbound, upperbound; + gdb::optional lowerbound = get_discrete_low_bound (range_type); + if (!lowerbound.has_value ()) + lowerbound = 0; - get_discrete_bounds (range_type, &lowerbound, &upperbound); if (VALUE_LVAL (array) != lval_memory) - return value_subscripted_rvalue (array, index, lowerbound); + return value_subscripted_rvalue (array, index, *lowerbound); if (!c_style) { - if (index >= lowerbound && index <= upperbound) - return value_subscripted_rvalue (array, index, lowerbound); + gdb::optional upperbound + = get_discrete_high_bound (range_type); + + if (!upperbound.has_value ()) + upperbound = 0; + + if (index >= *lowerbound && index <= *upperbound) + return value_subscripted_rvalue (array, index, *lowerbound); + /* Emit warning unless we have an array of unknown size. An array of unknown size has lowerbound 0 and upperbound -1. */ - if (upperbound > -1) + if (*upperbound > -1) warning (_("array or string index out of range")); /* fall doing C stuff */ c_style = true; } - index -= lowerbound; + index -= *lowerbound; array = value_coerce_array (array); }