Commit 539c5d9f767 for php.net

commit 539c5d9f767160c774d7dc31b7c57edf7ba7318f
Author: David Carlier <devnexen@gmail.com>
Date:   Sun Feb 8 15:05:03 2026 +0000

    Fix GH-21162: pg_connect() on error memory leak.

    The PHP_PQ_ERROR macro calls php_error_docref() which triggers user error handlers
    thus libpq does not have the chance to clean the resources (and empty
    connections string are allowed) on failure thus we avoid this macro
    and delay the error handling after.

    close GH-21165

diff --git a/NEWS b/NEWS
index 10a3dd00f2f..536eeafbb8b 100644
--- a/NEWS
+++ b/NEWS
@@ -34,6 +34,10 @@ PHP                                                                        NEWS
   . Fixed bug GH-21055 (connection attribute status typo for GSS negotiation).
     (lsaos)

+- PGSQL:
+  . Fixed bug GH-21162 (pg_connect() memory leak on error).
+    (David Carlier)
+
 - Sockets:
   . Fixed bug GH-21161 (socket_set_option() crash with array 'addr'
     entry as null). (David Carlier)
diff --git a/ext/pgsql/pgsql.c b/ext/pgsql/pgsql.c
index 80aacd5443e..99f2e3cf563 100644
--- a/ext/pgsql/pgsql.c
+++ b/ext/pgsql/pgsql.c
@@ -705,10 +705,12 @@ static void php_pgsql_do_connect(INTERNAL_FUNCTION_PARAMETERS, int persistent)
 			/* create the link */
 			pgsql = PQconnectdb(connstring);
 			if (pgsql == NULL || PQstatus(pgsql) == CONNECTION_BAD) {
-				PHP_PQ_ERROR("Unable to connect to PostgreSQL server: %s", pgsql)
+				zend_string *msgbuf = _php_pgsql_trim_message(PQerrorMessage(pgsql));
 				if (pgsql) {
 					PQfinish(pgsql);
 				}
+				php_error_docref(NULL, E_WARNING, "Unable to connect to PostgreSQL server: %s", ZSTR_VAL(msgbuf));
+				zend_string_release(msgbuf);
 				goto err;
 			}

@@ -789,19 +791,23 @@ static void php_pgsql_do_connect(INTERNAL_FUNCTION_PARAMETERS, int persistent)
 		if (connect_type & PGSQL_CONNECT_ASYNC) {
 			pgsql = PQconnectStart(connstring);
 			if (pgsql==NULL || PQstatus(pgsql)==CONNECTION_BAD) {
-				PHP_PQ_ERROR("Unable to connect to PostgreSQL server: %s", pgsql);
+				zend_string *msgbuf = _php_pgsql_trim_message(PQerrorMessage(pgsql));
 				if (pgsql) {
 					PQfinish(pgsql);
 				}
+				php_error_docref(NULL, E_WARNING, "Unable to connect to PostgreSQL server: %s", ZSTR_VAL(msgbuf));
+				zend_string_release(msgbuf);
 				goto err;
 			}
 		} else {
 			pgsql = PQconnectdb(connstring);
 			if (pgsql==NULL || PQstatus(pgsql)==CONNECTION_BAD) {
-				PHP_PQ_ERROR("Unable to connect to PostgreSQL server: %s", pgsql);
+				zend_string *msgbuf = _php_pgsql_trim_message(PQerrorMessage(pgsql));
 				if (pgsql) {
 					PQfinish(pgsql);
 				}
+				php_error_docref(NULL, E_WARNING, "Unable to connect to PostgreSQL server: %s", ZSTR_VAL(msgbuf));
+				zend_string_release(msgbuf);
 				goto err;
 			}
 		}
diff --git a/ext/pgsql/tests/gh21162.phpt b/ext/pgsql/tests/gh21162.phpt
new file mode 100644
index 00000000000..9f40ac1136d
--- /dev/null
+++ b/ext/pgsql/tests/gh21162.phpt
@@ -0,0 +1,18 @@
+--TEST--
+GH-21162 (pg_connect() on error memory leak)
+--EXTENSIONS--
+pgsql
+--FILE--
+<?php
+
+set_error_handler(function (int $errno, string $errstr) {
+    echo "Warning caught\n";
+});
+
+pg_connect('');
+
+echo "Done\n";
+?>
+--EXPECT--
+Warning caught
+Done