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: Scan() appends data to RawBytes #65201
Comments
I believe this is working as intended: RawBytes documents: https://pkg.go.dev/database/sql#RawBytes
|
I don't think this is the intended behavior. The document says "RawBytes is a byte slice that holds a reference to memory owned by the database itself". And users don't know about this behavior. Stop appending to RawBytes saves users from this pitfall without any downside. |
CC @bradfitz @kardianos as owner. |
Not clear to me what's intended here, but the actual behavior is surprising and easy to misuse. Consider:
If the database driver provides a If the database driver provides some other type, The latter case says to me that the above loop is written as intended: We reuse the same Where things go wrong is if we make two queries with the same Perhaps this is user error, but the documentation doesn't make it clear that a One fix might be to drop the optimization for the second case and never write to the data contained within a Another might be to zero out any I suspect this behavior hasn't been noticed before now since it's unusual to reuse a single query variable for scanning two different columns of different types. |
Change https://go.dev/cl/557917 mentions this issue: |
ah, apologies i didn't understand before how the append was observed without api misuse. |
RawBytes has two usage (zero copy and reusing buffer). How to fix this?
|
But this makes allocation of |
I doubt that this optimization is important.
How do you think? @bradfitz. |
I was the original reporter of this problem, and I agree that this is an unintended and undocumented behavior. The documentation makes it sound like a RawBytes will always receive a buffer pointer. One that either points directly into the raw sql buffer, or a newly allocated buffer with the data. Overwriting the data that is currently in the buffer does not make sense and can be a security issue. There are 3 places in sql/convert.go that write into the buffer that RawBytes currently holds. These should instead create a new buffer and set that on the RawBytes. |
I was going to ask on the commit but you blocked me from commenting. Just a thought, but on line 240 of
|
I blocked comments on the commit because we don't use GitHub for code review. GitHub is a mirror, and almost nobody sees comments on a GitHub commit. Comments about commits should be on the change review, which in this case is https://go.dev/cl/557917. Thanks. |
To answer your question, we don't use unsafe unless there is a very significant benefit. And in this case I don't actually see any benefit at all; |
I understand. I was just thinking the RawBytes functionality, meant for speed optimization, in which read-only use-once buffers are returned, kind of matched a use case for returning the direct bytes of a string. Thanks for answering though. |
Go version
go1.22
Output of
go env
in your module/workspace:What did you do?
See go-sql-driver/mysql#1539
This is very complex to reproduce in real code because it is relating mysql protocol and go-mysql double buffering.
So I explain what is happening in this simple code and comments.
The place database/sql breaks the buffer is here.
go/src/database/sql/convert.go
Lines 367 to 370 in f19f31f
go/src/database/sql/convert.go
Lines 512 to 515 in f19f31f
What did you see happen?
Reusing RawBytes breaks internal buffer.
What did you expect to see?
Reusing RawBytes variable should be safe.
This is very hard to debug pitfall.
The text was updated successfully, but these errors were encountered: