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

Pedro Alves
2017-12-03T15:24:53Z

On 11/23/2017 07:51 PM, Sergio Durigan Junior wrote:
> 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 ;-)

:-)

I was going to push this as is, but I noticed that when
testing against --target_board=native-gdbserver, sometimes
I'd see this:

ERROR: Process no longer exists
ERROR: : spawn id exp9 not open
while executing
"expect {
-i exp8 -timeout 220
-i $server_spawn_id
eof {
pass $test
wait -i $server_spawn_id
unset server_spawn_id
}
timeout {
..."
("uplevel" body line 1)
invoked from within
"uplevel $body" NONE : spawn id exp9 not open

The problem is that:

- inferior_spawn_id and server_spawn_id are the same when testing
with gdbserver.
- gdbserver exits after "detach", so we get an eof for
$inferior_spawn_id in the loop in detach_and_expect_exit.
That's the first "ERROR: Process no longer exists".
- and then when we reach test_server_exit, server_spawn_id
is already closed (because server_spawn_id==inferior_spawn_id).

To handle this, I'm making the loop in detach_and_expect_exit
use an indirect spawn id list and remove $inferior_spawn_id from
the list as soon as we got the inferior output we're expecting,
so that the "eof" is left unprocessed until we reach test_server_exit.

I'm squashing in the patch below.

From 75f48083daa998603438e71436e7268fc53aa978 Mon Sep 17 00:00:00 2001
From: Pedro Alves <palves@redhat.com>
Date: Sun, 3 Dec 2017 00:14:15 +0000
Subject: [PATCH] fix gdbserver target remote

---
gdb/testsuite/gdb.threads/process-dies-while-detaching.exp | 12 +++++++++++-
1 file changed, 11 insertions(+), 1 deletion(-)

diff --git a/gdb/testsuite/gdb.threads/process-dies-while-detaching.exp b/gdb/testsuite/gdb.threads/process-dies-while-detaching.exp
index ea8f6e9..910e786 100644
--- a/gdb/testsuite/gdb.threads/process-dies-while-detaching.exp
+++ b/gdb/testsuite/gdb.threads/process-dies-while-detaching.exp
@@ -86,6 +86,14 @@ proc detach_and_expect_exit {inf_output_re test} {
}
}]

+ # Use an indirect spawn id list, and remove inferior spawn id from
+ # the expected output as soon as it matches, so that if
+ # $inf_inferior_spawn_id is $server_spawn_id and we're testing in
+ # "target remote" mode, the eof caused by gdbserver exiting is
+ # left for the caller to handle.
+ global daee_spawn_id_list
+ set daee_spawn_id_list "$inferior_spawn_id $gdb_spawn_id"
+
set saw_prompt 0
set saw_inf_exit 0
while { !$saw_prompt || ! $saw_inf_exit } {
@@ -96,14 +104,16 @@ proc detach_and_expect_exit {inf_output_re test} {
# first in the script that occurs anywhere in the input, so that
# we don't skip anything.
return_if_fail [gdb_test_multiple "" $test {
- -i "$inferior_spawn_id $gdb_spawn_id"
+ -i daee_spawn_id_list
-re "($inf_output_re)|($gdb_prompt )" {
if {[info exists expect_out(1,string)]} {
verbose -log "saw inferior exit"
set saw_inf_exit 1
+ set daee_spawn_id_list "$gdb_spawn_id"
} elseif {[info exists expect_out(2,string)]} {
verbose -log "saw prompt"
set saw_prompt 1
+ set daee_spawn_id_list "$inferior_spawn_id"
}
array unset expect_out
}
--
2.5.5