-
Notifications
You must be signed in to change notification settings - Fork 17.7k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
database/sql: sql.RawBytes is not compatible with contexts #60304
Comments
Looks like this is a duplicate of #53970, although we didn't realize the severity of that one when it came in. |
Closed #53970 as a duplicate of this one, because this one is the better presentation. |
Of the three options, the atomic bool and delayed driver close seems like the right fix. /cc @kardianos |
@gopherbot please backport Go 1.20 and Go 1.19 |
Backport issue(s) opened: #60307 (for 1.19), #60308 (for 1.20). Remember to create the cherry-pick CL(s) as soon as the patch is submitted to master, according to https://go.dev/wiki/MinorReleases. |
The MySQL driver solution was to switch buffers if an error/cancellation happened. |
Even though it's old, it causes data corruption in code that looks perfectly innocent (and arguably is innocent). |
Change https://go.dev/cl/497675 mentions this issue: |
sql.RawBytes was added the very first Go release, Go 1. Its docs say: > RawBytes is a byte slice that holds a reference to memory owned by > the database itself. After a Scan into a RawBytes, the slice is only > valid until the next call to Next, Scan, or Close. That "only valid until the next call" bit was true at the time, until contexts were added to database/sql in Go 1.8. In the past ~dozen releases it's been unsafe to use QueryContext with a context that might become Done to get an *sql.Rows that's scanning into a RawBytes. The Scan can succeed, but then while the caller's reading the memory, a database/sql-managed goroutine can see the context becoming done and call Close on the database/sql/driver and make the caller's view of the RawBytes memory no longer valid, introducing races, crashes, or database corruption. See #60304 and #53970 for details. This change does the minimal surgery on database/sql to make it safe again: Rows.Scan was already acquiring a mutex to check whether the rows had been closed, so this change make Rows.Scan notice whether *RawBytes was used and, if so, doesn't release the mutex on exit before returning. That mean it's still locked while the user code operates on the RawBytes memory and the concurrent context-watching goroutine to close the database still runs, but if it fires, it then gets blocked on the mutex until the next call to a Rows method (Next, NextResultSet, Err, Close). Updates #60304 Updates #53970 (earlier one I'd missed) Change-Id: Ie41c0c6f32c24887b2f53ec3686c2aab73a1bfff Reviewed-on: https://go-review.googlesource.com/c/go/+/497675 TryBot-Result: Gopher Robot <[email protected]> Reviewed-by: Ian Lance Taylor <[email protected]> Run-TryBot: Brad Fitzpatrick <[email protected]> Auto-Submit: Ian Lance Taylor <[email protected]> Reviewed-by: Russ Cox <[email protected]>
@bradfitz seems like the CL above fixed this? Should we close? |
sql.RawBytes was added the very first Go release, Go 1. Its docs say: > RawBytes is a byte slice that holds a reference to memory owned by > the database itself. After a Scan into a RawBytes, the slice is only > valid until the next call to Next, Scan, or Close. That "only valid until the next call" bit was true at the time, until contexts were added to database/sql in Go 1.8. In the past ~dozen releases it's been unsafe to use QueryContext with a context that might become Done to get an *sql.Rows that's scanning into a RawBytes. The Scan can succeed, but then while the caller's reading the memory, a database/sql-managed goroutine can see the context becoming done and call Close on the database/sql/driver and make the caller's view of the RawBytes memory no longer valid, introducing races, crashes, or database corruption. See golang#60304 and golang#53970 for details. This change does the minimal surgery on database/sql to make it safe again: Rows.Scan was already acquiring a mutex to check whether the rows had been closed, so this change make Rows.Scan notice whether *RawBytes was used and, if so, doesn't release the mutex on exit before returning. That mean it's still locked while the user code operates on the RawBytes memory and the concurrent context-watching goroutine to close the database still runs, but if it fires, it then gets blocked on the mutex until the next call to a Rows method (Next, NextResultSet, Err, Close). Updates golang#60304 Updates golang#53970 (earlier one I'd missed) Change-Id: Ie41c0c6f32c24887b2f53ec3686c2aab73a1bfff Reviewed-on: https://go-review.googlesource.com/c/go/+/497675 TryBot-Result: Gopher Robot <[email protected]> Reviewed-by: Ian Lance Taylor <[email protected]> Run-TryBot: Brad Fitzpatrick <[email protected]> Auto-Submit: Ian Lance Taylor <[email protected]> Reviewed-by: Russ Cox <[email protected]>
sql.RawBytes was added the very first Go release, Go 1. Its docs say: > RawBytes is a byte slice that holds a reference to memory owned by > the database itself. After a Scan into a RawBytes, the slice is only > valid until the next call to Next, Scan, or Close. That "only valid until the next call" bit was true at the time, until contexts were added to database/sql in Go 1.8. In the past ~dozen releases it's been unsafe to use QueryContext with a context that might become Done to get an *sql.Rows that's scanning into a RawBytes. The Scan can succeed, but then while the caller's reading the memory, a database/sql-managed goroutine can see the context becoming done and call Close on the database/sql/driver and make the caller's view of the RawBytes memory no longer valid, introducing races, crashes, or database corruption. See golang#60304 and golang#53970 for details. This change does the minimal surgery on database/sql to make it safe again: Rows.Scan was already acquiring a mutex to check whether the rows had been closed, so this change make Rows.Scan notice whether *RawBytes was used and, if so, doesn't release the mutex on exit before returning. That mean it's still locked while the user code operates on the RawBytes memory and the concurrent context-watching goroutine to close the database still runs, but if it fires, it then gets blocked on the mutex until the next call to a Rows method (Next, NextResultSet, Err, Close). Updates golang#60304 Updates golang#53970 (earlier one I'd missed) Change-Id: Ie41c0c6f32c24887b2f53ec3686c2aab73a1bfff Reviewed-on: https://go-review.googlesource.com/c/go/+/497675 TryBot-Result: Gopher Robot <[email protected]> Reviewed-by: Ian Lance Taylor <[email protected]> Run-TryBot: Brad Fitzpatrick <[email protected]> Auto-Submit: Ian Lance Taylor <[email protected]> Reviewed-by: Russ Cox <[email protected]>
sql.RawBytes was added the very first Go release, Go 1. Its docs say: > RawBytes is a byte slice that holds a reference to memory owned by > the database itself. After a Scan into a RawBytes, the slice is only > valid until the next call to Next, Scan, or Close. That "only valid until the next call" bit was true at the time, until contexts were added to database/sql in Go 1.8. In the past ~dozen releases it's been unsafe to use QueryContext with a context that might become Done to get an *sql.Rows that's scanning into a RawBytes. The Scan can succeed, but then while the caller's reading the memory, a database/sql-managed goroutine can see the context becoming done and call Close on the database/sql/driver and make the caller's view of the RawBytes memory no longer valid, introducing races, crashes, or database corruption. See golang#60304 and golang#53970 for details. This change does the minimal surgery on database/sql to make it safe again: Rows.Scan was already acquiring a mutex to check whether the rows had been closed, so this change make Rows.Scan notice whether *RawBytes was used and, if so, doesn't release the mutex on exit before returning. That mean it's still locked while the user code operates on the RawBytes memory and the concurrent context-watching goroutine to close the database still runs, but if it fires, it then gets blocked on the mutex until the next call to a Rows method (Next, NextResultSet, Err, Close). Updates golang#60304 Updates golang#53970 (earlier one I'd missed) Change-Id: Ie41c0c6f32c24887b2f53ec3686c2aab73a1bfff Reviewed-on: https://go-review.googlesource.com/c/go/+/497675 TryBot-Result: Gopher Robot <[email protected]> Reviewed-by: Ian Lance Taylor <[email protected]> Run-TryBot: Brad Fitzpatrick <[email protected]> Auto-Submit: Ian Lance Taylor <[email protected]> Reviewed-by: Russ Cox <[email protected]>
Change https://go.dev/cl/498398 mentions this issue: |
The earlier CL 497675 for golang#60304 introduced a behavior change that, while not strictly a bug, caused a bunch of test failures in a large codebase. Rather than add behavior changes in a 10 year old package, revert to the old behavior: a context cancelation between Rows.Next reporting false and a call to Rows.Err should not result in Rows.Err returning the context error. That behavior was accidentally added in CL 497675 as part of changing how contexts and Rows iteration worked. Updates golang#60304 Updates golang#53970 Change-Id: I22f8a6a6b0b5a94b430576cf50e015efd01ec652
The earlier CL 497675 for #60304 introduced a behavior change that, while not strictly a bug, caused a bunch of test failures in a large codebase. Rather than add behavior changes in a 10 year old package, revert to the old behavior: a context cancelation between Rows.Next reporting false and a call to Rows.Err should not result in Rows.Err returning the context error. That behavior was accidentally added in CL 497675 as part of changing how contexts and Rows iteration worked. Updates #60304 Updates #53970 Change-Id: I22f8a6a6b0b5a94b430576cf50e015efd01ec652 Reviewed-on: https://go-review.googlesource.com/c/go/+/498398 Run-TryBot: Brad Fitzpatrick <[email protected]> Reviewed-by: Russ Cox <[email protected]> Reviewed-by: Ian Lance Taylor <[email protected]> TryBot-Result: Gopher Robot <[email protected]>
Is there anything else left to do for this issue? |
All set. |
… drivers Previously we allowed drivers to modify the row buffer used to scan values when closing Rows. This is no longer acceptable and can lead to data races. Fixes #23519 Change-Id: I91820a6266ffe52f95f40bb47307d375727715af Reviewed-on: https://go-review.googlesource.com/89936 Run-TryBot: Daniel Theophanes <[email protected]> TryBot-Result: Gobot Gobot <[email protected]> Reviewed-by: Russ Cox <[email protected]>
sql.RawBytes
says:That was true when
RawBytes
was added (in the first Go release, Go 1(.0)), but Go 1.8 addedcontext.Context
support to thedatabase/sql
package.Since that time,
RawBytes
has been unsafe to use with anyBeginTx
/QueryContext
with a context that might be done, as internally thedatabase/sql
package starts a goroutine (awaitDone
) waiting for the context(s) to be done and then callsClose
on thedatabase/sql/driver.Conn
, concurrently with the caller working with RawBytes.Consider this series of events:
Options:
RawBytes
can't be used with a context that might be DoneconvertAssignRows
clone the driver's[]byte
memory when a vulnerable context is in useRows.Next
/Rows.Close
/Rows.Err
/etc.... something that the user did explicitly, rather than doing something concurrently with the user code working with theRawBytes
.What version of Go are you using (
go version
)?Go 1.20, but happens starting with Go 1.8 probably (not verified)
Does this issue reproduce with the latest release?
Yes.
What operating system and processor architecture are you using (
go env
)?macOS, Linux, etc. Not platform-specific.
The text was updated successfully, but these errors were encountered: