aboutsummaryrefslogtreecommitdiff
path: root/src/time/time_test.go
diff options
context:
space:
mode:
authorIan Lance Taylor <iant@golang.org>2018-06-01 10:16:08 -0700
committerIan Lance Taylor <iant@golang.org>2018-06-04 18:33:41 +0000
commitd6c3b0a56d8c81c221b0adf69ae351f7cd467854 (patch)
treeedea6fb95f6cc34504642db1920a627834455d90 /src/time/time_test.go
parentcf2c2ea89d09d486bb018b1817c5874388038c3a (diff)
downloadgo-d6c3b0a56d8c81c221b0adf69ae351f7cd467854.tar.gz
go-d6c3b0a56d8c81c221b0adf69ae351f7cd467854.zip
runtime: don't crash holding locks on racy timer access
If we run into data corruption due to the program accessing timers in a racy way, do a normal panic rather than a hard crash with "panic holding locks". The hope is to make the problem less confusing for users. Fixes #25686 Change-Id: I863417adf21f7f8c088675b67a3acf49a0cdef41 Reviewed-on: https://go-review.googlesource.com/115815 Reviewed-by: Austin Clements <austin@google.com>
Diffstat (limited to 'src/time/time_test.go')
-rw-r--r--src/time/time_test.go37
1 files changed, 37 insertions, 0 deletions
diff --git a/src/time/time_test.go b/src/time/time_test.go
index 7778bf1f83..432a67dec3 100644
--- a/src/time/time_test.go
+++ b/src/time/time_test.go
@@ -9,11 +9,13 @@ import (
"encoding/gob"
"encoding/json"
"fmt"
+ "internal/race"
"math/big"
"math/rand"
"os"
"runtime"
"strings"
+ "sync"
"testing"
"testing/quick"
. "time"
@@ -1341,3 +1343,38 @@ func TestReadFileLimit(t *testing.T) {
t.Errorf("readFile(%q) error = %v; want error containing 'is too large'", zero, err)
}
}
+
+// Issue 25686: hard crash on concurrent timer access.
+// This test deliberately invokes a race condition.
+// We are testing that we don't crash with "fatal error: panic holding locks".
+func TestConcurrentTimerReset(t *testing.T) {
+ if race.Enabled {
+ t.Skip("skipping test under race detector")
+ }
+
+ // We expect this code to panic rather than crash.
+ // Don't worry if it doesn't panic.
+ catch := func(i int) {
+ if e := recover(); e != nil {
+ t.Logf("panic in goroutine %d, as expected, with %q", i, e)
+ } else {
+ t.Logf("no panic in goroutine %d", i)
+ }
+ }
+
+ const goroutines = 8
+ const tries = 1000
+ var wg sync.WaitGroup
+ wg.Add(goroutines)
+ timer := NewTimer(Hour)
+ for i := 0; i < goroutines; i++ {
+ go func(i int) {
+ defer wg.Done()
+ defer catch(i)
+ for j := 0; j < tries; j++ {
+ timer.Reset(Hour + Duration(i*j))
+ }
+ }(i)
+ }
+ wg.Wait()
+}