diff --git a/NEWS b/NEWS index daf52ae14d95..cd9186e9cb2f 100644 --- a/NEWS +++ b/NEWS @@ -237,6 +237,11 @@ PHP NEWS . Fixed bug GH-25006 (getColumnMeta() reads out of bounds for an out-of-range column index). (Ilia Alshanetsky) +- PDO_PGSQL: + . Fixed a use-after-free when a persistent connection receives a notice + after the request that called Pdo\Pgsql::setNoticeCallback() has ended. + (Ilia Alshanetsky) + - PDO_SQLite: . Fixed bug GH-25021 (SQLite createFunction corrupts large integers). (mvorisek) diff --git a/ext/pdo_pgsql/pgsql_driver.c b/ext/pdo_pgsql/pgsql_driver.c index 0c6175d365de..ad5d7d60b960 100644 --- a/ext/pdo_pgsql/pgsql_driver.c +++ b/ext/pdo_pgsql/pgsql_driver.c @@ -1297,6 +1297,15 @@ static const zend_function_entry *pdo_pgsql_get_driver_methods(pdo_dbh_t *dbh, i } } +static void pdo_pgsql_request_shutdown(pdo_dbh_t *dbh) +{ + pdo_pgsql_db_handle *H = (pdo_pgsql_db_handle *)dbh->driver_data; + + if (H && dbh->refcount <= 2) { + pdo_pgsql_cleanup_notice_callback(H); + } +} + static bool pdo_pgsql_set_attr(pdo_dbh_t *dbh, zend_long attr, zval *val) { bool bval; @@ -1334,7 +1343,7 @@ static const struct pdo_dbh_methods pgsql_methods = { pdo_pgsql_get_attribute, pdo_pgsql_check_liveness, /* check_liveness */ pdo_pgsql_get_driver_methods, /* get_driver_methods */ - NULL, + pdo_pgsql_request_shutdown, pgsql_handle_in_transaction, NULL, /* get_gc */ pdo_pgsql_scanner diff --git a/ext/pdo_pgsql/tests/pdopgsql_setNoticeCallback_persistent.phpt b/ext/pdo_pgsql/tests/pdopgsql_setNoticeCallback_persistent.phpt new file mode 100644 index 000000000000..15c1d6d69432 --- /dev/null +++ b/ext/pdo_pgsql/tests/pdopgsql_setNoticeCallback_persistent.phpt @@ -0,0 +1,49 @@ +--TEST-- +Pdo\Pgsql::setNoticeCallback() does not outlive the request on a persistent connection +--EXTENSIONS-- +pdo +pdo_pgsql +--SKIPIF-- + +--CONFLICTS-- +server +--FILE-- + true]);' . <<<'PHP' +if (isset($_GET['set'])) { + $db->setNoticeCallback(function ($message) { + echo trim($message), "\n"; + }); +} +$db->exec("DO $$ BEGIN RAISE NOTICE 'request {$_GET['n']}'; END $$"); +echo "request {$_GET['n']} done\n"; +PHP; + +$args = ['-d', 'extension_dir=' . ini_get('extension_dir')]; +foreach (['pdo', 'pdo_pgsql'] as $ext) { + $args[] = '-d'; + $args[] = 'extension=' . (PHP_OS_FAMILY === 'Windows' ? 'php_' : '') . $ext . '.' . PHP_SHLIB_SUFFIX; +} +if (php_ini_loaded_file()) { + $args[] = '-c'; + $args[] = php_ini_loaded_file(); +} +php_cli_server_start($code, 'index.php', $args); + +echo file_get_contents('http://' . PHP_CLI_SERVER_ADDRESS . '/?n=1&set=1'); +echo file_get_contents('http://' . PHP_CLI_SERVER_ADDRESS . '/?n=2'); +echo file_get_contents('http://' . PHP_CLI_SERVER_ADDRESS . '/?n=3&set=1'); +?> +--EXPECT-- +NOTICE: request 1 +request 1 done +request 2 done +NOTICE: request 3 +request 3 done