@@ -6,7 +6,7 @@ package runtime_test
6
6
7
7
import (
8
8
"bytes"
9
- "context "
9
+ "flag "
10
10
"fmt"
11
11
"internal/testenv"
12
12
"os"
@@ -400,6 +400,15 @@ func TestGdbBacktrace(t *testing.T) {
400
400
if runtime .GOOS == "netbsd" {
401
401
testenv .SkipFlaky (t , 15603 )
402
402
}
403
+ if flag .Lookup ("test.parallel" ).Value .(flag.Getter ).Get ().(int ) < 2 {
404
+ // It is possible that this test will hang for a long time due to an
405
+ // apparent GDB bug reported in https://go.dev/issue/37405.
406
+ // If test parallelism is high enough, that might be ok: the other parallel
407
+ // tests will finish, and then this test will finish right before it would
408
+ // time out. However, if test are running sequentially, a hang in this test
409
+ // would likely cause the remaining tests to run out of time.
410
+ testenv .SkipFlaky (t , 37405 )
411
+ }
403
412
404
413
checkGdbEnvironment (t )
405
414
t .Parallel ()
@@ -421,6 +430,7 @@ func TestGdbBacktrace(t *testing.T) {
421
430
}
422
431
423
432
// Execute gdb commands.
433
+ start := time .Now ()
424
434
args := []string {"-nx" , "-batch" ,
425
435
"-iex" , "add-auto-load-safe-path " + filepath .Join (testenv .GOROOT (t ), "src" , "runtime" ),
426
436
"-ex" , "set startup-with-shell off" ,
@@ -430,9 +440,32 @@ func TestGdbBacktrace(t *testing.T) {
430
440
"-ex" , "continue" ,
431
441
filepath .Join (dir , "a.exe" ),
432
442
}
433
- ctx , cancel := context .WithTimeout (context .Background (), time .Minute )
434
- defer cancel ()
435
- got , err := testenv .CommandContext (t , ctx , "gdb" , args ... ).CombinedOutput ()
443
+ cmd = testenv .Command (t , "gdb" , args ... )
444
+
445
+ // Work around the GDB hang reported in https://go.dev/issue/37405.
446
+ // Sometimes (rarely), the GDB process hangs completely when the Go program
447
+ // exits, and we suspect that the bug is on the GDB side.
448
+ //
449
+ // The default Cancel function added by testenv.Command will mark the test as
450
+ // failed if it is in danger of timing out, but we want to instead mark it as
451
+ // skipped. Change the Cancel function to kill the process and merely log
452
+ // instead of failing the test.
453
+ //
454
+ // (This approach does not scale: if the test parallelism is less than or
455
+ // equal to the number of tests that run right up to the deadline, then the
456
+ // remaining parallel tests are likely to time out. But as long as it's just
457
+ // this one flaky test, it's probably fine..?)
458
+ //
459
+ // If there is no deadline set on the test at all, relying on the timeout set
460
+ // by testenv.Command will cause the test to hang indefinitely, but that's
461
+ // what “no deadline” means, after all — and it's probably the right behavior
462
+ // anyway if someone is trying to investigate and fix the GDB bug.
463
+ cmd .Cancel = func () error {
464
+ t .Logf ("GDB command timed out after %v: %v" , time .Since (start ), cmd )
465
+ return cmd .Process .Kill ()
466
+ }
467
+
468
+ got , err := cmd .CombinedOutput ()
436
469
t .Logf ("gdb output:\n %s" , got )
437
470
if err != nil {
438
471
if bytes .Contains (got , []byte ("internal-error: wait returned unexpected status 0x0" )) {
0 commit comments