Re: [PATCH] Fix gdb.threads/process-dies-while-detaching.exp

Sergio Durigan Junior
2017-11-23T19:51:25Z

On Friday, November 17 2017, Pedro Alves wrote:

> I noticed [1] a test bug in gdb.threads/process-dies-while-detaching.exp.
> Simplified, the test code in question looks somewhat like this:
>
> ~~~
> # Detach from a process, and ensure that it exits after detaching.
> # This relies on inferior I/O.
>
> proc detach_and_expect_exit {test} {
>
> gdb_test_multiple "detach" $test ....
>
> set saw_prompt 0
> set saw_inf_exit 0
> while { !$saw_prompt && !$saw_inf_exit } {
> gdb_test_multiple "" $test {
> -re "exited, status=0" {
> set saw_inf_exit 1
> }
> -re "$gdb_prompt " {
> set saw_prompt 1
> }
> }
> }
>
> pass $test
> }
> ~~~
>
> The bug is in the while loop's condition. We want to make sure we see
> both the inferior output and the prompt, so the loop's test should be:
>
> - while { !$saw_prompt && !$saw_inf_exit } {
> + while { !$saw_prompt || !$saw_inf_exit } {
>
> If we just fix that, the test starts failing though, because that
> exposes a latent problem -- when called from
> test_detach_killed_outside, the parent doesn't print "exited,
> status=0", because in that case the child dies with a signal, and so
> detach_and_expect_exit times out. Fix it by making the parent print
> "signaled, sig=9" in that case, and have the .exp expect it.
>
> [1] I changed GDB in a way that should have made the test fail, but it
> didn't.

I skimmed over the patch and it looks good to me, but you're the expert
in this area here so I trust your judgement more than mine ;-).

> gdb/ChangeLog:
> yyyy-mm-dd Pedro Alves <palves@redhat.com>
>
> * gdb.threads/process-dies-while-detaching.c: Include <errno.h>
> and <string.h>.
> (parent_function): Print distinct messages when waitpid fails, or
> the child exits with a signal, or the child exits for an unhandled
> reason.
> * gdb.threads/process-dies-while-detaching.exp
> (detach_and_expect_exit): New 'inf_output_re' parameter and use
> it. Wait for both inferior output and GDB's prompt.
> (do_detach): New parameter 'child_exit'. Use it to compute
> expected inferior output.
> (test_detach, test_detach_watch, test_detach_killed_outside):
> Adjust to pass down the expected child exit kind.
> ---
> .../gdb.threads/process-dies-while-detaching.c | 22 +++++++++--
> .../gdb.threads/process-dies-while-detaching.exp | 43 +++++++++++++---------
> 2 files changed, 44 insertions(+), 21 deletions(-)
>
> diff --git a/gdb/testsuite/gdb.threads/process-dies-while-detaching.c b/gdb/testsuite/gdb.threads/process-dies-while-detaching.c
> index eecaaed..4ba50d4 100644
> --- a/gdb/testsuite/gdb.threads/process-dies-while-detaching.c
> +++ b/gdb/testsuite/gdb.threads/process-dies-while-detaching.c
> @@ -22,6 +22,8 @@
> #include <sys/types.h>
> #include <sys/wait.h>
> #include <assert.h>
> +#include <errno.h>
> +#include <string.h>
>
> /* This barrier ensures we only reach the initial breakpoint after all
> threads have started. */
> @@ -78,15 +80,27 @@ parent_function (pid_t child)
> alarm (300);
>
> ret = waitpid (child, &status, 0);
> +
> if (ret == -1)
> - exit (1);
> - else if (!WIFEXITED (status))
> - exit (2);
> - else
> + {
> + printf ("waitpid, errno=%d (%s)\n", errno, strerror (errno));
> + exit (1);
> + }
> + else if (WIFEXITED (status))
> {
> printf ("exited, status=%d\n", WEXITSTATUS (status));
> exit (0);
> }
> + else if (WIFSIGNALED (status))
> + {
> + printf ("signaled, sig=%d\n", WTERMSIG (status));
> + exit (2);
> + }
> + else
> + {
> + printf ("unexpected, status=%x\n", status);
> + exit (3);
> + }
> }
>
> #endif
> diff --git a/gdb/testsuite/gdb.threads/process-dies-while-detaching.exp b/gdb/testsuite/gdb.threads/process-dies-while-detaching.exp
> index 4cba80c..ea8f6e9 100644
> --- a/gdb/testsuite/gdb.threads/process-dies-while-detaching.exp
> +++ b/gdb/testsuite/gdb.threads/process-dies-while-detaching.exp
> @@ -72,9 +72,10 @@ proc return_if_fail { result } {
> }
>
> # Detach from a process, and ensure that it exits after detaching.
> -# This relies on inferior I/O.
> +# This relies on inferior I/O. INF_OUTPUT_RE is the pattern that
> +# matches the expected inferior output.
>
> -proc detach_and_expect_exit {test} {
> +proc detach_and_expect_exit {inf_output_re test} {
> global decimal
> global gdb_spawn_id
> global inferior_spawn_id
> @@ -87,7 +88,7 @@ proc detach_and_expect_exit {test} {
>
> set saw_prompt 0
> set saw_inf_exit 0
> - while { !$saw_prompt && ! $saw_inf_exit } {
> + while { !$saw_prompt || ! $saw_inf_exit } {
> # We don't know what order the interesting things will arrive in.
> # Using a pattern of the form 'x|y|z' instead of -re x ... -re y
> # ... -re z ensures that expect always chooses the match that
> @@ -96,7 +97,7 @@ proc detach_and_expect_exit {test} {
> # we don't skip anything.
> return_if_fail [gdb_test_multiple "" $test {
> -i "$inferior_spawn_id $gdb_spawn_id"
> - -re "(exited, status=0)|($gdb_prompt )" {
> + -re "($inf_output_re)|($gdb_prompt )" {
> if {[info exists expect_out(1,string)]} {
> verbose -log "saw inferior exit"
> set saw_inf_exit 1
> @@ -130,15 +131,28 @@ proc continue_to_exit_bp {} {
> #
> # CMD indicates what to do with the parent after detaching the child.
> # Can be either "detach" to detach, or "continue", to continue to
> -# exit. If "continue", then CONTINUE_RE is the regexp to expect.
> -# Defaults to normal exit output.
> +# exit.
> #
> -proc do_detach {multi_process cmd {continue_re ""}} {
> +# CHILD_EXIT indicates how is the child expected to exit. Can be
> +# either "normal" for normal exit, or "signal" for killed with signal
> +# SIGKILL.
> +#
> +proc do_detach {multi_process cmd child_exit} {
> global decimal
> global server_spawn_id
>
> - if {$continue_re == ""} {
> + if {$child_exit == "normal"} {
> set continue_re "exited normally.*"
> + set inf_output_re "exited, status=0"
> + } elseif {$child_exit == "signal"} {
> + if {$multi_process} {
> + set continue_re "exited with code 02.*"
> + } else {
> + set continue_re "terminated with signal SIGKILL.*"
> + }
> + set inf_output_re "signaled, sig=9"
> + } else {
> + error "unhandled \$child_exit: $child_exit"
> }
>
> set is_remote [expr {[target_info exists gdb_protocol]
> @@ -154,7 +168,7 @@ proc do_detach {multi_process cmd {continue_re ""}} {
> if {$cmd == "detach"} {
> # Make sure that detach works and that the parent process
> # exits cleanly.
> - detach_and_expect_exit "detach parent"
> + detach_and_expect_exit $inf_output_re "detach parent"
> } elseif {$cmd == "continue"} {
> # Make sure that continuing works and that the parent process
> # exits cleanly.
> @@ -205,7 +219,7 @@ proc test_detach {multi_process cmd} {
> # Run to _exit in the child.
> continue_to_exit_bp
>
> - do_detach $multi_process $cmd
> + do_detach $multi_process $cmd "normal"
> }
> }
>
> @@ -240,7 +254,7 @@ proc test_detach_watch {multi_process cmd} {
> # thread individually).
> continue_to_exit_bp
>
> - do_detach $multi_process $cmd
> + do_detach $multi_process $cmd "normal"
> }
> }
>
> @@ -279,12 +293,7 @@ proc test_detach_killed_outside {multi_process cmd} {
> # Give it some time to die.
> sleep 2
>
> - if {$multi_process} {
> - set continue_re "exited with code 02.*"
> - } else {
> - set continue_re "terminated with signal SIGKILL.*"
> - }
> - do_detach $multi_process $cmd $continue_re
> + do_detach $multi_process $cmd "signal"
> }
> }
>
> --
> 2.5.5

--
Sergio
GPG key ID: 237A 54B1 0287 28BF 00EF 31F4 D0EB 7628 65FC 5E36
Please send encrypted e-mail if possible