public inbox for gdb-patches@sourceware.org
 help / color / mirror / Atom feed
* [RFC] [gdb/python] Make sure python sys.exit makes gdb exit
@ 2024-07-27  9:48 Tom de Vries
  2024-07-30 18:53 ` Guinevere Larsen
  0 siblings, 1 reply; 4+ messages in thread
From: Tom de Vries @ 2024-07-27  9:48 UTC (permalink / raw)
  To: gdb-patches

With gdb 15.1, python sys.exit no longer makes gdb exit:
...
$ gdb -q -batch -ex "python sys.exit(2)" -ex "print 123"; echo $?
Python Exception <class 'SystemExit'>: 2
Error occurred in Python: 2
$1 = 123
0
...

This is a change in behaviour since commit a207f6b3a38 ("Rewrite "python"
command exception handling"), first available in gdb 15.1.

The question is whether this is a regression.

The semantics of sys.exit / exception SystemExit allow intercepting the thrown
exception [1].

This patch reverts to the old behaviour by handling PyExc_SystemExit in
gdbpy_handle_exception, such what we have instead:
...
$ gdb -q -batch -ex "python sys.exit(2)" -ex "print 123"; echo $?
2
...

But alternatively, we could decide that this is the behaviour we want for gdb.

Note that os._exit works as expected, and could be used instead.

Tested on x86_64-linux.

PR python/31946
Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=31946

[1] https://docs.python.org/3/library/sys.html#sys.exit
---
 gdb/python/py-utils.c                 |  7 +++++
 gdb/testsuite/gdb.python/sys-exit.exp | 37 +++++++++++++++++++++++++++
 2 files changed, 44 insertions(+)
 create mode 100644 gdb/testsuite/gdb.python/sys-exit.exp

diff --git a/gdb/python/py-utils.c b/gdb/python/py-utils.c
index 47f65f4fd44..ef70d937f9c 100644
--- a/gdb/python/py-utils.c
+++ b/gdb/python/py-utils.c
@@ -390,6 +390,13 @@ gdbpy_handle_exception ()
 
   if (fetched_error.type_matches (PyExc_KeyboardInterrupt))
     throw_quit ("Quit");
+  else if (fetched_error.type_matches (PyExc_SystemExit))
+    {
+      int exit_arg = 0;
+      if (msg != nullptr && *msg != '\0')
+	exit_arg = atoi (msg.get ());
+      quit_force (&exit_arg, 0);
+    }
   else if (! fetched_error.type_matches (gdbpy_gdberror_exc)
 	   || msg == NULL || *msg == '\0')
     {
diff --git a/gdb/testsuite/gdb.python/sys-exit.exp b/gdb/testsuite/gdb.python/sys-exit.exp
new file mode 100644
index 00000000000..9dd914d46f9
--- /dev/null
+++ b/gdb/testsuite/gdb.python/sys-exit.exp
@@ -0,0 +1,37 @@
+# Copyright 2024 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/>.
+
+# Check that python sys.exit makes gdb exit, with the correct exit status.
+
+require allow_python_tests
+
+foreach_with_prefix n { 0 1 2 } {
+    clean_restart
+
+    # Regression test for PR python/31946.
+    gdb_test_multiple "python sys.exit ($n)" "python sys.exit" {
+	eof {
+	    set wait_status [wait -i $gdb_spawn_id]
+	    unset gdb_spawn_id
+
+	    verbose -log "GDB process exited with wait status $wait_status"
+
+	    set os_error [lindex $wait_status 2]
+	    set exit_status [lindex $wait_status 3]
+
+	    gdb_assert { $os_error == 0 && $exit_status == $n } $gdb_test_name
+	}
+    }
+}

base-commit: 8d40cbfde5988ac6d7dad2fc2796d13c9ddb210b
-- 
2.35.3


^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: [RFC] [gdb/python] Make sure python sys.exit makes gdb exit
  2024-07-27  9:48 [RFC] [gdb/python] Make sure python sys.exit makes gdb exit Tom de Vries
@ 2024-07-30 18:53 ` Guinevere Larsen
  2024-08-11 23:22   ` Joel Brobecker
  0 siblings, 1 reply; 4+ messages in thread
From: Guinevere Larsen @ 2024-07-30 18:53 UTC (permalink / raw)
  To: Tom de Vries, gdb-patches

On 7/27/24 6:48 AM, Tom de Vries wrote:
> With gdb 15.1, python sys.exit no longer makes gdb exit:
> ...
> $ gdb -q -batch -ex "python sys.exit(2)" -ex "print 123"; echo $?
> Python Exception <class 'SystemExit'>: 2
> Error occurred in Python: 2
> $1 = 123
> 0
> ...
>
> This is a change in behaviour since commit a207f6b3a38 ("Rewrite "python"
> command exception handling"), first available in gdb 15.1.
>
> The question is whether this is a regression.
>
> The semantics of sys.exit / exception SystemExit allow intercepting the thrown
> exception [1].
>
> This patch reverts to the old behaviour by handling PyExc_SystemExit in
> gdbpy_handle_exception, such what we have instead:
> ...
> $ gdb -q -batch -ex "python sys.exit(2)" -ex "print 123"; echo $?
> 2
> ...
>
> But alternatively, we could decide that this is the behaviour we want for gdb.

For what it's worth, I think we should honor sys.exit requests from 
users, and exit GDB. Throwing an exception to exit seems (to me) to be 
intended for what this patch does: perform cleanups as required so we 
leave the system in a reasonable state when quitting, but still quit 
nonetheless.

>
> Note that os._exit works as expected, and could be used instead.

python's docs for os._exit[1] say the following:

 > The standard way to exit is sys.exit(n). _exit() should normally only 
be used in the child process after a fork().

so just eating the exception and not exiting feels wrong.


The code and test look fine, but I don't really understand this area of 
GDB, but I have tested and verified that it fixes the issue so feel free 
to add my tb tag: Tested-By: Guinevere Larsen <blarsen@redhat.com>

-- 
Cheers,
Guinevere Larsen
She/Her/Hers

[1] https://docs.python.org/3/library/os.html#os._exit

>
> Tested on x86_64-linux.
>
> PR python/31946
> Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=31946
>
> [1] https://docs.python.org/3/library/sys.html#sys.exit
> ---
>   gdb/python/py-utils.c                 |  7 +++++
>   gdb/testsuite/gdb.python/sys-exit.exp | 37 +++++++++++++++++++++++++++
>   2 files changed, 44 insertions(+)
>   create mode 100644 gdb/testsuite/gdb.python/sys-exit.exp
>
> diff --git a/gdb/python/py-utils.c b/gdb/python/py-utils.c
> index 47f65f4fd44..ef70d937f9c 100644
> --- a/gdb/python/py-utils.c
> +++ b/gdb/python/py-utils.c
> @@ -390,6 +390,13 @@ gdbpy_handle_exception ()
>   
>     if (fetched_error.type_matches (PyExc_KeyboardInterrupt))
>       throw_quit ("Quit");
> +  else if (fetched_error.type_matches (PyExc_SystemExit))
> +    {
> +      int exit_arg = 0;
> +      if (msg != nullptr && *msg != '\0')
> +	exit_arg = atoi (msg.get ());
> +      quit_force (&exit_arg, 0);
> +    }
>     else if (! fetched_error.type_matches (gdbpy_gdberror_exc)
>   	   || msg == NULL || *msg == '\0')
>       {
> diff --git a/gdb/testsuite/gdb.python/sys-exit.exp b/gdb/testsuite/gdb.python/sys-exit.exp
> new file mode 100644
> index 00000000000..9dd914d46f9
> --- /dev/null
> +++ b/gdb/testsuite/gdb.python/sys-exit.exp
> @@ -0,0 +1,37 @@
> +# Copyright 2024 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/>.
> +
> +# Check that python sys.exit makes gdb exit, with the correct exit status.
> +
> +require allow_python_tests
> +
> +foreach_with_prefix n { 0 1 2 } {
> +    clean_restart
> +
> +    # Regression test for PR python/31946.
> +    gdb_test_multiple "python sys.exit ($n)" "python sys.exit" {
> +	eof {
> +	    set wait_status [wait -i $gdb_spawn_id]
> +	    unset gdb_spawn_id
> +
> +	    verbose -log "GDB process exited with wait status $wait_status"
> +
> +	    set os_error [lindex $wait_status 2]
> +	    set exit_status [lindex $wait_status 3]
> +
> +	    gdb_assert { $os_error == 0 && $exit_status == $n } $gdb_test_name
> +	}
> +    }
> +}
>
> base-commit: 8d40cbfde5988ac6d7dad2fc2796d13c9ddb210b


^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: [RFC] [gdb/python] Make sure python sys.exit makes gdb exit
  2024-07-30 18:53 ` Guinevere Larsen
@ 2024-08-11 23:22   ` Joel Brobecker
  2024-08-13 11:05     ` Tom de Vries
  0 siblings, 1 reply; 4+ messages in thread
From: Joel Brobecker @ 2024-08-11 23:22 UTC (permalink / raw)
  To: Guinevere Larsen; +Cc: Tom de Vries, gdb-patches, Joel Brobecker

> > With gdb 15.1, python sys.exit no longer makes gdb exit:
> > ...
> > $ gdb -q -batch -ex "python sys.exit(2)" -ex "print 123"; echo $?
> > Python Exception <class 'SystemExit'>: 2
> > Error occurred in Python: 2
> > $1 = 123
> > 0
> > ...
> > 
> > This is a change in behaviour since commit a207f6b3a38 ("Rewrite "python"
> > command exception handling"), first available in gdb 15.1.
> > 
> > The question is whether this is a regression.

I had a bit of a knee-jerk reaction at first, and thought perhaps
we should perhaps provide an API for exiting GDB. Looking at
the semantics of what sys.exit does, I eventually reached the same
conclusion as Tom and Guinevere. It makes more sense to restore
the previous behavior, and have GDB exit when a SystemExit exception
is raised in the main thread, and unhandled.

-- 
Joel

^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: [RFC] [gdb/python] Make sure python sys.exit makes gdb exit
  2024-08-11 23:22   ` Joel Brobecker
@ 2024-08-13 11:05     ` Tom de Vries
  0 siblings, 0 replies; 4+ messages in thread
From: Tom de Vries @ 2024-08-13 11:05 UTC (permalink / raw)
  To: Joel Brobecker, Guinevere Larsen; +Cc: gdb-patches

On 8/12/24 01:22, Joel Brobecker wrote:
>>> With gdb 15.1, python sys.exit no longer makes gdb exit:
>>> ...
>>> $ gdb -q -batch -ex "python sys.exit(2)" -ex "print 123"; echo $?
>>> Python Exception <class 'SystemExit'>: 2
>>> Error occurred in Python: 2
>>> $1 = 123
>>> 0
>>> ...
>>>
>>> This is a change in behaviour since commit a207f6b3a38 ("Rewrite "python"
>>> command exception handling"), first available in gdb 15.1.
>>>
>>> The question is whether this is a regression.
> 
> I had a bit of a knee-jerk reaction at first, and thought perhaps
> we should perhaps provide an API for exiting GDB. Looking at
> the semantics of what sys.exit does, I eventually reached the same
> conclusion as Tom and Guinevere. It makes more sense to restore
> the previous behavior, and have GDB exit when a SystemExit exception
> is raised in the main thread, and unhandled.
> 

Hi,

thank you both for your reactions.

With two votes pointing in the same direction, I've dropped the RCF bit 
from the commit log and resubmitted here ( 
https://sourceware.org/pipermail/gdb-patches/2024-August/211022.html ).

Thanks,
- Tom

^ permalink raw reply	[flat|nested] 4+ messages in thread

end of thread, other threads:[~2024-08-13 11:04 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2024-07-27  9:48 [RFC] [gdb/python] Make sure python sys.exit makes gdb exit Tom de Vries
2024-07-30 18:53 ` Guinevere Larsen
2024-08-11 23:22   ` Joel Brobecker
2024-08-13 11:05     ` Tom de Vries

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).