From patchwork Fri Dec 11 21:38:35 2015 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Andrew Burgess X-Patchwork-Id: 9991 Received: (qmail 8970 invoked by alias); 11 Dec 2015 21:38:59 -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 8856 invoked by uid 89); 11 Dec 2015 21:38:58 -0000 Authentication-Results: sourceware.org; auth=none X-Spam-SWARE-Status: No, score=-2.4 required=5.0 tests=AWL, BAYES_00, RCVD_IN_DNSWL_LOW autolearn=ham version=3.3.2 X-HELO: mail-wm0-f53.google.com Received: from mail-wm0-f53.google.com (HELO mail-wm0-f53.google.com) (74.125.82.53) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with (AES128-GCM-SHA256 encrypted) ESMTPS; Fri, 11 Dec 2015 21:38:50 +0000 Received: by mail-wm0-f53.google.com with SMTP id l68so32267008wml.0 for ; Fri, 11 Dec 2015 13:38:50 -0800 (PST) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:in-reply-to:references; bh=UFlqc44SFrbMZUEWVf0I3mz95I3bIg/Yzz45godw+d0=; b=SSo0a9S+gw8xXSjlMLdA0e26CxItoBDCHs8wDHP3iMLDTz1Jam8T8CQjJFByIdHm45 aHgMEzkzhS/bSQOO0U/VliqyNv+x3GiiGvA5haV3c3rWo+5LUy/Lklsa+b/IGvSxzlGi BDP2//BzesBKzLTfogeqHjvhQHsq0WNuDVcIk6pd/BEb7OViUnYrWNIXLGxXZwQi0XbW Qu1OofZ3Kr91fEscB0CQDGjYoW6cUCRfpTtqoxJOqr9aXIkArsislvLN+mreT4lKjmFt rN2DovwCNMKylD7tNtpzHpcT2Tw40uA3ZQjZ6gGT2aHp+8GhtOWN9lHXNQGwkrco0UTe ZMOg== X-Gm-Message-State: ALoCoQllp2vMQw6xA1zbk4Ipv4wcerqADrgEsIYq+03EpQZhsvrccNefcGbosrdeA/KWSWVmL+SPvJaWcgGzW2yQyquirQbipA== X-Received: by 10.28.142.205 with SMTP id q196mr9120950wmd.42.1449869927509; Fri, 11 Dec 2015 13:38:47 -0800 (PST) Received: from localhost (host86-138-95-213.range86-138.btcentralplus.com. [86.138.95.213]) by smtp.gmail.com with ESMTPSA id w4sm18638625wje.49.2015.12.11.13.38.45 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Fri, 11 Dec 2015 13:38:46 -0800 (PST) From: Andrew Burgess To: gdb-patches@sourceware.org Cc: Andrew Burgess Subject: [PATCH 1/3] gdb: New set/show max-value-size command. Date: Fri, 11 Dec 2015 21:38:35 +0000 Message-Id: <57e2731e179d11c584e8cde994ab1e822a9893b0.1449869722.git.andrew.burgess@embecosm.com> In-Reply-To: References: In-Reply-To: References: X-IsSubscribed: yes For languages with dynamic types, an incorrect program could result in an incorrect, overly large type being associated with a value. Currently, attempting to print such a variable will result in gdb attempting to allocate an overly large buffer. This could result in the allocation failing, and gdb terminating, or the buffer might be allocated, but the machine on which gdb is being run might struggle due to the high memory requirement of gdb. A new user visible variable in gdb helps guard against such problems, two new commands are available: set max-value-size show max-value-size The 'max-value-size' is the maximum size in bytes that the contents of a value may allocate. Any attempt to allocate a value with size greater than this will result in an error. The default for this variable is currently unlimited. Setting the default to unlimited reduces the use of this variable a little bit, if a user hits one of these rogue types without realising it, then gdb will still allocate the large buffer, with all the problems that this entails. The user will then be forced to probably restart their gdb session, and then set the 'max-value-size' variable to guard against future crashes. However, it's not clear what a good default would actually be, given the huge range of resources that are available on different machines. One solution might be to introduce platform specific code that attempts to figure out what memory resources are available on the machine running gdb, we could then set the max-value-size to some percentage of the available memory, while still defaulting to unlimited for those machines where we can't figure out a good alternative. Such a feature is not implemented in this commit, but could be added later. gdb/ChangeLog: * value.c (max_value_size): New variable. (show_max_value_size): New function. (check_type_length_before_alloc): New function. (allocate_value_contents): Call check_type_length_before_alloc. (set_value_enclosing_type): Likewise. (_initialize_values): Add set/show handler for max-value-size. * NEWS: Mention new set/show command. gdb/doc/ChangeLog: * gdb.texinfo (Value Sizes): New section. gdb/testsuite/ChangeLog: * gdb.base/max-value-size.c: New file. * gdb.base/max-value-size.exp: New file. --- gdb/ChangeLog | 11 +++++ gdb/NEWS | 6 +++ gdb/doc/ChangeLog | 4 ++ gdb/doc/gdb.texinfo | 35 +++++++++++++++ gdb/testsuite/ChangeLog | 5 +++ gdb/testsuite/gdb.base/max-value-size.c | 26 +++++++++++ gdb/testsuite/gdb.base/max-value-size.exp | 68 +++++++++++++++++++++++++++++ gdb/value.c | 71 +++++++++++++++++++++++++++++-- 8 files changed, 222 insertions(+), 4 deletions(-) create mode 100644 gdb/testsuite/gdb.base/max-value-size.c create mode 100644 gdb/testsuite/gdb.base/max-value-size.exp diff --git a/gdb/ChangeLog b/gdb/ChangeLog index 03ae010..8e36907 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -1,3 +1,14 @@ +2015-12-11 Andrew Burgess + + * value.c (max_value_size): New variable. + (set_max_value_size): New function. + (show_max_value_size): New function. + (check_type_length_before_alloc): New function. + (allocate_value_contents): Call check_type_length_before_alloc. + (set_value_enclosing_type): Likewise. + (_initialize_values): Add set/show handler for max-value-size. + * NEWS: Mention new set/show command. + 2015-12-10 Antoine Tremblay * linux-thread-db.c (find_new_threads_callback): Use record_thread. diff --git a/gdb/NEWS b/gdb/NEWS index 9ca7f49..2fb264a 100644 --- a/gdb/NEWS +++ b/gdb/NEWS @@ -60,6 +60,12 @@ show ada print-signatures" Control whether parameter types and return types are displayed in overloads selection menus. It is activaled (@code{on}) by default. +set max-value-size +show max-value-size + Control the maximum size, in bytes, that GDB will allocate for value + contents. Prevent incorrect programs from causing GDB to allocate + overly large buffers. Default is unlimited. + * The "disassemble" command accepts a new modifier: /s. It prints mixed source+disassembly like /m with two differences: - disassembled instructions are now printed in program order, and diff --git a/gdb/doc/ChangeLog b/gdb/doc/ChangeLog index fc81d09..796e2cd 100644 --- a/gdb/doc/ChangeLog +++ b/gdb/doc/ChangeLog @@ -1,3 +1,7 @@ +2015-12-11 Andrew Burgess + + * gdb.texinfo (Value Sizes): New section. + 2015-12-10 Pedro Alves * gdb.texinfo (Threads): Replace warning with explanation diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo index bb68e21..5d8b579 100644 --- a/gdb/doc/gdb.texinfo +++ b/gdb/doc/gdb.texinfo @@ -11592,6 +11592,41 @@ $1 = 1 $2 = (void *) 0x8049560 @end smallexample +@node Value Sizes +@section Value Sizes + +Whenever @value{GDBN} prints a value memory will be allocated within +@value{GDBN} to hold the contents of the value. It is possible in +some languages with dynamic typing systems, that an invalid program +may indicate a value that is incorrectly large, this in turn may cause +@value{GDBN} to try and allocate an overly large ammount of memory. + +@table @code +@kindex set max-value-size +@itemx set max-value-size @var{bytes} +@itemx set max-value-size unlimited +Set the maximum size, in bytes, that @value{GDBN} will allocate for +the contents of a value to @var{bytes}. Any value whose contents +require more than this number of bytes can't be displayed by +@value{GDBN}, and trying to display the value will result in an error. + +Setting this variable does not effect values that have already been +allocated within gdb, only future allocations. + +By default this variable is set to @var{unlimited}, meaning +@value{GDBN} will always attempt to allocate space for the values +contents. + +There's a minimum size that @code{max-value-size} can be set too in +order that @value{GDBN} can still operate correctly. This varies by +target, but will generally be around 8 bytes. + +@kindex show max-value-size +@item show max-value-size +Show the maximum size, in bytes, that @value{GDBN} will allocate for +the contents of a value. +@end table + @node Optimized Code @chapter Debugging Optimized Code @cindex optimized code, debugging diff --git a/gdb/testsuite/ChangeLog b/gdb/testsuite/ChangeLog index ab7a324..93bb3bb 100644 --- a/gdb/testsuite/ChangeLog +++ b/gdb/testsuite/ChangeLog @@ -1,3 +1,8 @@ +2015-12-11 Andrew Burgess + + * gdb.base/max-value-size.c: New file. + * gdb.base/max-value-size.exp: New file. + 2015-12-10 Pedro Alves * gdb.multi/base.exp: Remove stale "spaces" references. diff --git a/gdb/testsuite/gdb.base/max-value-size.c b/gdb/testsuite/gdb.base/max-value-size.c new file mode 100644 index 0000000..4d47280 --- /dev/null +++ b/gdb/testsuite/gdb.base/max-value-size.c @@ -0,0 +1,26 @@ +/* This testcase is part of GDB, the GNU debugger. + + Copyright 2015 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 . */ + +char one; +char ten [10]; +char one_hundred [100]; + +int +main () +{ + return 0; +} diff --git a/gdb/testsuite/gdb.base/max-value-size.exp b/gdb/testsuite/gdb.base/max-value-size.exp new file mode 100644 index 0000000..cb09ad8 --- /dev/null +++ b/gdb/testsuite/gdb.base/max-value-size.exp @@ -0,0 +1,68 @@ +# Copyright 2015 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 . + +standard_testfile + +if {[prepare_for_testing $testfile.exp $testfile $srcfile debug]} { + untested $testfile.exp + return -1 +} + +if ![runto_main] then { + fail "Can't run to main" + return 0 +} + +gdb_test "show max-value-size" \ + "Maximum value size is unlimited." \ + "the initial value of max-value-size is unlimited" + +with_test_prefix "max-value-size is 'unlimited'" { + gdb_test "p/d one" " = 0" + gdb_test "p/d one_hundred" " = \\{0 \\}" +} + +# Check that setting it low does prevent values being allocated. +gdb_test_no_output "set max-value-size 25" +with_test_prefix "max-value-size is '25'" { + gdb_test "p/d one" " = 0" + gdb_test "p/d one_hundred" "value contents too large \\(100 bytes\\)" +} + +# Check that we can't set the maximum size stupidly low. +gdb_test "set max-value-size 1" \ + "max-value-size set too low, increasing to \[0-9\]+ bytes" +gdb_test "set max-value-size 0" \ + "max-value-size set too low, increasing to \[0-9\]+ bytes" + +# Check we can set it to something "large", and then view our values. +gdb_test_no_output "set max-value-size 200" +gdb_test "show max-value-size" \ + "Maximum value size is 200 bytes." \ + "check that the value shows as 200 bytes" +with_test_prefix "max-value-size is '200'" { + gdb_test "p/d one" " = 0" + gdb_test "p/d one_hundred" " = \\{0 \\}" +} + +# Check we can restore it too unlimited. +gdb_test_no_output "set max-value-size unlimited" +gdb_test "show max-value-size" \ + "Maximum value size is unlimited." \ + "check that the unlimited maximum restored correctly" +with_test_prefix "max-value-size is 'unlimited' again" { + gdb_test "p/d one" " = 0" + gdb_test "p/d one_hundred" " = \\{0 \\}" +} diff --git a/gdb/value.c b/gdb/value.c index 91bf49e..9554333 100644 --- a/gdb/value.c +++ b/gdb/value.c @@ -955,13 +955,60 @@ allocate_value_lazy (struct type *type) return val; } +/* The maximum size, in bytes, that the contents of a value might have. + Setting this to -1 indicates unlimited. Adjust this variable does not + invalidate already allocated values, only prevents future large values + being allocated. */ + +static int max_value_size = -1; +static void +set_max_value_size (char *args, int from_tty, + struct cmd_list_element *c) +{ + if (max_value_size > -1 && max_value_size < sizeof (LONGEST)) + { + max_value_size = sizeof (LONGEST); + error (_("max-value-size set too low, increasing to %u bytes"), + ((unsigned int) max_value_size)); + } +} +static void +show_max_value_size (struct ui_file *file, int from_tty, + struct cmd_list_element *c, const char *value) +{ + if (max_value_size == -1) + fprintf_filtered (file, _("Maximum value size is unlimited.\n")); + else + fprintf_filtered (file, _("Maximum value size is %d bytes.\n"), + max_value_size); +} + +/* Called before we attempt to allocate or reallocate a buffer for the + contents of a value. TYPE is the type of the value for which we are + allocating the buffer. If the buffer is too large (based on the user + controllable setting) then throw an error. If this function returns + then we should attempt to allocate the buffer. */ + +static void +check_type_length_before_alloc (const struct type *type) +{ + int length = TYPE_LENGTH (type); + if (max_value_size > -1 && (length < 0 || length > max_value_size)) + error (_("value contents too large (%u bytes)"), + ((unsigned int) length)); +} + /* Allocate the contents of VAL if it has not been allocated yet. */ static void allocate_value_contents (struct value *val) { if (!val->contents) - val->contents = (gdb_byte *) xzalloc (TYPE_LENGTH (val->enclosing_type)); + { + check_type_length_before_alloc (val->enclosing_type); + val->contents = + (gdb_byte *) xzalloc (TYPE_LENGTH (val->enclosing_type)); + } } /* Allocate a value and its contents for type TYPE. */ @@ -2986,9 +3033,12 @@ value_static_field (struct type *type, int fieldno) void set_value_enclosing_type (struct value *val, struct type *new_encl_type) { - if (TYPE_LENGTH (new_encl_type) > TYPE_LENGTH (value_enclosing_type (val))) - val->contents = - (gdb_byte *) xrealloc (val->contents, TYPE_LENGTH (new_encl_type)); + if (TYPE_LENGTH (new_encl_type) > TYPE_LENGTH (value_enclosing_type (val))) + { + check_type_length_before_alloc (new_encl_type); + val->contents = + (gdb_byte *) xrealloc (val->contents, TYPE_LENGTH (new_encl_type)); + } val->enclosing_type = new_encl_type; } @@ -4013,4 +4063,17 @@ Check whether an expression is void.\n\ Usage: $_isvoid (expression)\n\ Return 1 if the expression is void, zero otherwise."), isvoid_internal_fn, NULL); + + add_setshow_zuinteger_unlimited_cmd ("max-value-size", + class_support, &max_value_size, _("\ +Set maximum sized value gdb will load from the inferior."), _("\ +Show maximum sized value gdb will load from the inferior."), _("\ +Use this to control the maximum size, in bytes, of a value that gdb\n\ +will load from the inferior. Setting this value to 'unlimited'\n\ +disables checking.\n\ +Setting this does not invalidate already allocated values, it only\n\ +prevents future values, larger than this size, from being allocated."), + set_max_value_size, + show_max_value_size, + &setlist, &showlist); }