Commit 425cd3d6a15 for php.net
commit 425cd3d6a15bb5fec5724a9f89130029bdd9aa4f
Author: Gina Peter Banyard <girgias@php.net>
Date: Sat May 30 14:42:02 2026 +0200
ext/openssl: convert SESSION callback to FCC
Prevent rechecking the given zval callable every single time
diff --git a/ext/openssl/xp_ssl.c b/ext/openssl/xp_ssl.c
index f90d7549ae7..9486513fab7 100644
--- a/ext/openssl/xp_ssl.c
+++ b/ext/openssl/xp_ssl.c
@@ -190,9 +190,9 @@ typedef struct _php_openssl_psk_callbacks_t {
/* Holds session callback */
typedef struct _php_openssl_session_callbacks_t {
int refcount;
- zval new_cb;
- zval get_cb;
- zval remove_cb;
+ zend_fcall_info_cache new_cb;
+ zend_fcall_info_cache get_cb;
+ zend_fcall_info_cache remove_cb;
} php_openssl_session_callbacks_t;
/* This implementation is very closely tied to the that of the native
@@ -2004,15 +2004,11 @@ static int php_openssl_session_new_cb(SSL *ssl, SSL_SESSION *session)
SSL_SESSION_up_ref(session);
zval args[2];
- zval retval;
ZVAL_RES(&args[0], stream->res);
php_openssl_session_object_init(&args[1], session);
- if (call_user_function(EG(function_table), NULL, &sslsock->session_callbacks->new_cb,
- &retval, 2, args) == SUCCESS) {
- zval_ptr_dtor(&retval);
- }
+ zend_call_known_fcc(&sslsock->session_callbacks->new_cb, NULL, 2, args, NULL);
zval_ptr_dtor(&args[1]);
@@ -2045,22 +2041,21 @@ static SSL_SESSION *php_openssl_session_get_cb(SSL *ssl, const unsigned char *se
SSL_SESSION *session = NULL;
- if (call_user_function(EG(function_table), NULL, &sslsock->session_callbacks->get_cb,
- &retval, 2, args) == SUCCESS) {
- if (php_openssl_is_session_ce(&retval)) {
- /* Get session from object and increment ref since OpenSSL will own it */
- php_openssl_session_object *obj = Z_OPENSSL_SESSION_P(&retval);
- if (obj->session) {
- SSL_SESSION_up_ref(obj->session);
- session = obj->session;
- }
- } else if (Z_TYPE(retval) != IS_NULL) {
- zend_type_error("session_get_cb return type must be null or OpenSSLSession");
+ zend_call_known_fcc(&sslsock->session_callbacks->get_cb, &retval, 2, args, NULL);
+ zval_ptr_dtor(&args[1]);
+
+ if (php_openssl_is_session_ce(&retval)) {
+ /* Get session from object and increment ref since OpenSSL will own it */
+ php_openssl_session_object *obj = Z_OPENSSL_SESSION_P(&retval);
+ if (obj->session) {
+ SSL_SESSION_up_ref(obj->session);
+ session = obj->session;
}
+ } else if (Z_TYPE(retval) != IS_NULL) {
+ zend_type_error("session_get_cb return type must be null or OpenSSLSession");
}
zval_ptr_dtor(&retval);
- zval_ptr_dtor(&args[1]);
*copy = 0;
return session;
@@ -2085,28 +2080,41 @@ static void php_openssl_session_remove_cb(SSL_CTX *ctx, SSL_SESSION *session)
const unsigned char *session_id = SSL_SESSION_get_id(session, &session_id_len);
zval args[2];
- zval retval;
ZVAL_RES(&args[0], stream->res);
ZVAL_STRINGL(&args[1], (char *)session_id, session_id_len);
- if (call_user_function(EG(function_table), NULL, &sslsock->session_callbacks->remove_cb,
- &retval, 2, args) == SUCCESS) {
- zval_ptr_dtor(&retval);
- }
-
+ zend_call_known_fcc(&sslsock->session_callbacks->remove_cb, NULL, 2, args, NULL);
zval_ptr_dtor(&args[1]);
}
+
+enum php_openssl_session_callback_type {
+ PHP_OPENSSL_NEW_CB,
+ PHP_OPENSSL_GET_CB,
+ PHP_OPENSSL_REMOVE_CB,
+};
/**
* Validate callable and allocate callback structure if needed.
*/
-static zend_result php_openssl_validate_and_allocate_callback(
- php_openssl_netstream_data_t *sslsock, zval *callable,
- const char *callback_name, bool is_persistent)
+static zend_result php_openssl_validate_and_allocate_session_callback(
+ php_openssl_netstream_data_t *sslsock, const zval *callable,
+ enum php_openssl_session_callback_type cb_type, bool is_persistent)
{
- zend_fcall_info_cache fcc;
char *is_callable_error = NULL;
+ const char *callback_name;
+
+ switch (cb_type) {
+ case PHP_OPENSSL_NEW_CB:
+ callback_name = "session_new_cb";
+ break;
+ case PHP_OPENSSL_GET_CB:
+ callback_name = "session_get_cb";
+ break;
+ case PHP_OPENSSL_REMOVE_CB:
+ callback_name = "session_remove_cb";
+ break;
+ }
/* Callbacks not supported for persistent streams */
if (is_persistent) {
@@ -2116,6 +2124,7 @@ static zend_result php_openssl_validate_and_allocate_callback(
}
/* Validate callable */
+ zend_fcall_info_cache fcc;
if (!zend_is_callable_ex(callable, NULL, 0, NULL, &fcc, &is_callable_error)) {
if (is_callable_error) {
zend_type_error("%s must be a valid callback, %s", callback_name, is_callable_error);
@@ -2128,14 +2137,24 @@ static zend_result php_openssl_validate_and_allocate_callback(
/* Allocate callback structure if not already allocated */
if (!sslsock->session_callbacks) {
- sslsock->session_callbacks = (php_openssl_session_callbacks_t *)pemalloc(
- sizeof(php_openssl_session_callbacks_t), is_persistent);
- ZVAL_UNDEF(&sslsock->session_callbacks->new_cb);
- ZVAL_UNDEF(&sslsock->session_callbacks->get_cb);
- ZVAL_UNDEF(&sslsock->session_callbacks->remove_cb);
+ sslsock->session_callbacks = (php_openssl_session_callbacks_t *)pecalloc(
+ 1, sizeof(php_openssl_session_callbacks_t), is_persistent);
sslsock->session_callbacks->refcount = 1;
}
+ zend_fcc_addref(&fcc);
+ switch (cb_type) {
+ case PHP_OPENSSL_NEW_CB:
+ sslsock->session_callbacks->new_cb = fcc;
+ break;
+ case PHP_OPENSSL_GET_CB:
+ sslsock->session_callbacks->get_cb = fcc;
+ break;
+ case PHP_OPENSSL_REMOVE_CB:
+ sslsock->session_callbacks->remove_cb = fcc;
+ break;
+ }
+
return SUCCESS;
}
@@ -2159,12 +2178,11 @@ static zend_result php_openssl_setup_client_session(php_stream *stream,
}
if (GET_VER_OPT("session_new_cb")) {
- if (FAILURE == php_openssl_validate_and_allocate_callback(
- sslsock, val, "session_new_cb", is_persistent)) {
+ if (FAILURE == php_openssl_validate_and_allocate_session_callback(
+ sslsock, val, PHP_OPENSSL_NEW_CB, is_persistent)) {
return FAILURE;
}
- ZVAL_COPY(&sslsock->session_callbacks->new_cb, val);
SSL_CTX_sess_set_new_cb(sslsock->ctx, php_openssl_session_new_cb);
enable_client_cache = true;
}
@@ -2207,11 +2225,10 @@ static zend_result php_openssl_setup_server_session(php_stream *stream,
/* Check for session_get_cb first (determines cache mode) */
if (GET_VER_OPT("session_get_cb")) {
- if (FAILURE == php_openssl_validate_and_allocate_callback(
- sslsock, val, "session_new_cb", is_persistent)) {
+ if (FAILURE == php_openssl_validate_and_allocate_session_callback(
+ sslsock, val, PHP_OPENSSL_GET_CB, is_persistent)) {
return FAILURE;
}
- ZVAL_COPY(&sslsock->session_callbacks->get_cb, val);
has_get_cb = true;
}
@@ -2227,11 +2244,10 @@ static zend_result php_openssl_setup_server_session(php_stream *stream,
/* Check for session_new_cb */
if (GET_VER_OPT("session_new_cb")) {
- if (FAILURE == php_openssl_validate_and_allocate_callback(
- sslsock, val, "session_new_cb", is_persistent)) {
+ if (FAILURE == php_openssl_validate_and_allocate_session_callback(
+ sslsock, val, PHP_OPENSSL_NEW_CB, is_persistent)) {
return FAILURE;
}
- ZVAL_COPY(&sslsock->session_callbacks->new_cb, val);
has_new_cb = true;
if (!has_session_id_context &&
@@ -2249,12 +2265,11 @@ static zend_result php_openssl_setup_server_session(php_stream *stream,
/* Check for session_remove_cb (optional) */
if (GET_VER_OPT("session_remove_cb")) {
- if (FAILURE == php_openssl_validate_and_allocate_callback(
- sslsock, val, "session_remove_cb", is_persistent)) {
+ if (FAILURE == php_openssl_validate_and_allocate_session_callback(
+ sslsock, val, PHP_OPENSSL_REMOVE_CB, is_persistent)) {
return FAILURE;
}
- ZVAL_COPY(&sslsock->session_callbacks->remove_cb, val);
has_remove_cb = true;
}
@@ -3088,9 +3103,15 @@ static int php_openssl_sockop_close(php_stream *stream, int close_handle) /* {{{
}
if (sslsock->session_callbacks && --sslsock->session_callbacks->refcount == 0) {
- zval_ptr_dtor(&sslsock->session_callbacks->new_cb);
- zval_ptr_dtor(&sslsock->session_callbacks->get_cb);
- zval_ptr_dtor(&sslsock->session_callbacks->remove_cb);
+ if (ZEND_FCC_INITIALIZED(sslsock->session_callbacks->new_cb)) {
+ zend_fcc_dtor(&sslsock->session_callbacks->new_cb);
+ }
+ if (ZEND_FCC_INITIALIZED(sslsock->session_callbacks->get_cb)) {
+ zend_fcc_dtor(&sslsock->session_callbacks->get_cb);
+ }
+ if (ZEND_FCC_INITIALIZED(sslsock->session_callbacks->remove_cb)) {
+ zend_fcc_dtor(&sslsock->session_callbacks->remove_cb);
+ }
pefree(sslsock->session_callbacks, php_stream_is_persistent(stream));
}