Skip to content

Commit dfacdbf

Browse files
committed
Make libxml_set_external_entity_loader() return the previous loader
Fixes #76763.
1 parent 7d6b961 commit dfacdbf

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

@@ -892,8 +880,12 @@ static PHP_RINIT_FUNCTION(libxml)
892880

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

@@ -1109,29 +1101,36 @@ PHP_FUNCTION(libxml_disable_entity_loader)
11091101
}
11101102
/* }}} */
11111103

1112-
/* {{{ Changes the default external entity loader */
1104+
/* {{{ Change the default external entity loader and return the previous loader */
11131105
PHP_FUNCTION(libxml_set_external_entity_loader)
11141106
{
1107+
zval *callback;
11151108
zend_fcall_info fci;
1116-
zend_fcall_info_cache fcc;
1109+
zend_fcall_info_cache fcc;
1110+
char *error = NULL;
11171111

11181112
ZEND_PARSE_PARAMETERS_START(1, 1)
1119-
Z_PARAM_FUNC_OR_NULL(fci, fcc)
1113+
Z_PARAM_ZVAL(callback)
11201114
ZEND_PARSE_PARAMETERS_END();
11211115

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

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)