Skip to content

Commit 1805822

Browse files
authored
sapi: only use FCC for header_register_callback() (#22877)
No need to rederive callability of zval, or copies of it.
1 parent f465d35 commit 1805822

4 files changed

Lines changed: 48 additions & 42 deletions

File tree

main/SAPI.c

Lines changed: 14 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -111,51 +111,25 @@ PHP_FUNCTION(header_register_callback)
111111
zend_fcall_info fci;
112112
zend_fcall_info_cache fcc;
113113

114-
if (zend_parse_parameters(ZEND_NUM_ARGS(), "f", &fci, &fcc) == FAILURE) {
114+
if (zend_parse_parameters(ZEND_NUM_ARGS(), "F", &fci, &fcc) == FAILURE) {
115115
RETURN_THROWS();
116116
}
117117

118-
if (Z_TYPE(SG(callback_func)) != IS_UNDEF) {
119-
zval_ptr_dtor(&SG(callback_func));
120-
SG(fci_cache) = empty_fcall_info_cache;
118+
if (ZEND_FCC_INITIALIZED(SG(send_header_fcc))) {
119+
zend_fcc_dtor(&SG(send_header_fcc));
121120
}
122121

123122
/* Don't store callback if headers have already been sent:
124123
* It won't get used and we won't have a chance to release it. */
125-
if (!SG(headers_sent)) {
126-
ZVAL_COPY(&SG(callback_func), &fci.function_name);
124+
if (UNEXPECTED(SG(headers_sent))) {
125+
zend_release_fcall_info_cache(&fcc);
126+
} else {
127+
zend_fcc_dup(&SG(send_header_fcc), &fcc);
127128
}
128-
129129
RETURN_TRUE;
130130
}
131131
/* }}} */
132132

133-
static void sapi_run_header_callback(zval *callback)
134-
{
135-
int error;
136-
zend_fcall_info fci;
137-
char *callback_error = NULL;
138-
zval retval;
139-
140-
if (zend_fcall_info_init(callback, 0, &fci, &SG(fci_cache), NULL, &callback_error) == SUCCESS) {
141-
fci.retval = &retval;
142-
143-
error = zend_call_function(&fci, &SG(fci_cache));
144-
if (error == FAILURE) {
145-
goto callback_failed;
146-
} else {
147-
zval_ptr_dtor(&retval);
148-
}
149-
} else {
150-
callback_failed:
151-
php_error_docref(NULL, E_WARNING, "Could not call the sapi_header_callback");
152-
}
153-
154-
if (callback_error) {
155-
efree(callback_error);
156-
}
157-
}
158-
159133
SAPI_API void sapi_handle_post(void *arg)
160134
{
161135
if (SG(request_info).post_entry && SG(request_info).content_type_dup) {
@@ -436,7 +410,6 @@ SAPI_API void sapi_activate(void)
436410
SG(sapi_headers).http_status_line = NULL;
437411
SG(sapi_headers).mimetype = NULL;
438412
SG(headers_sent) = 0;
439-
ZVAL_UNDEF(&SG(callback_func));
440413
SG(read_post_bytes) = 0;
441414
SG(request_info).request_body = NULL;
442415
SG(request_info).current_user = NULL;
@@ -446,6 +419,7 @@ SAPI_API void sapi_activate(void)
446419
SG(request_info).proto_num = 1000; /* Default to HTTP 1.0 */
447420
SG(global_request_time) = 0;
448421
SG(post_read) = 0;
422+
SG(send_header_fcc) = empty_fcall_info_cache;
449423
/* It's possible to override this general case in the activate() callback, if necessary. */
450424
if (SG(request_info).request_method && !strcmp(SG(request_info).request_method, "HEAD")) {
451425
SG(request_info).headers_only = 1;
@@ -889,12 +863,12 @@ SAPI_API int sapi_send_headers(void)
889863
SG(sapi_headers).send_default_content_type = 0;
890864
}
891865

892-
if (Z_TYPE(SG(callback_func)) != IS_UNDEF) {
893-
zval cb;
894-
ZVAL_COPY_VALUE(&cb, &SG(callback_func));
895-
ZVAL_UNDEF(&SG(callback_func));
896-
sapi_run_header_callback(&cb);
897-
zval_ptr_dtor(&cb);
866+
if (ZEND_FCC_INITIALIZED(SG(send_header_fcc))) {
867+
zend_fcall_info_cache fcc = SG(send_header_fcc);
868+
/* Prevent triggering the callback multiple times */
869+
SG(send_header_fcc) = empty_fcall_info_cache;
870+
zend_call_known_fcc(&fcc, NULL, 0, NULL, NULL);
871+
zend_fcc_dtor(&fcc);
898872
}
899873

900874
SG(headers_sent) = 1;

main/SAPI.h

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -143,8 +143,7 @@ typedef struct _sapi_globals_struct {
143143
bool sapi_started;
144144
double global_request_time;
145145
HashTable known_post_content_types;
146-
zval callback_func;
147-
zend_fcall_info_cache fci_cache;
146+
zend_fcall_info_cache send_header_fcc;
148147
sapi_request_parse_body_context request_parse_body_context;
149148
} sapi_globals_struct;
150149

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
--TEST--
2+
Test header_register_callback
3+
--FILE--
4+
<?php
5+
class TrampolineTest {
6+
public function __call(string $name, array $arguments) {
7+
echo 'Trampoline for ', $name, PHP_EOL;
8+
}
9+
}
10+
$o = new TrampolineTest();
11+
$callback = [$o, 'trampoline'];
12+
13+
header_register_callback($callback);
14+
?>
15+
--EXPECT--
16+
Trampoline for trampoline
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
--TEST--
2+
Test header_register_callback
3+
--FILE--
4+
<?php
5+
class TrampolineTest {
6+
public function __call(string $name, array $arguments) {
7+
echo 'Trampoline for ', $name, PHP_EOL;
8+
}
9+
}
10+
$o = new TrampolineTest();
11+
$callback = [$o, 'trampoline'];
12+
13+
echo "Send headers.\n";
14+
header_register_callback($callback);
15+
?>
16+
--EXPECT--
17+
Send headers.

0 commit comments

Comments
 (0)