From: Hannes Domani Date: Tue, 6 Aug 2024 17:34:18 +0000 (+0200) Subject: Mark unavailable bytes of limited-length arrays when allocating contents X-Git-Tag: gdb-16-branchpoint~1218 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=8fdd2b2bcd8117cafcc6ef976e45f0d9f95fb528;p=thirdparty%2Fbinutils-gdb.git Mark unavailable bytes of limited-length arrays when allocating contents Using 'output' to print arrays larger than max-value-size, with only repeating elements, can cause gdb to crash: ``` $ cat a.c: char a[1000000]; int main() { return a[0]; } $ gdb -q a (gdb) print a $1 = {0 '\000' , } (gdb) output a This application has requested the Runtime to terminate it in an unusual way. Please contact the application's support team for more information. ``` Using 'print' works, because value::record_latest sets the unavailable bytes of the value when it's added to the value history. But 'outout' doesn't do that, so the printing tries to access more bytes than are available. The original problem in PR32015 was about using 'print' of a dynamic array in a D program. Here the crash happens because for 'print' the value was a struct with length/ptr fields, which is converted in d-valprint.c into an array. So value::record_latest didn't have a chance to mark the unavailable bytes in this case. To make sure the unavailable bytes always match the contents, this fixes it by marking the unavailable bytes immediately after the contents are allocated. Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=32015 Reviewed-By: Alexandra Petlanova Hajkova Approved-By: Andrew Burgess --- diff --git a/gdb/testsuite/gdb.base/limited-length.c b/gdb/testsuite/gdb.base/limited-length.c index 627c34d2dbe..c8ece16167e 100644 --- a/gdb/testsuite/gdb.base/limited-length.c +++ b/gdb/testsuite/gdb.base/limited-length.c @@ -41,6 +41,8 @@ int large_2d_array[][10] = { {90, 91, 92, 93, 94, 95, 96, 97, 98, 99} }; +char large_empty_string[100000] = ""; + int main () { diff --git a/gdb/testsuite/gdb.base/limited-length.exp b/gdb/testsuite/gdb.base/limited-length.exp index a24adcb458a..2d160e128ae 100644 --- a/gdb/testsuite/gdb.base/limited-length.exp +++ b/gdb/testsuite/gdb.base/limited-length.exp @@ -240,3 +240,13 @@ with_test_prefix "with unlimited print elements" { "value is not available" \ "output expression referring unavailable element from history" } + +gdb_test_no_output "set max-value-size 10000" +gdb_test_no_output "set print elements 200" + +gdb_test "print large_empty_string" \ + " = \\\{0 '\\\\000' , \\\}" \ + "print large empty string which is not fully available" +gdb_test -nonl "output large_empty_string" \ + "\\\{0 '\\\\000' , \\\}" \ + "output large empty string which is not fully available" diff --git a/gdb/value.c b/gdb/value.c index 09fb19b9bf8..aaa9ed20ae1 100644 --- a/gdb/value.c +++ b/gdb/value.c @@ -1716,10 +1716,6 @@ value::record_latest () fetch_lazy (); } - ULONGEST limit = m_limited_length; - if (limit != 0) - mark_bytes_unavailable (limit, m_enclosing_type->length () - limit); - /* Mark the value as recorded in the history for the availability check. */ m_in_history = true; @@ -3990,6 +3986,11 @@ value::fetch_lazy_memory () if (len > 0) read_value_memory (this, 0, stack (), addr, contents_all_raw ().data (), len); + + /* If only part of an array was loaded, mark the rest as unavailable. */ + if (m_limited_length > 0) + mark_bytes_unavailable (m_limited_length, + m_enclosing_type->length () - m_limited_length); } /* See value.h. */