Ensure that SqliteStmt.closed property is guarded.

Because the closed property of the SQLiteRows's *SqliteStmt
was not guarded, it was causing an issue during context
cancellation.

be424d27ac/sqlite3.go (L1785-L1796)

When a statement is performing a query(), if it determines that
the context has been canceled, it will launch a goroutine that
closes the resulting driver.Rows if it's not already completed.

If the driver.Rows is not done (and the context has been canceled),
it will interrupt the connection and more importantly, perform
a rows.Close(). The method rows.Close() guards the closed bool with
a sync.Mutex to set it to true.

If a reader is reading from the SqliteRow, it will call Next()
and that performs this check:

be424d27ac/sqlite3.go (L1915-L1917)

Because this is not guarded, a data race ensues, and this was
actually caught by the Go race detector recently.

I didn't include a test case here because the fix seemed
straightforward enough and because race conditions are hard
to test for.  It's been verified in another program that this
fixes the issue.  If tests should be provided I'm more than
happy to do so.
This commit is contained in:
Collin Van Dyck 2018-07-17 20:29:43 -04:00 committed by Gert-Jan Timmer
parent 3aefd9f0a1
commit b3511bfdd7
1 changed files with 2 additions and 2 deletions

View File

@ -1883,11 +1883,11 @@ func (rc *SQLiteRows) DeclTypes() []string {
// Next move cursor to next. // Next move cursor to next.
func (rc *SQLiteRows) Next(dest []driver.Value) error { func (rc *SQLiteRows) Next(dest []driver.Value) error {
rc.s.mu.Lock()
defer rc.s.mu.Unlock()
if rc.s.closed { if rc.s.closed {
return io.EOF return io.EOF
} }
rc.s.mu.Lock()
defer rc.s.mu.Unlock()
rv := C.sqlite3_step(rc.s.s) rv := C.sqlite3_step(rc.s.s)
if rv == C.SQLITE_DONE { if rv == C.SQLITE_DONE {
return io.EOF return io.EOF