From 9def857072bb708a79c291bb88c4b2830f0a8376 Mon Sep 17 00:00:00 2001 From: Daniel Theophanes Date: Mon, 26 Dec 2016 11:33:46 -0800 Subject: database/sql: prevent Tx.rollback from racing Tx.close Previously Tx.done was being set in close, but in a Tx rollback and Commit are the real closing methods, and Tx.close is just a helper common to both. Prior to this change a multiple rollback statements could be called, one would enter close and begin closing it while the other was still in rollback breaking it. Fix that by setting done in rollback and Commit, not in Tx.close. Fixes #18429 Change-Id: Ie274f60c2aa6a4a5aa38e55109c05ea9d4fe0223 Reviewed-on: https://go-review.googlesource.com/34716 Reviewed-by: Brad Fitzpatrick Run-TryBot: Brad Fitzpatrick TryBot-Result: Gobot Gobot --- src/database/sql/sql.go | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) (limited to 'src/database/sql/sql.go') diff --git a/src/database/sql/sql.go b/src/database/sql/sql.go index 960245065e..58e927e0c4 100644 --- a/src/database/sql/sql.go +++ b/src/database/sql/sql.go @@ -1421,10 +1421,9 @@ func (tx *Tx) isDone() bool { // that has already been committed or rolled back. var ErrTxDone = errors.New("sql: Transaction has already been committed or rolled back") +// close returns the connection to the pool and +// must only be called by Tx.rollback or Tx.Commit. func (tx *Tx) close(err error) { - if !atomic.CompareAndSwapInt32(&tx.done, 0, 1) { - panic("double close") // internal error - } tx.db.putConn(tx.dc, err) tx.cancel() tx.dc = nil @@ -1449,7 +1448,7 @@ func (tx *Tx) closePrepared() { // Commit commits the transaction. func (tx *Tx) Commit() error { - if tx.isDone() { + if !atomic.CompareAndSwapInt32(&tx.done, 0, 1) { return ErrTxDone } select { @@ -1471,7 +1470,7 @@ func (tx *Tx) Commit() error { // rollback aborts the transaction and optionally forces the pool to discard // the connection. func (tx *Tx) rollback(discardConn bool) error { - if tx.isDone() { + if !atomic.CompareAndSwapInt32(&tx.done, 0, 1) { return ErrTxDone } var err error -- cgit v1.3