Skip to content

Commit 9e28332

Browse files
committed
Make libxml_set_external_entity_loader() return the previous loader
Fixes #76763.
1 parent 2a0bc0b commit 9e28332

File tree

6 files changed

+66
-34
lines changed

6 files changed

+66
-34
lines changed

ext/libxml/libxml.c

Lines changed: 27 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -226,23 +226,11 @@ static PHP_GINIT_FUNCTION(libxml)
226226
ZVAL_UNDEF(&libxml_globals->stream_context);
227227
libxml_globals->error_buffer.s = NULL;
228228
libxml_globals->error_list = NULL;
229-
ZVAL_UNDEF(&libxml_globals->entity_loader.object);
229+
ZVAL_NULL(&libxml_globals->entity_loader.callback);
230230
libxml_globals->entity_loader.fci.size = 0;
231231
libxml_globals->entity_loader_disabled = 0;
232232
}
233233

234-
static void _php_libxml_destroy_fci(zend_fcall_info *fci, zval *object)
235-
{
236-
if (fci->size > 0) {
237-
zval_ptr_dtor(&fci->function_name);
238-
fci->size = 0;
239-
}
240-
if (!Z_ISUNDEF_P(object)) {
241-
zval_ptr_dtor(object);
242-
ZVAL_UNDEF(object);
243-
}
244-
}
245-
246234
/* Channel libxml file io layer through the PHP streams subsystem.
247235
* This allows use of ftps:// and https:// urls */
248236

@@ -893,8 +881,12 @@ static PHP_RINIT_FUNCTION(libxml)
893881

894882
static PHP_RSHUTDOWN_FUNCTION(libxml)
895883
{
896-
_php_libxml_destroy_fci(&LIBXML(entity_loader).fci, &LIBXML(entity_loader).object);
897-
884+
LIBXML(entity_loader).fci.size = 0;
885+
if (!Z_ISNULL(LIBXML(entity_loader).callback)) {
886+
zval_ptr_dtor_nogc(&LIBXML(entity_loader).callback);
887+
ZVAL_NULL(&LIBXML(entity_loader).callback);
888+
}
889+
898890
return SUCCESS;
899891
}
900892

@@ -1110,29 +1102,36 @@ PHP_FUNCTION(libxml_disable_entity_loader)
11101102
}
11111103
/* }}} */
11121104

1113-
/* {{{ Changes the default external entity loader */
1105+
/* {{{ Change the default external entity loader and return the previous loader */
11141106
PHP_FUNCTION(libxml_set_external_entity_loader)
11151107
{
1108+
zval *callback;
11161109
zend_fcall_info fci;
1117-
zend_fcall_info_cache fcc;
1110+
zend_fcall_info_cache fcc;
1111+
char *error = NULL;
11181112

11191113
ZEND_PARSE_PARAMETERS_START(1, 1)
1120-
Z_PARAM_FUNC_OR_NULL(fci, fcc)
1114+
Z_PARAM_ZVAL(callback)
11211115
ZEND_PARSE_PARAMETERS_END();
11221116

1123-
_php_libxml_destroy_fci(&LIBXML(entity_loader).fci, &LIBXML(entity_loader).object);
1124-
1125-
if (ZEND_FCI_INITIALIZED(fci)) { /* argument not null */
1126-
LIBXML(entity_loader).fci = fci;
1127-
Z_ADDREF(fci.function_name);
1128-
if (fci.object != NULL) {
1129-
ZVAL_OBJ(&LIBXML(entity_loader).object, fci.object);
1130-
Z_ADDREF(LIBXML(entity_loader).object);
1117+
if (Z_ISNULL_P(callback)) {
1118+
LIBXML(entity_loader).fci.size = 0;
1119+
} else {
1120+
fci.size = sizeof(fci);
1121+
fci.object = NULL;
1122+
fci.named_params = NULL;
1123+
if (zend_fcall_info_init(callback, 0, &fci, &fcc, NULL, &error) != SUCCESS) {
1124+
zend_argument_type_error(0, "must be a valid callback or NULL, %s", error);
1125+
RETURN_FALSE;
11311126
}
1127+
LIBXML(entity_loader).fci = fci;
11321128
LIBXML(entity_loader).fcc = fcc;
11331129
}
1134-
1135-
RETURN_TRUE;
1130+
ZVAL_COPY(return_value, &LIBXML(entity_loader).callback);
1131+
if (!Z_ISNULL(LIBXML(entity_loader).callback)) {
1132+
zval_ptr_dtor_nogc(&LIBXML(entity_loader).callback);
1133+
}
1134+
ZVAL_COPY(&LIBXML(entity_loader).callback, callback);
11361135
}
11371136
/* }}} */
11381137

ext/libxml/libxml.stub.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,4 +27,4 @@ function libxml_clear_errors(): void {}
2727
/** @deprecated */
2828
function libxml_disable_entity_loader(bool $disable = true): bool {}
2929

30-
function libxml_set_external_entity_loader(?callable $resolver_function): bool {}
30+
function libxml_set_external_entity_loader(?callable $resolver_function): callable|bool|null {}

ext/libxml/libxml_arginfo.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/* This is a generated file, edit the .stub.php file instead.
2-
* Stub hash: 4bde2f5c4e55b6e0c273b0d8605cb765cc9f8400 */
2+
* Stub hash: 71b8744c16e10fc3af07a66ca68cb68b5410bc85 */
33

44
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_libxml_set_streams_context, 0, 1, IS_VOID, 0)
55
ZEND_ARG_INFO(0, context)
@@ -22,7 +22,7 @@ ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_libxml_disable_entity_loader, 0,
2222
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, disable, _IS_BOOL, 0, "true")
2323
ZEND_END_ARG_INFO()
2424

25-
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_libxml_set_external_entity_loader, 0, 1, _IS_BOOL, 0)
25+
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_MASK_EX(arginfo_libxml_set_external_entity_loader, 0, 1, MAY_BE_CALLABLE|MAY_BE_BOOL|MAY_BE_NULL)
2626
ZEND_ARG_TYPE_INFO(0, resolver_function, IS_CALLABLE, 1)
2727
ZEND_END_ARG_INFO()
2828

ext/libxml/php_libxml.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -43,8 +43,8 @@ ZEND_BEGIN_MODULE_GLOBALS(libxml)
4343
smart_str error_buffer;
4444
zend_llist *error_list;
4545
struct _php_libxml_entity_resolver {
46-
zval object;
47-
zend_fcall_info fci;
46+
zval callback;
47+
zend_fcall_info fci;
4848
zend_fcall_info_cache fcc;
4949
} entity_loader;
5050
bool entity_loader_disabled;

ext/libxml/tests/libxml_set_external_entity_loader_error1.phpt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,6 @@ try {
2222
echo "Done.\n";
2323
?>
2424
--EXPECT--
25-
bool(true)
25+
NULL
2626
Exception: Too few arguments to function {closure}(), 3 passed and exactly 4 expected
2727
Done.
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
--TEST--
2+
libxml_set_external_entity_loader() returns previous handler
3+
--SKIPIF--
4+
<?php if (!extension_loaded('dom')) die('skip dom extension not available'); ?>
5+
--FILE--
6+
<?php
7+
8+
class Handler {
9+
private $name;
10+
11+
public function __construct($name) {
12+
$this->name = $name;
13+
}
14+
15+
public function handle($public, $system, $context) {
16+
return null;
17+
}
18+
19+
public function __toString() {
20+
return "Handler#{$this->name}";
21+
}
22+
}
23+
24+
var_dump(libxml_set_external_entity_loader([new Handler('A'), 'handle']));
25+
print libxml_set_external_entity_loader([new Handler('B'), 'handle'])[0] . "\n";
26+
print libxml_set_external_entity_loader(null)[0] . "\n";
27+
var_dump(libxml_set_external_entity_loader(null));
28+
29+
--EXPECT--
30+
NULL
31+
Handler#A
32+
Handler#B
33+
NULL

0 commit comments

Comments
 (0)