[2/2] Tweak the handling of $GDBHISTSIZE edge cases [PR gdb/16999]

Message ID 1432293831-23599-2-git-send-email-patrick@parcs.ath.cx
State New, archived
Headers

Commit Message

Patrick Palka May 22, 2015, 11:23 a.m. UTC
  When GDB reads a nonsensical value for the GDBHISTSIZE environment
variable, i.e. one that is non-numeric or negative, GDB then sets its
history size to 0.  This behavior is annoying and also inconsistent
with the behavior of bash.

This patch makes the behavior of invalid GDBHISTSIZE consistent with how
bash handles HISTSIZE.  When we encounter a null or out-of-range
GDBHISTSIZE (outside of [0, INT_MAX]) we now set the history size to
unlimited instead of 0.  When we encounter a non-numeric GDBHISTSIZE we
do nothing.

gdb/ChangeLog:

	PR gdb/16999
	* top.c (init_history): For null or out-of-range GDBHISTSIZE,
	set history size to unlimited.  Ignore non-numeric GDBHISTSIZE.

gdb/testsuite/ChangeLog:

	PR gdb/16999
	* gdb.base/gdbhistsize-history.exp: New test.
---
 gdb/NEWS                                       |  4 +-
 gdb/doc/gdb.texinfo                            |  9 ++--
 gdb/testsuite/gdb.base/gdbhistsize-history.exp | 69 ++++++++++++++++++++++++++
 gdb/top.c                                      | 42 ++++++++++------
 4 files changed, 105 insertions(+), 19 deletions(-)
 create mode 100644 gdb/testsuite/gdb.base/gdbhistsize-history.exp
  

Comments

Patrick Palka May 22, 2015, 11:57 a.m. UTC | #1
On Fri, May 22, 2015 at 7:23 AM, Patrick Palka <patrick@parcs.ath.cx> wrote:
> When GDB reads a nonsensical value for the GDBHISTSIZE environment
> variable, i.e. one that is non-numeric or negative, GDB then sets its
> history size to 0.  This behavior is annoying and also inconsistent
> with the behavior of bash.
>
> This patch makes the behavior of invalid GDBHISTSIZE consistent with how
> bash handles HISTSIZE.  When we encounter a null or out-of-range
> GDBHISTSIZE (outside of [0, INT_MAX]) we now set the history size to
> unlimited instead of 0.  When we encounter a non-numeric GDBHISTSIZE we
> do nothing.
>
> gdb/ChangeLog:
>
>         PR gdb/16999
>         * top.c (init_history): For null or out-of-range GDBHISTSIZE,
>         set history size to unlimited.  Ignore non-numeric GDBHISTSIZE.
>

Oops, this ChangeLog entry is not complete.  I will make sure to
complete it before pushing/re-posting.
  
Pedro Alves May 29, 2015, 9:32 a.m. UTC | #2
On 05/22/2015 12:23 PM, Patrick Palka wrote:

> +      while (isspace (*tmpenv))
> +	tmpenv++;

...

> +
> +      while (isspace (*endptr))
> +	endptr++;

Use skip_spaces/skip_spaces_const for these.

Otherwise looks good to me.

(I suspect that testing the interaction between setting
the history both from a .gdbinit and $GDBHISTSIZE would
call for merging the gdbhistsize-history.exp / gdbinit-history.exp
to a single file.)

Thanks,
Pedro Alves
  
Patrick Palka June 17, 2015, 7:17 p.m. UTC | #3
On Fri, May 29, 2015 at 5:32 AM, Pedro Alves <palves@redhat.com> wrote:
> On 05/22/2015 12:23 PM, Patrick Palka wrote:
>
>> +      while (isspace (*tmpenv))
>> +     tmpenv++;
>
> ...
>
>> +
>> +      while (isspace (*endptr))
>> +     endptr++;
>
> Use skip_spaces/skip_spaces_const for these.
>
> Otherwise looks good to me.
>
> (I suspect that testing the interaction between setting
> the history both from a .gdbinit and $GDBHISTSIZE would
> call for merging the gdbhistsize-history.exp / gdbinit-history.exp
> to a single file.)

Committed.

The test files would not necessarily have to be merged to test the
interaction between $GDBHISTSIZE and .gdbinit.  One may worry about
code duplication by not merging them, but I think there would be code
duplication either way unless you really refactor the tests.  I think
it would be easier to test the interaction inside gdbinit-history.exp
since adding environment variable manipulation to gdbinit-history.exp
is easier than adding .gdbinit file manipulation in
gdbhistsize-history.exp.  In fact, gdbinit-history.exp already has to
manipulate the environment to unset GDBHISTSIZE.  So adding an
interaction test would only require a few lines of code.  I'll do it.

>
> Thanks,
> Pedro Alves
>
  
Yao Qi June 23, 2015, 12:56 p.m. UTC | #4
Patrick Palka <patrick@parcs.ath.cx> writes:

Hi Patrick,

> +# A huge number (hopefully larger than INT_MAX)
> +test_histsize_history_setting "99999999999999999999999999999999999"
> "unlimited"

This test fails on some targets (32-bit?) as shown in buildbot,
https://www.sourceware.org/ml/gdb-testers/2015-q2/msg06883.html

 (gdb) show history size
 The size of the command history is 2147483647.
 (gdb) FAIL: gdb.base/gdbhistsize-history.exp: histsize=99999999999999999999999999999999999: show history size
  
Patrick Palka June 23, 2015, 2:28 p.m. UTC | #5
On Tue, Jun 23, 2015 at 8:56 AM, Yao Qi <qiyaoltc@gmail.com> wrote:
> Patrick Palka <patrick@parcs.ath.cx> writes:
>
> Hi Patrick,
>
>> +# A huge number (hopefully larger than INT_MAX)
>> +test_histsize_history_setting "99999999999999999999999999999999999"
>> "unlimited"
>
> This test fails on some targets (32-bit?) as shown in buildbot,
> https://www.sourceware.org/ml/gdb-testers/2015-q2/msg06883.html
>
>  (gdb) show history size
>  The size of the command history is 2147483647.
>  (gdb) FAIL: gdb.base/gdbhistsize-history.exp: histsize=99999999999999999999999999999999999: show history size
>
> --
> Yao (齐尧)


Thanks for the heads up.  I failed to account for targets where
INT_MAX == LONG_MAX.  I have a patch to send.
  

Patch

diff --git a/gdb/NEWS b/gdb/NEWS
index 1be239f..f3cee13 100644
--- a/gdb/NEWS
+++ b/gdb/NEWS
@@ -50,7 +50,9 @@ 
 
 * The HISTSIZE environment variable is no longer read when determining
   the size of GDB's command history.  GDB now instead reads the dedicated
-  GDBHISTSIZE environment variable.
+  GDBHISTSIZE environment variable.  Setting GDBHISTSIZE to "-1" or to "" now
+  disables truncation of command history.  Non-numeric values of GDBHISTSIZE
+  are ignored.
 
 * Guile Scripting
 
diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
index c21a312..b0bd194 100644
--- a/gdb/doc/gdb.texinfo
+++ b/gdb/doc/gdb.texinfo
@@ -22603,10 +22603,11 @@  Stop recording command history in a file.
 @item set history size @var{size}
 @itemx set history size unlimited
 Set the number of commands which @value{GDBN} keeps in its history list.
-This defaults to the value of the environment variable
-@code{GDBHISTSIZE}, or to 256 if this variable is not set.  If @var{size}
-is @code{unlimited}, the number of commands @value{GDBN} keeps in the
-history list is unlimited.
+This defaults to the value of the environment variable @code{GDBHISTSIZE}, or
+to 256 if this variable is not set.  Non-numeric values of @code{GDBHISTSIZE}
+are ignored.  If @var{size} is @code{unlimited} or if @code{GDBHISTSIZE} is a
+negative number, the number of commands @value{GDBN} keeps in the history list
+is unlimited.
 @end table
 
 History expansion assigns special meaning to the character @kbd{!}.
diff --git a/gdb/testsuite/gdb.base/gdbhistsize-history.exp b/gdb/testsuite/gdb.base/gdbhistsize-history.exp
new file mode 100644
index 0000000..a7b70d1
--- /dev/null
+++ b/gdb/testsuite/gdb.base/gdbhistsize-history.exp
@@ -0,0 +1,69 @@ 
+# 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 <http://www.gnu.org/licenses/>.
+
+# This file is part of the gdb testsuite.
+
+# Test the setting of "history size" via the GDBHISTSIZE environment variable
+
+
+# Check that the history size is properly set to SIZE when the environment
+# variable ENV_VAR is set to GDBHISTSIZE.
+
+proc test_histsize_history_setting { histsize size { env_var "GDBHISTSIZE" } } {
+    global env
+
+    set have_old_gdbhistsize 0
+    if [info exists env($env_var)] {
+        set have_old_gdbhistsize 1
+        set old_gdbhistsize $env($env_var)
+    }
+    set env($env_var) $histsize
+
+    with_test_prefix "histsize=$histsize" {
+	gdb_exit
+	gdb_start
+
+	gdb_test "show history size" "The size of the command history is $size."
+
+	if { $size == "0" } {
+	    gdb_test_no_output "show commands"
+	} elseif { $size != "1" } {
+	    gdb_test "show commands" \
+		     "    .  show history size\r\n    .  show commands"
+	}
+
+	if { $have_old_gdbhistsize } {
+	    set env($env_var) $old_gdbhistsize
+	} else {
+	    unset env($env_var)
+	}
+    }
+}
+
+test_histsize_history_setting "" "unlimited"
+test_histsize_history_setting "0" "0"
+test_histsize_history_setting "20" "20"
+test_histsize_history_setting " 20 " "20"
+test_histsize_history_setting "-5" "unlimited"
+
+# Test defaulting to 256 upon encountering a non-numeric GDBHISTSIZE.
+test_histsize_history_setting "not_an_integer" "256"
+test_histsize_history_setting "10zab" "256"
+
+# A huge number (hopefully larger than INT_MAX)
+test_histsize_history_setting "99999999999999999999999999999999999" "unlimited"
+
+# We no longer read HISTSIZE
+test_histsize_history_setting "50" "256" "HISTSIZE"
diff --git a/gdb/top.c b/gdb/top.c
index 6f0421d..efcb8d0 100644
--- a/gdb/top.c
+++ b/gdb/top.c
@@ -1683,21 +1683,35 @@  init_history (void)
   tmpenv = getenv ("GDBHISTSIZE");
   if (tmpenv)
     {
-      int var;
-
-      var = atoi (tmpenv);
-      if (var < 0)
-	{
-	  /* Prefer ending up with no history rather than overflowing
-	     readline's history interface, which uses signed 'int'
-	     everywhere.  */
-	  var = 0;
-	}
-
-      history_size_setshow_var = var;
+      long var;
+      char *endptr;
+
+      while (isspace (*tmpenv))
+	tmpenv++;
+
+      var = strtol (tmpenv, &endptr, 10);
+
+      while (isspace (*endptr))
+	endptr++;
+
+      /* If GDBHISTSIZE is non-numeric then ignore it.  If GDBHISTSIZE is the
+	 empty string, a negative number or a huge positive number (larger than
+	 INT_MAX) then set the history size to unlimited.  Otherwise set our
+	 history size to the number we have read.  This behavior is consistent
+	 with how bash handles HISTSIZE.  */
+      if (*endptr != '\0')
+	;
+      else if (*tmpenv == '\0'
+	       || var < 0
+	       || var > INT_MAX)
+	history_size_setshow_var = -1;
+      else
+	history_size_setshow_var = var;
     }
-  /* If the init file hasn't set a size yet, pick the default.  */
-  else if (history_size_setshow_var == -2)
+
+  /* If neither the init file nor GDBHISTSIZE has set a size yet, pick the
+     default.  */
+  if (history_size_setshow_var == -2)
     history_size_setshow_var = 256;
 
   set_readline_history_size (history_size_setshow_var);