Skip to content

Commit f9ccae9

Browse files
committed
Improve error when swapping object
1 parent 87a5212 commit f9ccae9

File tree

2 files changed

+67
-15
lines changed

2 files changed

+67
-15
lines changed
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
--TEST--
2+
Swap underlying object to call methods with xml_set_object() new object has missing methods
3+
--EXTENSIONS--
4+
xml
5+
--FILE--
6+
<?php
7+
8+
class A {
9+
public function start_element($parser, $name, $attributes) {
10+
global $b;
11+
echo "A::start_element($name)\n";
12+
try {
13+
xml_set_object($parser, $b);
14+
} catch (\Throwable $e) {
15+
echo $e::class, ': ', $e->getMessage(), PHP_EOL;
16+
exit();
17+
}
18+
}
19+
public function end_element($parser, $name) {
20+
echo "B::end_element($name)\n";
21+
}
22+
}
23+
24+
class B {
25+
public function start_element($parser, $name) {
26+
echo "B::start_element($name)\n";
27+
}
28+
}
29+
30+
$a = new A;
31+
$b = new B;
32+
33+
$parser = xml_parser_create();
34+
xml_set_object($parser, $a);
35+
xml_set_element_handler($parser, "start_element", "end_element");
36+
xml_parse($parser, <<<XML
37+
<?xml version="1.0"?>
38+
<container>
39+
<child/>
40+
</container>
41+
XML);
42+
43+
?>
44+
--EXPECT--
45+
A::start_element(CONTAINER)
46+
ValueError: xml_set_object(): Argument #2 ($object) cannot safely swap to object of class B as method "end_element" does not exist which was set via xml_set_element_handler()

ext/xml/xml.c

Lines changed: 21 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1059,11 +1059,13 @@ static bool php_xml_check_string_method_arg(
10591059
zend_fcall_info_cache *const parser_handler_fcc
10601060
) {
10611061
if (ZSTR_LEN(method_name) == 0) {
1062+
ZEND_ASSERT(arg_num != 0);
10621063
/* Unset handler */
10631064
return true;
10641065
}
10651066

10661067
if (!object) {
1068+
ZEND_ASSERT(arg_num != 0);
10671069
zend_argument_value_error(arg_num, "an object must be set via xml_set_object() to be able to lookup method");
10681070
return false;
10691071
}
@@ -1073,7 +1075,9 @@ static bool php_xml_check_string_method_arg(
10731075
zend_function *method_ptr = zend_hash_find_ptr(&ce->function_table, lc_name);
10741076
zend_string_release_ex(lc_name, 0);
10751077
if (!method_ptr) {
1076-
zend_argument_value_error(arg_num, "method %s::%s() does not exist", ZSTR_VAL(ce->name), ZSTR_VAL(method_name));
1078+
if (arg_num) {
1079+
zend_argument_value_error(arg_num, "method %s::%s() does not exist", ZSTR_VAL(ce->name), ZSTR_VAL(method_name));
1080+
}
10771081
return false;
10781082
}
10791083

@@ -1086,17 +1090,19 @@ static bool php_xml_check_string_method_arg(
10861090
return true;
10871091
}
10881092

1089-
#define PHP_XML_CHECK_NEW_THIS_METHODS(parser_to_check, new_this_obj, fcc_field) \
1093+
#define PHP_XML_CHECK_NEW_THIS_METHODS(parser_to_check, new_this_obj, fcc_field, handler_set_method) \
10901094
if ( \
10911095
ZEND_FCC_INITIALIZED(parser_to_check->fcc_field) \
10921096
&& parser_to_check->fcc_field.object == parser_to_check->object \
10931097
&& parser_to_check->fcc_field.calling_scope == NULL \
10941098
) { \
10951099
zend_string *method_name = zend_string_copy(parser_to_check->fcc_field.function_handler->common.function_name); \
10961100
zend_fcc_dtor(&parser_to_check->fcc_field); \
1097-
bool status = php_xml_check_string_method_arg(2, new_this_obj, method_name, &parser_to_check->fcc_field); \
1101+
bool status = php_xml_check_string_method_arg(0, new_this_obj, method_name, &parser_to_check->fcc_field); \
10981102
if (status == false) { \
1099-
/* TODO Better error message */ RETURN_THROWS(); \
1103+
zend_argument_value_error(2, "cannot safely swap to object of class %s as method \"%s\" does not exist which was set via " handler_set_method, \
1104+
ZSTR_VAL(new_this_obj->ce->name), ZSTR_VAL(method_name)); \
1105+
RETURN_THROWS(); \
11001106
} \
11011107
zend_fcc_addref(&parser_to_check->fcc_field); \
11021108
}
@@ -1117,17 +1123,17 @@ PHP_FUNCTION(xml_set_object)
11171123
new_this = Z_OBJ_P(mythis);
11181124

11191125
if (parser->object) {
1120-
PHP_XML_CHECK_NEW_THIS_METHODS(parser, new_this, startElementHandler);
1121-
PHP_XML_CHECK_NEW_THIS_METHODS(parser, new_this, endElementHandler);
1122-
PHP_XML_CHECK_NEW_THIS_METHODS(parser, new_this, characterDataHandler);
1123-
PHP_XML_CHECK_NEW_THIS_METHODS(parser, new_this, processingInstructionHandler);
1124-
PHP_XML_CHECK_NEW_THIS_METHODS(parser, new_this, defaultHandler);
1125-
PHP_XML_CHECK_NEW_THIS_METHODS(parser, new_this, unparsedEntityDeclHandler);
1126-
PHP_XML_CHECK_NEW_THIS_METHODS(parser, new_this, notationDeclHandler);
1127-
PHP_XML_CHECK_NEW_THIS_METHODS(parser, new_this, externalEntityRefHandler);
1128-
PHP_XML_CHECK_NEW_THIS_METHODS(parser, new_this, unknownEncodingHandler);
1129-
PHP_XML_CHECK_NEW_THIS_METHODS(parser, new_this, startNamespaceDeclHandler);
1130-
PHP_XML_CHECK_NEW_THIS_METHODS(parser, new_this, endNamespaceDeclHandler);
1126+
PHP_XML_CHECK_NEW_THIS_METHODS(parser, new_this, startElementHandler, "xml_set_element_handler()");
1127+
PHP_XML_CHECK_NEW_THIS_METHODS(parser, new_this, endElementHandler, "xml_set_element_handler()");
1128+
PHP_XML_CHECK_NEW_THIS_METHODS(parser, new_this, characterDataHandler, "xml_set_character_data_handler()");
1129+
PHP_XML_CHECK_NEW_THIS_METHODS(parser, new_this, processingInstructionHandler, "xml_set_processing_instruction_handler()");
1130+
PHP_XML_CHECK_NEW_THIS_METHODS(parser, new_this, defaultHandler, "xml_set_default_handler()");
1131+
PHP_XML_CHECK_NEW_THIS_METHODS(parser, new_this, unparsedEntityDeclHandler, "xml_set_unparsed_entity_decl_handler()");
1132+
PHP_XML_CHECK_NEW_THIS_METHODS(parser, new_this, notationDeclHandler, "xml_set_notation_decl_handler()");
1133+
PHP_XML_CHECK_NEW_THIS_METHODS(parser, new_this, externalEntityRefHandler, "xml_set_external_entity_ref_handler()");
1134+
//PHP_XML_CHECK_NEW_THIS_METHODS(parser, new_this, unknownEncodingHandler, "we_dont_have_a_function_for_this_loool()");
1135+
PHP_XML_CHECK_NEW_THIS_METHODS(parser, new_this, startNamespaceDeclHandler, "xml_set_start_namespace_decl_handler()");
1136+
PHP_XML_CHECK_NEW_THIS_METHODS(parser, new_this, endNamespaceDeclHandler, "xml_set_end_namespace_decl_handler()");
11311137

11321138
OBJ_RELEASE(parser->object);
11331139
}

0 commit comments

Comments
 (0)