Skip to content

Commit 08707d6

Browse files
nklaassengopherbot
authored andcommitted
database/sql: fix panic with concurrent Conn and Close
The current implementation has a panic when the database is closed concurrently with a new connection attempt. connRequestSet.CloseAndRemoveAll sets connRequestSet.s to a nil slice. If this happens between calls to connRequestSet.Add and connRequestSet.Delete, there is a panic when trying to write to the nil slice. This is sequence is likely to occur in DB.conn, where the mutex is released between calls to db.connRequests.Add and db.connRequests.Delete This change updates connRequestSet.CloseAndRemoveAll to set the curIdx to -1 for all pending requests before setting its internal slice to nil. CloseAndRemoveAll already iterates the full slice to close all the request channels. It seems appropriate to set curIdx to -1 before deleting the slice for 3 reasons: 1. connRequestSet.deleteIndex also sets curIdx to -1 2. curIdx will not be relevant to anything after the slice is set to nil 3. connRequestSet.Delete already checks for negative indices Fixes #68949 Change-Id: I6b7ebc5a71b67322908271d13865fa12f2469b87 GitHub-Last-Rev: 7d26691 GitHub-Pull-Request: #68953 Reviewed-on: https://go-review.googlesource.com/c/go/+/607238 LUCI-TryBot-Result: Go LUCI <[email protected]> Auto-Submit: Ian Lance Taylor <[email protected]> Commit-Queue: Ian Lance Taylor <[email protected]> Reviewed-by: Brad Fitzpatrick <[email protected]> Reviewed-by: Cherry Mui <[email protected]> Reviewed-by: Dmitri Shuralyov <[email protected]>
1 parent 3b36d92 commit 08707d6

File tree

2 files changed

+14
-2
lines changed

2 files changed

+14
-2
lines changed

src/database/sql/sql.go

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1368,8 +1368,8 @@ func (db *DB) conn(ctx context.Context, strategy connReuseStrategy) (*driverConn
13681368

13691369
db.waitDuration.Add(int64(time.Since(waitStart)))
13701370

1371-
// If we failed to delete it, that means something else
1372-
// grabbed it and is about to send on it.
1371+
// If we failed to delete it, that means either the DB was closed or
1372+
// something else grabbed it and is about to send on it.
13731373
if !deleted {
13741374
// TODO(bradfitz): rather than this best effort select, we
13751375
// should probably start a goroutine to read from req. This best
@@ -3594,6 +3594,7 @@ type connRequestAndIndex struct {
35943594
// and clears the set.
35953595
func (s *connRequestSet) CloseAndRemoveAll() {
35963596
for _, v := range s.s {
3597+
*v.curIdx = -1
35973598
close(v.req)
35983599
}
35993600
s.s = nil

src/database/sql/sql_test.go

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4920,6 +4920,17 @@ func TestConnRequestSet(t *testing.T) {
49204920
t.Error("wasn't random")
49214921
}
49224922
})
4923+
t.Run("close-delete", func(t *testing.T) {
4924+
reset()
4925+
ch := make(chan connRequest)
4926+
dh := s.Add(ch)
4927+
wantLen(1)
4928+
s.CloseAndRemoveAll()
4929+
wantLen(0)
4930+
if s.Delete(dh) {
4931+
t.Error("unexpected delete after CloseAndRemoveAll")
4932+
}
4933+
})
49234934
}
49244935

49254936
func BenchmarkConnRequestSet(b *testing.B) {

0 commit comments

Comments
 (0)