Commit b156471a30f for php.net

commit b156471a30f92008214d07af51f30151583fbe4a
Author: David Carlier <devnexen@gmail.com>
Date:   Sat Jan 24 14:49:10 2026 +0000

    Fix GH-21023: CURLOPT_XFERINFOFUNCTION with invalid callback crash.

    we check the FCC is properly initialised beforehand in its handler.

    close GH-21025

diff --git a/NEWS b/NEWS
index 59d35b5df94..dbac366b38a 100644
--- a/NEWS
+++ b/NEWS
@@ -5,6 +5,10 @@ PHP                                                                        NEWS
 - Core:
   . Fixed bug GH-21029 (zend_mm_heap corrupted on Aarch64, LTO builds). (Arnaud)

+- Curl:
+  . Fixed bug GH-21023 (CURLOPT_XFERINFOFUNCTION crash with a null callback).
+    (David Carlier)
+
 - PDO_PGSQL:
   . Fixed bug GH-21055 (connection attribute status typo for GSS negotiation).
     (lsaos)
diff --git a/ext/curl/interface.c b/ext/curl/interface.c
index db249eee057..12db566c089 100644
--- a/ext/curl/interface.c
+++ b/ext/curl/interface.c
@@ -621,6 +621,10 @@ static int curl_fnmatch(void *ctx, const char *pattern, const char *string)
 	zval argv[3];
 	zval retval;

+	if (!ZEND_FCC_INITIALIZED(ch->handlers.fnmatch)) {
+		return rval;
+	}
+
 	GC_ADDREF(&ch->std);
 	ZVAL_OBJ(&argv[0], &ch->std);
 	ZVAL_STRING(&argv[1], pattern);
@@ -652,6 +656,9 @@ static int curl_progress(void *clientp, double dltotal, double dlnow, double ult
 	fprintf(stderr, "curl_progress() called\n");
 	fprintf(stderr, "clientp = %x, dltotal = %f, dlnow = %f, ultotal = %f, ulnow = %f\n", clientp, dltotal, dlnow, ultotal, ulnow);
 #endif
+	if (!ZEND_FCC_INITIALIZED(ch->handlers.progress)) {
+		return rval;
+	}

 	zval args[5];
 	zval retval;
@@ -690,6 +697,9 @@ static int curl_xferinfo(void *clientp, curl_off_t dltotal, curl_off_t dlnow, cu
 	fprintf(stderr, "curl_xferinfo() called\n");
 	fprintf(stderr, "clientp = %x, dltotal = %ld, dlnow = %ld, ultotal = %ld, ulnow = %ld\n", clientp, dltotal, dlnow, ultotal, ulnow);
 #endif
+	if (!ZEND_FCC_INITIALIZED(ch->handlers.xferinfo)) {
+		return rval;
+	}

 	zval argv[5];
 	zval retval;
diff --git a/ext/curl/tests/gh21023.phpt b/ext/curl/tests/gh21023.phpt
new file mode 100644
index 00000000000..9647bd7baad
--- /dev/null
+++ b/ext/curl/tests/gh21023.phpt
@@ -0,0 +1,27 @@
+--TEST--
+GH-21023 (crash with CURLOPT_XFERINFOFUNCTION set with an invalid callback)
+--EXTENSIONS--
+curl
+--FILE--
+<?php
+include 'server.inc';
+$host = curl_cli_server_start();
+$url = "{$host}/get.inc";
+$ch = curl_init($url);
+curl_setopt($ch, CURLOPT_NOPROGRESS, 0);
+curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
+curl_setopt($ch, CURLOPT_XFERINFOFUNCTION, null);
+curl_exec($ch);
+$ch = curl_init($url);
+curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
+curl_setopt($ch, CURLOPT_PROGRESSFUNCTION, null);
+curl_exec($ch);
+$ch = curl_init($url);
+curl_setopt($ch, CURLOPT_WILDCARDMATCH, 1);
+curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
+curl_setopt($ch, CURLOPT_FNMATCH_FUNCTION, null);
+curl_exec($ch);
+echo "OK", PHP_EOL;
+?>
+--EXPECT--
+OK