[2/2] gdb: Check element of optimised out vla exists

Message ID 8e9a61d7fd387de60ea454bd4a308ecef1a0c45d.1533157680.git.andrew.burgess@embecosm.com
State New, archived
Headers

Commit Message

Andrew Burgess Aug. 1, 2018, 9:12 p.m. UTC
  The new tests cover accessing an element that should exist in the VLA
(except it has been optimised out), accessing just beyond the VLA, and
accessing far beyond the VLA.

The third test is included as this might cause GDB to crash without
the fix (though undefined behaviour, so, you never know).

I did have a patch that added an assertion and caught the rogue
access, however, it turns out the assertion triggers from our
extension language pretty-printer code <sigh> so I've had to drop the
assertion for now while I work on fixing that.

Thanks,
Andrew

---

If a vla is not in memory, and the upper bound is not defined, then we
can't know that an array element exists or not, and we should not try
to access the array element.  One case where this happens is for
arrays that have been optimised out, the array will then have
VALUE_LVAL of not_lval, and an undefined upper bound, if we then try
to access an element of this array we will index into random GDB
memory.

An argument could be made that even for arrays that are in inferior
memory, if the upper bound is not defined then we should not try to
access the array element, however, in some of the Fortran tests, it
seems as though we do rely indexing from a base address into an array
which has no bounds defined.  In this case GDBs standard protection
for detecting unreadable target memory prevents bad thing happening.

gdb/ChangeLog:

	* valarith.c (value_subscripted_rvalue): If an array is not in
	memory, and we don't know the upper bound, then we can't know that
	the requested element exists or not.

gdb/testsuite/ChangeLog:

	* gdb.base/vla-optimized-out.exp: Add new test.
---
 gdb/ChangeLog                                |  6 ++++++
 gdb/testsuite/ChangeLog                      |  4 ++++
 gdb/testsuite/gdb.base/vla-optimized-out.exp | 22 ++++++++++++++++++++++
 gdb/valarith.c                               |  7 +++++--
 4 files changed, 37 insertions(+), 2 deletions(-)
  

Comments

Tom Tromey Aug. 2, 2018, 7:01 p.m. UTC | #1
>>>>> "Andrew" == Andrew Burgess <andrew.burgess@embecosm.com> writes:

Andrew> The third test is included as this might cause GDB to crash without
Andrew> the fix (though undefined behaviour, so, you never know).

This will be nice if we enable -fsanitize=undefined, because in that
case it would cause a test failure.

Andrew> An argument could be made that even for arrays that are in inferior
Andrew> memory, if the upper bound is not defined then we should not try to
Andrew> access the array element

In this case, it seems to me that it's fine for gdb to try to respect
the user's request.  After all, although gdb doesn't know the array
bound, the user might.

Andrew> gdb/ChangeLog:

Andrew> 	* valarith.c (value_subscripted_rvalue): If an array is not in
Andrew> 	memory, and we don't know the upper bound, then we can't know that
Andrew> 	the requested element exists or not.

Andrew> gdb/testsuite/ChangeLog:

Andrew> 	* gdb.base/vla-optimized-out.exp: Add new test.

Thank you.  This is ok.

Tom
  

Patch

diff --git a/gdb/testsuite/gdb.base/vla-optimized-out.exp b/gdb/testsuite/gdb.base/vla-optimized-out.exp
index fa521765969..ed9f269b5f3 100644
--- a/gdb/testsuite/gdb.base/vla-optimized-out.exp
+++ b/gdb/testsuite/gdb.base/vla-optimized-out.exp
@@ -37,6 +37,28 @@  proc vla_optimized_out {compile_flags exe_suffix sizeof_result} {
     gdb_test "p sizeof (a)" \
 	" = $sizeof_result" \
 	"printed size of optimized out vla"
+
+    # At lower optimisation levels, the upper bound of the array is
+    # still defined, it's just the loctaion that tells GDB the array
+    # is optimised out.  In that case, when we access an element that
+    # is within the bounds of the array an answer of '<optimized out>'
+    # is reasonable.
+    #
+    # At higher optimisation levels, the array bounds themselves have
+    # been removed.  As such GDB can't be expected to know if the
+    # array contains _any_ elements at all.  It seems reasonable in
+    # that case to reply with 'no such vector element'.
+    gdb_test "p a\[0\]" \
+	"(= <optimized out>|no such vector element)" \
+	"print out of range element of vla (0)"
+
+    gdb_test "p a\[6\]" \
+	"no such vector element" \
+	"print out of range element of vla (6)"
+
+    gdb_test "p a\[0xffffffff\]" \
+	"no such vector element" \
+	"print out of range element of vla (0xffffffff)"
 }
 
 foreach test_settings [list \
diff --git a/gdb/valarith.c b/gdb/valarith.c
index 01ca50d3d21..807cdd5dbd4 100644
--- a/gdb/valarith.c
+++ b/gdb/valarith.c
@@ -189,8 +189,11 @@  value_subscripted_rvalue (struct value *array, LONGEST index, int lowerbound)
   ULONGEST elt_size = type_length_units (elt_type);
   ULONGEST elt_offs = elt_size * (index - lowerbound);
 
-  if (index < lowerbound || (!TYPE_ARRAY_UPPER_BOUND_IS_UNDEFINED (array_type)
-			     && elt_offs >= type_length_units (array_type)))
+  if (index < lowerbound
+      || (!TYPE_ARRAY_UPPER_BOUND_IS_UNDEFINED (array_type)
+          && elt_offs >= type_length_units (array_type))
+      || (VALUE_LVAL (array) != lval_memory
+          && TYPE_ARRAY_UPPER_BOUND_IS_UNDEFINED (array_type)))
     {
       if (type_not_associated (array_type))
         error (_("no such vector element (vector not associated)"));