diff --git a/ext/dom/document.c b/ext/dom/document.c index 9c5e2937560..425895c3240 100644 --- a/ext/dom/document.c +++ b/ext/dom/document.c @@ -1285,6 +1285,7 @@ static xmlDocPtr dom_document_parser(zval *id, int mode, char *source, size_t so options |= XML_PARSE_NOBLANKS; } + php_libxml_sanitize_parse_ctxt_options(ctxt); xmlCtxtUseOptions(ctxt, options); ctxt->recovery = recover; @@ -1594,7 +1595,9 @@ PHP_METHOD(DOMDocument, xinclude) DOM_GET_OBJ(docp, id, xmlDocPtr, intern); + PHP_LIBXML_SANITIZE_GLOBALS(xinclude); err = xmlXIncludeProcessFlags(docp, (int)flags); + PHP_LIBXML_RESTORE_GLOBALS(xinclude); /* XML_XINCLUDE_START and XML_XINCLUDE_END nodes need to be removed as these are added via xmlXIncludeProcess to mark beginning and ending of xincluded document @@ -1634,6 +1637,7 @@ PHP_METHOD(DOMDocument, validate) DOM_GET_OBJ(docp, id, xmlDocPtr, intern); + PHP_LIBXML_SANITIZE_GLOBALS(validate); cvp = xmlNewValidCtxt(); cvp->userData = NULL; @@ -1645,6 +1649,7 @@ PHP_METHOD(DOMDocument, validate) } else { RETVAL_FALSE; } + PHP_LIBXML_RESTORE_GLOBALS(validate); xmlFreeValidCtxt(cvp); @@ -1679,14 +1684,18 @@ static void _dom_document_schema_validate(INTERNAL_FUNCTION_PARAMETERS, int type DOM_GET_OBJ(docp, id, xmlDocPtr, intern); + PHP_LIBXML_SANITIZE_GLOBALS(new_parser_ctxt); + switch (type) { case DOM_LOAD_FILE: if (CHECK_NULL_PATH(source, source_len)) { + PHP_LIBXML_RESTORE_GLOBALS(new_parser_ctxt); zend_argument_value_error(1, "must not contain any null bytes"); RETURN_THROWS(); } valid_file = _dom_get_valid_file_path(source, resolved_path, MAXPATHLEN); if (!valid_file) { + PHP_LIBXML_RESTORE_GLOBALS(new_parser_ctxt); php_error_docref(NULL, E_WARNING, "Invalid Schema file source"); RETURN_FALSE; } @@ -1707,6 +1716,7 @@ static void _dom_document_schema_validate(INTERNAL_FUNCTION_PARAMETERS, int type parser); sptr = xmlSchemaParse(parser); xmlSchemaFreeParserCtxt(parser); + PHP_LIBXML_RESTORE_GLOBALS(new_parser_ctxt); if (!sptr) { if (!EG(exception)) { php_error_docref(NULL, E_WARNING, "Invalid Schema"); @@ -1727,11 +1737,13 @@ static void _dom_document_schema_validate(INTERNAL_FUNCTION_PARAMETERS, int type valid_opts |= XML_SCHEMA_VAL_VC_I_CREATE; } + PHP_LIBXML_SANITIZE_GLOBALS(validate); xmlSchemaSetValidOptions(vptr, valid_opts); xmlSchemaSetValidErrors(vptr, php_libxml_error_handler, php_libxml_error_handler, vptr); is_valid = xmlSchemaValidateDoc(vptr, docp); xmlSchemaFree(sptr); xmlSchemaFreeValidCtxt(vptr); + PHP_LIBXML_RESTORE_GLOBALS(validate); if (is_valid == 0) { RETURN_TRUE; @@ -1802,12 +1814,14 @@ static void _dom_document_relaxNG_validate(INTERNAL_FUNCTION_PARAMETERS, int typ return; } + PHP_LIBXML_SANITIZE_GLOBALS(parse); xmlRelaxNGSetParserErrors(parser, (xmlRelaxNGValidityErrorFunc) php_libxml_error_handler, (xmlRelaxNGValidityWarningFunc) php_libxml_error_handler, parser); sptr = xmlRelaxNGParse(parser); xmlRelaxNGFreeParserCtxt(parser); + PHP_LIBXML_RESTORE_GLOBALS(parse); if (!sptr) { php_error_docref(NULL, E_WARNING, "Invalid RelaxNG"); RETURN_FALSE; @@ -1903,6 +1917,7 @@ static void dom_load_html(INTERNAL_FUNCTION_PARAMETERS, int mode) /* {{{ */ ctxt->sax->error = php_libxml_ctx_error; ctxt->sax->warning = php_libxml_ctx_warning; } + php_libxml_sanitize_parse_ctxt_options(ctxt); if (options) { htmlCtxtUseOptions(ctxt, (int)options); } diff --git a/ext/dom/documentfragment.c b/ext/dom/documentfragment.c index 36265293ae3..4b832e0574c 100644 --- a/ext/dom/documentfragment.c +++ b/ext/dom/documentfragment.c @@ -80,7 +80,9 @@ PHP_METHOD(DOMDocumentFragment, appendXML) { } if (data) { + PHP_LIBXML_SANITIZE_GLOBALS(parse); err = xmlParseBalancedChunkMemory(nodep->doc, NULL, NULL, 0, (xmlChar *) data, &lst); + PHP_LIBXML_RESTORE_GLOBALS(parse); if (err != 0) { RETURN_FALSE; } diff --git a/ext/dom/tests/libxml_global_state_entity_loader_bypass.phpt b/ext/dom/tests/libxml_global_state_entity_loader_bypass.phpt new file mode 100644 index 00000000000..b28afd4694e --- /dev/null +++ b/ext/dom/tests/libxml_global_state_entity_loader_bypass.phpt @@ -0,0 +1,36 @@ +--TEST-- +GHSA-3qrf-m4j2-pcrr (libxml global state entity loader bypass) +--SKIPIF-- + +--FILE-- + %bork;]>"; + +libxml_use_internal_errors(true); + +function parseXML($xml) { + $doc = new DOMDocument(); + @$doc->loadXML($xml); + $doc->createDocumentFragment()->appendXML("&bork;"); + foreach (libxml_get_errors() as $error) { + var_dump(trim($error->message)); + } +} + +parseXML($xml); +zend_test_override_libxml_global_state(); +parseXML($xml); + +echo "Done\n"; + +?> +--EXPECT-- +string(25) "Entity 'bork' not defined" +string(25) "Entity 'bork' not defined" +string(25) "Entity 'bork' not defined" +Done diff --git a/ext/libxml/php_libxml.h b/ext/libxml/php_libxml.h index 6ffb076c63d..3bd5202f587 100644 --- a/ext/libxml/php_libxml.h +++ b/ext/libxml/php_libxml.h @@ -145,6 +145,42 @@ PHP_LIBXML_API void php_libxml_shutdown(void); ZEND_TSRMLS_CACHE_EXTERN() #endif +/* Other extension may override the global state options, these global options + * are copied initially to ctxt->options. Set the options to a known good value. + * See libxml2 globals.c and parserInternals.c. + * The unique_name argument allows multiple sanitizes and restores within the + * same function, even nested is necessary. */ +#define PHP_LIBXML_SANITIZE_GLOBALS(unique_name) \ + int xml_old_loadsubset_##unique_name = xmlLoadExtDtdDefaultValue; \ + xmlLoadExtDtdDefaultValue = 0; \ + int xml_old_validate_##unique_name = xmlDoValidityCheckingDefaultValue; \ + xmlDoValidityCheckingDefaultValue = 0; \ + int xml_old_pedantic_##unique_name = xmlPedanticParserDefault(0); \ + int xml_old_substitute_##unique_name = xmlSubstituteEntitiesDefault(0); \ + int xml_old_linenrs_##unique_name = xmlLineNumbersDefault(0); \ + int xml_old_blanks_##unique_name = xmlKeepBlanksDefault(1); + +#define PHP_LIBXML_RESTORE_GLOBALS(unique_name) \ + xmlLoadExtDtdDefaultValue = xml_old_loadsubset_##unique_name; \ + xmlDoValidityCheckingDefaultValue = xml_old_validate_##unique_name; \ + (void) xmlPedanticParserDefault(xml_old_pedantic_##unique_name); \ + (void) xmlSubstituteEntitiesDefault(xml_old_substitute_##unique_name); \ + (void) xmlLineNumbersDefault(xml_old_linenrs_##unique_name); \ + (void) xmlKeepBlanksDefault(xml_old_blanks_##unique_name); + +/* Alternative for above, working directly on the context and not setting globals. + * Generally faster because no locking is involved, and this has the advantage that it sets the options to a known good value. */ +static zend_always_inline void php_libxml_sanitize_parse_ctxt_options(xmlParserCtxtPtr ctxt) +{ + ctxt->loadsubset = 0; + ctxt->validate = 0; + ctxt->pedantic = 0; + ctxt->replaceEntities = 0; + ctxt->linenumbers = 0; + ctxt->keepBlanks = 1; + ctxt->options = 0; +} + #else /* HAVE_LIBXML */ #define libxml_module_ptr NULL #endif diff --git a/ext/phar/dirstream.c b/ext/phar/dirstream.c index d7fda32de04..ab6986c8ef2 100644 --- a/ext/phar/dirstream.c +++ b/ext/phar/dirstream.c @@ -89,26 +89,28 @@ static int phar_dir_seek(php_stream *stream, zend_off_t offset, int whence, zend */ static ssize_t phar_dir_read(php_stream *stream, char *buf, size_t count) /* {{{ */ { - size_t to_read; HashTable *data = (HashTable *)stream->abstract; zend_string *str_key; zend_ulong unused; + if (count != sizeof(php_stream_dirent)) { + return -1; + } + if (HASH_KEY_NON_EXISTENT == zend_hash_get_current_key(data, &str_key, &unused)) { return 0; } zend_hash_move_forward(data); - to_read = MIN(ZSTR_LEN(str_key), count); - if (to_read == 0 || count < ZSTR_LEN(str_key)) { + php_stream_dirent *dirent = (php_stream_dirent *) buf; + + if (sizeof(dirent->d_name) <= ZSTR_LEN(str_key)) { return 0; } - memset(buf, 0, sizeof(php_stream_dirent)); - memcpy(((php_stream_dirent *) buf)->d_name, ZSTR_VAL(str_key), to_read); - ((php_stream_dirent *) buf)->d_name[to_read + 1] = '\0'; - ((php_stream_dirent *) buf)->d_type = DT_UNKNOWN; + memset(dirent, 0, sizeof(php_stream_dirent)); + PHP_STRLCPY(dirent->d_name, ZSTR_VAL(str_key), sizeof(dirent->d_name), ZSTR_LEN(str_key)); return sizeof(php_stream_dirent); } diff --git a/ext/phar/tests/GHSA-jqcx-ccgc-xwhv.phpt b/ext/phar/tests/GHSA-jqcx-ccgc-xwhv.phpt new file mode 100644 index 00000000000..4e12f05fb62 --- /dev/null +++ b/ext/phar/tests/GHSA-jqcx-ccgc-xwhv.phpt @@ -0,0 +1,27 @@ +--TEST-- +GHSA-jqcx-ccgc-xwhv (Buffer overflow and overread in phar_dir_read()) +--SKIPIF-- + +--INI-- +phar.readonly=0 +--FILE-- +startBuffering(); +$phar->addFromString(str_repeat('A', PHP_MAXPATHLEN - 1), 'This is the content of file 1.'); +$phar->addFromString(str_repeat('B', PHP_MAXPATHLEN - 1).'C', 'This is the content of file 2.'); +$phar->stopBuffering(); + +$handle = opendir('phar://' . __DIR__ . '/GHSA-jqcx-ccgc-xwhv.phar'); +var_dump(strlen(readdir($handle))); +// Must not be a string of length PHP_MAXPATHLEN+1 +var_dump(readdir($handle)); +closedir($handle); +?> +--CLEAN-- + +--EXPECTF-- +int(%d) +bool(false) diff --git a/ext/simplexml/simplexml.c b/ext/simplexml/simplexml.c index 6996474e49e..e03a61cd66e 100644 --- a/ext/simplexml/simplexml.c +++ b/ext/simplexml/simplexml.c @@ -2256,7 +2256,9 @@ PHP_FUNCTION(simplexml_load_file) RETURN_THROWS(); } + PHP_LIBXML_SANITIZE_GLOBALS(read_file); docp = xmlReadFile(filename, NULL, (int)options); + PHP_LIBXML_RESTORE_GLOBALS(read_file); if (!docp) { RETURN_FALSE; @@ -2309,7 +2311,9 @@ PHP_FUNCTION(simplexml_load_string) RETURN_THROWS(); } + PHP_LIBXML_SANITIZE_GLOBALS(read_memory); docp = xmlReadMemory(data, (int)data_len, NULL, NULL, (int)options); + PHP_LIBXML_RESTORE_GLOBALS(read_memory); if (!docp) { RETURN_FALSE; @@ -2358,7 +2362,9 @@ PHP_METHOD(SimpleXMLElement, __construct) RETURN_THROWS(); } + PHP_LIBXML_SANITIZE_GLOBALS(read_file_or_memory); docp = is_url ? xmlReadFile(data, NULL, (int)options) : xmlReadMemory(data, (int)data_len, NULL, NULL, (int)options); + PHP_LIBXML_RESTORE_GLOBALS(read_file_or_memory); if (!docp) { ((php_libxml_node_object *)sxe)->document = NULL; diff --git a/ext/simplexml/tests/libxml_global_state_entity_loader_bypass.phpt b/ext/simplexml/tests/libxml_global_state_entity_loader_bypass.phpt new file mode 100644 index 00000000000..2152e012328 --- /dev/null +++ b/ext/simplexml/tests/libxml_global_state_entity_loader_bypass.phpt @@ -0,0 +1,36 @@ +--TEST-- +GHSA-3qrf-m4j2-pcrr (libxml global state entity loader bypass) +--SKIPIF-- + +--FILE-- + %bork;]>"; + +libxml_use_internal_errors(true); +zend_test_override_libxml_global_state(); + +echo "--- String test ---\n"; +simplexml_load_string($xml); +echo "--- Constructor test ---\n"; +new SimpleXMLElement($xml); +echo "--- File test ---\n"; +file_put_contents("libxml_global_state_entity_loader_bypass.tmp", $xml); +simplexml_load_file("libxml_global_state_entity_loader_bypass.tmp"); + +echo "Done\n"; + +?> +--CLEAN-- + +--EXPECT-- +--- String test --- +--- Constructor test --- +--- File test --- +Done diff --git a/ext/soap/php_xml.c b/ext/soap/php_xml.c index a847059cd40..3ff7aa055fd 100644 --- a/ext/soap/php_xml.c +++ b/ext/soap/php_xml.c @@ -91,6 +91,7 @@ xmlDocPtr soap_xmlParseFile(const char *filename) if (ctxt) { bool old; + php_libxml_sanitize_parse_ctxt_options(ctxt); ctxt->keepBlanks = 0; ctxt->sax->ignorableWhitespace = soap_ignorableWhitespace; ctxt->sax->comment = soap_Comment; @@ -139,6 +140,7 @@ xmlDocPtr soap_xmlParseMemory(const void *buf, size_t buf_size) if (ctxt) { bool old; + php_libxml_sanitize_parse_ctxt_options(ctxt); ctxt->sax->ignorableWhitespace = soap_ignorableWhitespace; ctxt->sax->comment = soap_Comment; ctxt->sax->warning = NULL; diff --git a/ext/xml/compat.c b/ext/xml/compat.c index d3b3f0bf345..5c41e7d2f5d 100644 --- a/ext/xml/compat.c +++ b/ext/xml/compat.c @@ -17,6 +17,7 @@ #include "php.h" #if defined(HAVE_LIBXML) && (defined(HAVE_XML) || defined(HAVE_XMLRPC)) && !defined(HAVE_LIBEXPAT) #include "expat_compat.h" +#include "ext/libxml/php_libxml.h" typedef struct _php_xml_ns { xmlNsPtr nsptr; @@ -469,6 +470,7 @@ XML_ParserCreate_MM(const XML_Char *encoding, const XML_Memory_Handling_Suite *m return NULL; } + php_libxml_sanitize_parse_ctxt_options(parser->parser); xmlCtxtUseOptions(parser->parser, XML_PARSE_OLDSAX); parser->parser->replaceEntities = 1; diff --git a/ext/xmlreader/php_xmlreader.c b/ext/xmlreader/php_xmlreader.c index b10a849e59a..137c12f7151 100644 --- a/ext/xmlreader/php_xmlreader.c +++ b/ext/xmlreader/php_xmlreader.c @@ -283,6 +283,7 @@ static xmlRelaxNGPtr _xmlreader_get_relaxNG(char *source, size_t source_len, siz return NULL; } + PHP_LIBXML_SANITIZE_GLOBALS(parse); if (error_func || warn_func) { xmlRelaxNGSetParserErrors(parser, (xmlRelaxNGValidityErrorFunc) error_func, @@ -291,6 +292,7 @@ static xmlRelaxNGPtr _xmlreader_get_relaxNG(char *source, size_t source_len, siz } sptr = xmlRelaxNGParse(parser); xmlRelaxNGFreeParserCtxt(parser); + PHP_LIBXML_RESTORE_GLOBALS(parse); return sptr; } @@ -865,7 +867,9 @@ PHP_METHOD(XMLReader, open) valid_file = _xmlreader_get_valid_file_path(source, resolved_path, MAXPATHLEN ); if (valid_file) { + PHP_LIBXML_SANITIZE_GLOBALS(reader_for_file); reader = xmlReaderForFile(valid_file, encoding, options); + PHP_LIBXML_RESTORE_GLOBALS(reader_for_file); } if (reader == NULL) { @@ -937,8 +941,10 @@ PHP_METHOD(XMLReader, setSchema) id = ZEND_THIS; intern = Z_XMLREADER_P(id); - if (intern->ptr) { + if (intern && intern->ptr) { + PHP_LIBXML_SANITIZE_GLOBALS(schema); retval = xmlTextReaderSchemaValidate(intern->ptr, source); + PHP_LIBXML_RESTORE_GLOBALS(schema); if (retval == 0) { RETURN_TRUE; @@ -1059,6 +1065,7 @@ PHP_METHOD(XMLReader, XML) } uri = (char *) xmlCanonicPath((const xmlChar *) resolved_path); } + PHP_LIBXML_SANITIZE_GLOBALS(text_reader); reader = xmlNewTextReader(inputbfr, uri); if (reader != NULL) { @@ -1077,9 +1084,11 @@ PHP_METHOD(XMLReader, XML) xmlFree(uri); } + PHP_LIBXML_RESTORE_GLOBALS(text_reader); return; } } + PHP_LIBXML_RESTORE_GLOBALS(text_reader); } if (uri) { diff --git a/ext/xmlreader/tests/libxml_global_state_entity_loader_bypass.phpt b/ext/xmlreader/tests/libxml_global_state_entity_loader_bypass.phpt new file mode 100644 index 00000000000..e9ffb04c2bb --- /dev/null +++ b/ext/xmlreader/tests/libxml_global_state_entity_loader_bypass.phpt @@ -0,0 +1,35 @@ +--TEST-- +GHSA-3qrf-m4j2-pcrr (libxml global state entity loader bypass) +--SKIPIF-- + +--FILE-- + %bork;]>"; + +libxml_use_internal_errors(true); +zend_test_override_libxml_global_state(); + +echo "--- String test ---\n"; +$reader = XMLReader::xml($xml); +$reader->read(); +echo "--- File test ---\n"; +file_put_contents("libxml_global_state_entity_loader_bypass.tmp", $xml); +$reader = XMLReader::open("libxml_global_state_entity_loader_bypass.tmp"); +$reader->read(); + +echo "Done\n"; + +?> +--CLEAN-- + +--EXPECT-- +--- String test --- +--- File test --- +Done diff --git a/ext/xsl/xsltprocessor.c b/ext/xsl/xsltprocessor.c index 5f1482ea31b..70223458a54 100644 --- a/ext/xsl/xsltprocessor.c +++ b/ext/xsl/xsltprocessor.c @@ -320,7 +320,7 @@ PHP_METHOD(XSLTProcessor, importStylesheet) xmlDoc *doc = NULL, *newdoc = NULL; xsltStylesheetPtr sheetp, oldsheetp; xsl_object *intern; - int prevSubstValue, prevExtDtdValue, clone_docu = 0; + int clone_docu = 0; xmlNode *nodep = NULL; zval *cloneDocu, rv; zend_string *member; @@ -344,13 +344,12 @@ PHP_METHOD(XSLTProcessor, importStylesheet) stylesheet document otherwise the node proxies will be a mess */ newdoc = xmlCopyDoc(doc, 1); xmlNodeSetBase((xmlNodePtr) newdoc, (xmlChar *)doc->URL); - prevSubstValue = xmlSubstituteEntitiesDefault(1); - prevExtDtdValue = xmlLoadExtDtdDefaultValue; + PHP_LIBXML_SANITIZE_GLOBALS(parse); + xmlSubstituteEntitiesDefault(1); xmlLoadExtDtdDefaultValue = XML_DETECT_IDS | XML_COMPLETE_ATTRS; sheetp = xsltParseStylesheetDoc(newdoc); - xmlSubstituteEntitiesDefault(prevSubstValue); - xmlLoadExtDtdDefaultValue = prevExtDtdValue; + PHP_LIBXML_RESTORE_GLOBALS(parse); if (!sheetp) { xmlFreeDoc(newdoc); diff --git a/ext/zend_test/test.c b/ext/zend_test/test.c index cf6005ea083..eda4feb08cb 100644 --- a/ext/zend_test/test.c +++ b/ext/zend_test/test.c @@ -33,6 +33,27 @@ #include "zend_call_stack.h" #include "zend_exceptions.h" +#ifdef HAVE_LIBXML +# include +# include +#endif + +ZEND_BEGIN_MODULE_GLOBALS(zend_test) + int observer_enabled; + int observer_show_output; + int observer_observe_all; + int observer_observe_includes; + int observer_observe_functions; + zend_array *observer_observe_function_names; + int observer_show_return_type; + int observer_show_return_value; + int observer_show_init_backtrace; + int observer_show_opcode; + int observer_nesting_depth; + int replace_zend_execute_ex; + HashTable global_weakmap; +ZEND_END_MODULE_GLOBALS(zend_test) + ZEND_DECLARE_MODULE_GLOBALS(zend_test) static zend_class_entry *zend_test_interface; @@ -353,6 +374,18 @@ static ZEND_FUNCTION(zend_get_current_func_name) RETURN_STR(function_name); } +static ZEND_FUNCTION(zend_test_override_libxml_global_state) +{ + ZEND_PARSE_PARAMETERS_NONE(); + + xmlLoadExtDtdDefaultValue = 1; + xmlDoValidityCheckingDefaultValue = 1; + (void) xmlPedanticParserDefault(1); + (void) xmlSubstituteEntitiesDefault(1); + (void) xmlLineNumbersDefault(1); + (void) xmlKeepBlanksDefault(0); +} + /* TESTS Z_PARAM_ITERABLE and Z_PARAM_ITERABLE_OR_NULL */ static ZEND_FUNCTION(zend_iterable) { diff --git a/ext/zend_test/test.stub.php b/ext/zend_test/test.stub.php index 6da31580d06..e1172d2e6ef 100644 --- a/ext/zend_test/test.stub.php +++ b/ext/zend_test/test.stub.php @@ -226,6 +226,10 @@ namespace { function zend_test_create_throwing_resource() {} function get_open_basedir(): ?string {} + +#ifdef HAVE_LIBXML + function zend_test_override_libxml_global_state(): void {} +#endif } namespace ZendTestNS { diff --git a/ext/zend_test/test_arginfo.h b/ext/zend_test/test_arginfo.h index 575044bd2b4..65849349a3f 100644 --- a/ext/zend_test/test_arginfo.h +++ b/ext/zend_test/test_arginfo.h @@ -139,6 +139,14 @@ ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_ZendTestNS2_namespaced_func, 0, 0, _IS_BOOL, 0) ZEND_END_ARG_INFO() +#if defined(HAVE_LIBXML) +ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_zend_test_override_libxml_global_state, 0, 0, IS_VOID, 0) +ZEND_END_ARG_INFO() +#endif + +ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_ZendTestNS2_ZendSubNS_namespaced_func, 0, 0, _IS_BOOL, 0) +ZEND_END_ARG_INFO() + #define arginfo_ZendTestNS2_namespaced_deprecated_func arginfo_zend_test_void_return #define arginfo_ZendTestNS2_namespaced_aliased_func arginfo_zend_test_void_return @@ -259,6 +267,10 @@ static ZEND_FUNCTION(ZendTestNS2_namespaced_func); static ZEND_FUNCTION(ZendTestNS2_namespaced_deprecated_func); static ZEND_FUNCTION(ZendTestNS2_ZendSubNS_namespaced_func); static ZEND_FUNCTION(ZendTestNS2_ZendSubNS_namespaced_deprecated_func); +#if defined(HAVE_LIBXML) +static ZEND_FUNCTION(zend_test_override_libxml_global_state); +#endif +static ZEND_FUNCTION(namespaced_func); static ZEND_METHOD(_ZendTestClass, is_object); static ZEND_METHOD(_ZendTestClass, __toString); static ZEND_METHOD(_ZendTestClass, returnsStatic); @@ -332,6 +344,10 @@ static const zend_function_entry ext_functions[] = { ZEND_NS_DEP_FALIAS("ZendTestNS2\\ZendSubNS", namespaced_deprecated_func, ZendTestNS2_ZendSubNS_namespaced_deprecated_func, arginfo_ZendTestNS2_ZendSubNS_namespaced_deprecated_func) ZEND_NS_FALIAS("ZendTestNS2\\ZendSubNS", namespaced_aliased_func, zend_test_void_return, arginfo_ZendTestNS2_ZendSubNS_namespaced_aliased_func) ZEND_NS_DEP_FALIAS("ZendTestNS2\\ZendSubNS", namespaced_deprecated_aliased_func, zend_test_void_return, arginfo_ZendTestNS2_ZendSubNS_namespaced_deprecated_aliased_func) + ZEND_NS_FE("ZendTestNS2\\ZendSubNS", namespaced_func, arginfo_ZendTestNS2_ZendSubNS_namespaced_func) +#if defined(HAVE_LIBXML) + ZEND_FE(zend_test_override_libxml_global_state, arginfo_zend_test_override_libxml_global_state) +#endif ZEND_FE_END };