do not bail out on finalize error in closeCachedStmtsLocked

Finalize all cached statements even if one fails. Leaving a
finalized statement in the cache map would be a use-after-finalize
bug per SQLite documentation.
This commit is contained in:
Yasuhiro Matsumoto
2026-04-08 13:40:21 +09:00
parent 325cb8d5d9
commit e9f47da5c5

View File

@@ -1884,9 +1884,7 @@ func (c *SQLiteConn) Close() error {
return nil return nil
} }
runtime.SetFinalizer(c, nil) runtime.SetFinalizer(c, nil)
if err := c.closeCachedStmtsLocked(); err != nil { c.closeCachedStmtsLocked()
return err
}
rv := C.sqlite3_close_v2(c.db) rv := C.sqlite3_close_v2(c.db)
if rv != C.SQLITE_OK { if rv != C.SQLITE_OK {
return lastError(c.db) return lastError(c.db)
@@ -1949,23 +1947,20 @@ func (c *SQLiteConn) putCachedStmt(s *SQLiteStmt) bool {
return true return true
} }
func (c *SQLiteConn) closeCachedStmtsLocked() error { func (c *SQLiteConn) closeCachedStmtsLocked() {
for key, stmts := range c.stmtCache { for key, stmts := range c.stmtCache {
for _, s := range stmts { for _, s := range stmts {
if s == nil || s.s == nil { if s == nil || s.s == nil {
continue continue
} }
runtime.SetFinalizer(s, nil) runtime.SetFinalizer(s, nil)
if rv := C.sqlite3_finalize(s.s); rv != C.SQLITE_OK { C.sqlite3_finalize(s.s)
return lastError(c.db)
}
s.s = nil s.s = nil
s.c = nil s.c = nil
} }
delete(c.stmtCache, key) delete(c.stmtCache, key)
} }
c.stmtCacheCount = 0 c.stmtCacheCount = 0
return nil
} }
// Prepare the query string. Return a new statement. // Prepare the query string. Return a new statement.