[php-src] PHP-8.5: sqlite3: Fix leak when trying to close db if blob stream is still open

ndossche <[email protected]> Mon, 3 Aug 2026 20:56:03 +0000
Newsgroups gmane.comp.php.cvs.general
Message-ID <[email protected]>
Author: ndossche (ndossche)
Date: 2026-08-03T22:55:04+02:00

Commit: https://github.com/php/php-src/commit/eaac0378e3c2e16814f9aeef55a07c2418d6d27a
Raw diff: https://github.com/php/php-src/commit/eaac0378e3c2e16814f9aeef55a07c2418d6d27a.diff

sqlite3: Fix leak when trying to close db if blob stream is still open

Discovered coincidentally with ESSS [1], even though I was actually using
it for something else.

[1] https://github.com/csl-ugent/ESSS

Closes GH-22992.

Changed paths:
  A  ext/sqlite3/tests/sqlite3_close_blob_stream.phpt
  M  NEWS
  M  ext/sqlite3/sqlite3.c


Diff:

diff --git a/NEWS b/NEWS
index ee333ae9f20c..6738d104f5bc 100644
--- a/NEWS
+++ b/NEWS
@@ -18,6 +18,10 @@ PHP                                                                        NEWS
   . Fixed bug GH-21036 (mb_ereg_search_getregs() crashes after mb_eregi()
     invalidates the regex cache). (Matthias Goergens)
 
+- Opcache:
+  . Fixed bug GH-22857 (Function JIT emits wrong code for FETCH_OBJ_FUNC_ARG on a
+    property hook getter, losing register-held variables). (Zhao Hao)
+
 - PCRE:
   . Fixed bug GH-21134 (Crash with \C + UTF-8). Using \C in UTF-8 patterns is
     now forbidden. (Arnaud)
@@ -29,6 +33,9 @@ PHP                                                                        NEWS
 - Sockets:
   . Fixed various memory related issues in ext/sockets. (David Carlier)
 
+- SQLite:
+  . Fix leak when trying to close db if blob stream is still open. (ndossche)
+
 - Streams:
   . Fixed bug GH-15836 (Use-after-free when a user stream filter accesses
     $this->stream during the close flush). (iliaal)
@@ -37,10 +44,6 @@ PHP                                                                        NEWS
   . Fixed out-of-bounds write when shm_attach() opens an existing segment with
     a size larger than the segment actually is. (David Carlier)
 
-- Opcache:
-  . Fixed bug GH-22857 (Function JIT emits wrong code for FETCH_OBJ_FUNC_ARG on a
-    property hook getter, losing register-held variables). (Zhao Hao)
-
 30 Jul 2026, PHP 8.4.24
 
 - BCMath:
diff --git a/ext/sqlite3/sqlite3.c b/ext/sqlite3/sqlite3.c
index 1bb93e0e2675..20714c38aada 100644
--- a/ext/sqlite3/sqlite3.c
+++ b/ext/sqlite3/sqlite3.c
@@ -2255,7 +2255,9 @@ static void php_sqlite3_object_free_storage(zend_object *object) /* {{{ */
 	}
 
 	if (intern->initialised && intern->db) {
-		sqlite3_close(intern->db);
+		/* Use sqlite3_close_v2() because the object may be destroyed while resources depending on the connection are still alive,
+		 * e.g. a blob stream created by SQLite3::openBlob(). */
+		sqlite3_close_v2(intern->db);
 		intern->initialised = 0;
 	}
 
diff --git a/ext/sqlite3/tests/sqlite3_close_blob_stream.phpt b/ext/sqlite3/tests/sqlite3_close_blob_stream.phpt
new file mode 100644
index 000000000000..d2426445a7cd
--- /dev/null
+++ b/ext/sqlite3/tests/sqlite3_close_blob_stream.phpt
@@ -0,0 +1,22 @@
+--TEST--
+Destroying the SQLite3 object while a blob stream is still open must not leak the connection
+--EXTENSIONS--
+sqlite3
+--FILE--
+<?php
+
+$db = new SQLite3(':memory:');
+$db->exec('CREATE TABLE test (data BLOB)');
+$db->exec("INSERT INTO test (data) VALUES (x'34323432')");
+
+$stream = $db->openBlob('test', 'data', 1);
+var_dump($db->close());
+unset($db);
+var_dump(fread($stream, 4));
+fclose($stream);
+
+?>
+--EXPECTF--
+Warning: SQLite3::close(): Unable to close database: %s in %s on line %d
+bool(false)
+string(4) "4242"