Skip to content

Commit 1179622

Browse files
tstarlingbukka
authored andcommitted
Add libxml_get_external_entity_loader()
Add libxml_get_external_entity_loader(), which returns the currently installed external entity loader, i.e. the value which was passed to libxml_set_external_entity_loader() or null if no loader was installed and the default entity loader will be used. This allows libraries to save and restore the loader, controlling entity expansion without interfering with the rest of the application. Add macro Z_PARAM_FUNC_OR_NULL_WITH_ZVAL(). This allows us to get the zval for a callable parameter without duplicating callable argument parsing. The saved zval keeps the object needed for fcc/fci alive, simplifying memory management. Fixes #76763.
1 parent 35e2a25 commit 1179622

File tree

9 files changed

+94
-26
lines changed

9 files changed

+94
-26
lines changed

NEWS

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,9 @@ PHP NEWS
3030
. Fixed bug GH-9316 ($http_response_header is wrong for long status line).
3131
(cmb, timwolla)
3232

33+
- XML:
34+
. Added libxml_get_external_entity_loader() function. (Tim Starling)
35+
3336
18 Aug 2022, PHP 8.2.0beta3
3437

3538
- Core:

UPGRADING

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -251,6 +251,9 @@ PHP 8.2 UPGRADE NOTES
251251
ini_parse_quantity(). The `memory_limit` setting accepts values higher than
252252
PHP_INT_MAX, than can not be parsed by ini_parse_quantity().
253253

254+
- XML:
255+
. libxml_get_external_entity_loader()
256+
254257
========================================
255258
7. New Classes and Interfaces
256259
========================================

Zend/zend_API.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1538,6 +1538,10 @@ ZEND_API ZEND_COLD void zend_argument_value_error(uint32_t arg_num, const char *
15381538
SEPARATE_ZVAL_NOREF(_arg); \
15391539
}
15401540

1541+
/* get the zval* for a previously parsed argument */
1542+
#define Z_PARAM_GET_PREV_ZVAL(dest) \
1543+
zend_parse_arg_zval_deref(_arg, &dest, 0);
1544+
15411545
/* old "|" */
15421546
#define Z_PARAM_OPTIONAL \
15431547
_optional = 1;
@@ -1700,6 +1704,10 @@ ZEND_API ZEND_COLD void zend_argument_value_error(uint32_t arg_num, const char *
17001704
#define Z_PARAM_FUNC_OR_NULL(dest_fci, dest_fcc) \
17011705
Z_PARAM_FUNC_EX(dest_fci, dest_fcc, 1, 0)
17021706

1707+
#define Z_PARAM_FUNC_OR_NULL_WITH_ZVAL(dest_fci, dest_fcc, dest_zp) \
1708+
Z_PARAM_FUNC_EX(dest_fci, dest_fcc, 1, 0) \
1709+
Z_PARAM_GET_PREV_ZVAL(dest_zp)
1710+
17031711
/* old "h" */
17041712
#define Z_PARAM_ARRAY_HT_EX2(dest, check_null, deref, separate) \
17051713
Z_PARAM_PROLOGUE(deref, separate); \

ext/libxml/libxml.c

Lines changed: 20 additions & 23 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,7 +839,9 @@ 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);
842+
LIBXML(entity_loader).fci.size = 0;
843+
zval_ptr_dtor_nogc(&LIBXML(entity_loader).callback);
844+
ZVAL_NULL(&LIBXML(entity_loader).callback);
855845

856846
return SUCCESS;
857847
}
@@ -1071,29 +1061,36 @@ PHP_FUNCTION(libxml_disable_entity_loader)
10711061
/* {{{ Changes the default external entity loader */
10721062
PHP_FUNCTION(libxml_set_external_entity_loader)
10731063
{
1064+
zval *callback;
10741065
zend_fcall_info fci;
10751066
zend_fcall_info_cache fcc;
10761067

10771068
ZEND_PARSE_PARAMETERS_START(1, 1)
1078-
Z_PARAM_FUNC_OR_NULL(fci, fcc)
1069+
Z_PARAM_FUNC_OR_NULL_WITH_ZVAL(fci, fcc, callback)
10791070
ZEND_PARSE_PARAMETERS_END();
10801071

1081-
_php_libxml_destroy_fci(&LIBXML(entity_loader).fci, &LIBXML(entity_loader).object);
1082-
10831072
if (ZEND_FCI_INITIALIZED(fci)) { /* argument not null */
10841073
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);
1089-
}
10901074
LIBXML(entity_loader).fcc = fcc;
1075+
} else {
1076+
LIBXML(entity_loader).fci.size = 0;
10911077
}
1092-
1078+
if (!Z_ISNULL(LIBXML(entity_loader).callback)) {
1079+
zval_ptr_dtor_nogc(&LIBXML(entity_loader).callback);
1080+
}
1081+
ZVAL_COPY(&LIBXML(entity_loader).callback, callback);
10931082
RETURN_TRUE;
10941083
}
10951084
/* }}} */
10961085

1086+
/* {{{ Get the current external entity loader, or null if the default loader is installer. */
1087+
PHP_FUNCTION(libxml_get_external_entity_loader)
1088+
{
1089+
ZEND_PARSE_PARAMETERS_NONE();
1090+
RETURN_COPY(&LIBXML(entity_loader).callback);
1091+
}
1092+
/* }}} */
1093+
10971094
/* {{{ Common functions shared by extensions */
10981095
int php_libxml_xmlCheckUTF8(const unsigned char *s)
10991096
{

ext/libxml/libxml.stub.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -177,3 +177,5 @@ function libxml_clear_errors(): void {}
177177
function libxml_disable_entity_loader(bool $disable = true): bool {}
178178

179179
function libxml_set_external_entity_loader(?callable $resolver_function): bool {}
180+
181+
function libxml_get_external_entity_loader(): ?callable {}

ext/libxml/libxml_arginfo.h

Lines changed: 6 additions & 1 deletion
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;
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
--TEST--
2+
libxml_get_external_entity_loader() returns current handler
3+
--EXTENSIONS--
4+
libxml
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_get_external_entity_loader());
25+
libxml_set_external_entity_loader([new Handler('A'), 'handle']);
26+
print libxml_get_external_entity_loader()[0] . "\n";
27+
libxml_set_external_entity_loader([new Handler('B'), 'handle']);
28+
print libxml_get_external_entity_loader()[0] . "\n";
29+
libxml_set_external_entity_loader(null);
30+
var_dump(libxml_get_external_entity_loader());
31+
32+
--EXPECT--
33+
NULL
34+
Handler#A
35+
Handler#B
36+
NULL
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
--TEST--
2+
libxml_set_external_entity_loader() with non-callable argument
3+
--EXTENSIONS--
4+
libxml
5+
--FILE--
6+
<?php
7+
try {
8+
libxml_set_external_entity_loader('nonexistent_function');
9+
} catch (Throwable $e) {
10+
echo "Exception: " . $e->getMessage() . "\n";
11+
}
12+
?>
13+
--EXPECT--
14+
Exception: libxml_set_external_entity_loader(): Argument #1 ($resolver_function) must be a valid callback or null, function "nonexistent_function" not found or invalid function name

0 commit comments

Comments
 (0)