Skip to content

Commit b6f5acc

Browse files
committed
Make libxml_set_external_entity_loader() return the previous loader
Fixes #76763.
1 parent 107ad28 commit b6f5acc

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
@@ -228,23 +228,11 @@ static PHP_GINIT_FUNCTION(libxml)
228228
ZVAL_UNDEF(&libxml_globals->stream_context);
229229
libxml_globals->error_buffer.s = NULL;
230230
libxml_globals->error_list = NULL;
231-
ZVAL_UNDEF(&libxml_globals->entity_loader.object);
231+
ZVAL_NULL(&libxml_globals->entity_loader.callback);
232232
libxml_globals->entity_loader.fci.size = 0;
233233
libxml_globals->entity_loader_disabled = 0;
234234
}
235235

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

@@ -851,8 +839,12 @@ static PHP_RINIT_FUNCTION(libxml)
851839

852840
static PHP_RSHUTDOWN_FUNCTION(libxml)
853841
{
854-
_php_libxml_destroy_fci(&LIBXML(entity_loader).fci, &LIBXML(entity_loader).object);
855-
842+
LIBXML(entity_loader).fci.size = 0;
843+
if (!Z_ISNULL(LIBXML(entity_loader).callback)) {
844+
zval_ptr_dtor_nogc(&LIBXML(entity_loader).callback);
845+
ZVAL_NULL(&LIBXML(entity_loader).callback);
846+
}
847+
856848
return SUCCESS;
857849
}
858850

@@ -1068,29 +1060,36 @@ PHP_FUNCTION(libxml_disable_entity_loader)
10681060
}
10691061
/* }}} */
10701062

1071-
/* {{{ Changes the default external entity loader */
1063+
/* {{{ Change the default external entity loader and return the previous loader */
10721064
PHP_FUNCTION(libxml_set_external_entity_loader)
10731065
{
1066+
zval *callback;
10741067
zend_fcall_info fci;
1075-
zend_fcall_info_cache fcc;
1068+
zend_fcall_info_cache fcc;
1069+
char *error = NULL;
10761070

10771071
ZEND_PARSE_PARAMETERS_START(1, 1)
1078-
Z_PARAM_FUNC_OR_NULL(fci, fcc)
1072+
Z_PARAM_ZVAL(callback)
10791073
ZEND_PARSE_PARAMETERS_END();
10801074

1081-
_php_libxml_destroy_fci(&LIBXML(entity_loader).fci, &LIBXML(entity_loader).object);
1082-
1083-
if (ZEND_FCI_INITIALIZED(fci)) { /* argument not null */
1084-
LIBXML(entity_loader).fci = fci;
1085-
Z_ADDREF(fci.function_name);
1086-
if (fci.object != NULL) {
1087-
ZVAL_OBJ(&LIBXML(entity_loader).object, fci.object);
1088-
Z_ADDREF(LIBXML(entity_loader).object);
1075+
if (Z_ISNULL_P(callback)) {
1076+
LIBXML(entity_loader).fci.size = 0;
1077+
} else {
1078+
fci.size = sizeof(fci);
1079+
fci.object = NULL;
1080+
fci.named_params = NULL;
1081+
if (zend_fcall_info_init(callback, 0, &fci, &fcc, NULL, &error) != SUCCESS) {
1082+
zend_argument_type_error(0, "must be a valid callback or NULL, %s", error);
1083+
RETURN_FALSE;
10891084
}
1085+
LIBXML(entity_loader).fci = fci;
10901086
LIBXML(entity_loader).fcc = fcc;
10911087
}
1092-
1093-
RETURN_TRUE;
1088+
ZVAL_COPY(return_value, &LIBXML(entity_loader).callback);
1089+
if (!Z_ISNULL(LIBXML(entity_loader).callback)) {
1090+
zval_ptr_dtor_nogc(&LIBXML(entity_loader).callback);
1091+
}
1092+
ZVAL_COPY(&LIBXML(entity_loader).callback, callback);
10941093
}
10951094
/* }}} */
10961095

ext/libxml/libxml.stub.php

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

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

ext/libxml/libxml_arginfo.h

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

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)