Open sharwell opened 3 years ago
That's interesting. Thanks for the info.
Just curious -- did you find this issue because some problem showed up in the wild? Or did you notice it on code review?
We found this issue during our work to update dotnet/roslyn from v1 to v2.
Thinking more about this.
Issues like this one make me wonder if it was a mistake to migrate these types to use SafeHandle.
The goal of the lowest layer of SQLitePCLRaw is, as much as possible, to present the exact same semantics as the SQLite C API.
For example, in the SQLite C API, it is illegal to close a sqlite3 if it still has sqlite3_stmt instances open. Nothing ever calls sqlite3_close() automatically, and there is certainly no way to have sqlite3_close() find all sqlite3_stmts that are open and close them down first.
Right now I'm wondering if it would have been better if I had one layer that exactly matched the SQLite C API and everything related to SafeHandle and finalizers was one layer about that.
Still thinking...
Document that sqlite3 is allowed to be disposed before sqlite3_blob
I wonder how credible it would be for me to argue that this documentation is already present and exists here:
@ericsink I believe that is a reasonable claim to make. The only remaining question is whether the sqlite3_blob
is usable while the connection is in the zombie state.
Please let me know if you think the issue I am describing is not related, I will file a new one, but it's also related to SafeHandle
.
I was looking at a PerfView trace for an application using sqlite and the GC stats show a lot of finalized objects:
SQLitePCL.hook_handle | 12434 |
---|
This happens if the object's finalizer is called, and it's not expected if it implements IDisposable
since it should call GC.SuppressFinalize()
in that case. It happens that hook_handle
inherits from SafeHandle
which correctly invokes GC.SuppressFinalize()
, so it leads me to think that some instances of hook_handle
are not correctly disposed.
@sebastienros That's a separate issue. hook_handle.ForDispose()
prevents instances created to represent null from getting disposed. The solution is to delete hook_handle.ForDispose()
since it's unnecessary (disposing of a null/invalid SafeHandle
is not only fine; it's expected).
The
sqlite3_blob
implementation does not ensure it is released prior to the owningsqlite3
object. One of the following is needed:sqlite3
is allowed to be disposed beforesqlite3_blob
(and more specifically,internal_sqlite3_close_v2
is allowed to be caled beforeinternal_sqlite3_blob_close
).sqlite3_blob
to lease thesqlite3
handle, which guarantees the finalization order. An example of this behavior using the v1 API is available inSafeSqliteBlobHandle
.Without the above, the new
SafeHandle
implementations are not directly usable, and must be wrapped in a second layer of safe handles to provide the ordering guarantees.This issue applies to
sqlite3_stmt
(which dotnet/roslyn uses), and may apply to other types as well (not used by dotnet/roslyn). Please feel free to let me know if you have any questions and/or to mention me on a review.