diff --git a/NEWS b/NEWS index 12d15e699f1f..6794dbe0a246 100644 --- a/NEWS +++ b/NEWS @@ -89,6 +89,9 @@ PHP NEWS (Ilia Alshanetsky) . Fixed a duplicate warning when ATTR_STATEMENT_CLASS is rejected on a persistent connection. (Ilia Alshanetsky) + . Fixed crash when the garbage collector freed SQLite user functions, + aggregates, or collations of a persistent connection shared by several + PDO objects. (Ilia Alshanetsky) - Phpdbg: . Fix wrong command names. (ndossche, Weilin Du) diff --git a/ext/pdo/pdo_dbh.c b/ext/pdo/pdo_dbh.c index 804cbb644077..05ac39bb2838 100644 --- a/ext/pdo/pdo_dbh.c +++ b/ext/pdo/pdo_dbh.c @@ -1443,7 +1443,8 @@ static HashTable *dbh_get_gc(zend_object *object, zval **gc_data, int *gc_count) pdo_dbh_t *dbh = php_pdo_dbh_fetch_inner(object); zend_get_gc_buffer *gc_buffer = zend_get_gc_buffer_create(); zend_get_gc_buffer_add_zval(gc_buffer, &dbh->def_stmt_ctor_args); - if (dbh->methods && dbh->methods->get_gc) { + if (dbh->methods && dbh->methods->get_gc + && (!dbh->is_persistent || dbh->refcount <= 2)) { dbh->methods->get_gc(dbh, gc_buffer); } zend_get_gc_buffer_use(gc_buffer, gc_data, gc_count); diff --git a/ext/pdo_sqlite/tests/gc_persistent_shared.phpt b/ext/pdo_sqlite/tests/gc_persistent_shared.phpt new file mode 100644 index 000000000000..21854b94b07c --- /dev/null +++ b/ext/pdo_sqlite/tests/gc_persistent_shared.phpt @@ -0,0 +1,30 @@ +--TEST-- +GC must not free callbacks of a persistent connection shared by several PDO objects +--EXTENSIONS-- +pdo_sqlite +--FILE-- +pdo = Pdo\Sqlite::connect('sqlite::memory:', null, null, [PDO::ATTR_PERSISTENT => true]); + $this->pdo->createFunction("udf_$name", [$this, 'udf'], 1); + } + + public function udf($x) { + return $this->name . $x; + } +} + +$repos = [new Repo('one'), new Repo('two')]; +echo "collected: "; var_dump(gc_collect_cycles()); +echo "udf_one: "; var_dump($repos[0]->pdo->query("SELECT udf_one('!')")->fetchColumn()); +echo "udf_two: "; var_dump($repos[1]->pdo->query("SELECT udf_two('?')")->fetchColumn()); + +unset($repos[0]->pdo, $repos[1]->pdo); +?> +--EXPECT-- +collected: int(0) +udf_one: string(4) "one!" +udf_two: string(4) "two?"