A bunch of different issues:
1) The referenced value is copied without incrementing the refcount.
The reason the refcount isn't incremented is because otherwise
the array modifications would violate the RC1 constraints.
Solve this by copying the reference itself instead and always
read the referenced value.
2) No type checks on the array data, so malicious scripts could
cause type confusion bugs.
3) Potential overflow when the arrays resize and we access ctag.
Closes GH-17205.
Upon unwinding from an exception, the parser state is not stable, we
should not continue updating the values if an exception was thrown.
Closes GH-15879.
Upon unwinding from an exception, the parser state is not stable, we
should not continue updating the values if an exception was thrown.
Closes GH-15879.
libxml2 2.13 makes changes to how the parsing state is set, update our
code accordingly. In particular, it started reporting entities within
attributes, while it should only report entities inside text nodes.
Closes GH-14837.
The reflection failure is because the XML extension is used to check the
module dependency information, but that extension can be configured to
not depend on ext/libxml, resulting in a different output. The solution
is to check another extension instead.
The test failures in ext/xml/tests are because of different behaviour
between libxml2 and Expat error handling. These are expected differences
and the solution is to split the tests.
Closes GH-13522.
It's possible to categorise the failures into 2 categories:
- Changed error message. In this case we either duplicate the test and
modify the error message. Or if the change in error message is
small, we use the EXPECTF matchers to make the test compatible with both
old and new versions of libxml2.
- Missing warnings. This is caused by a change in libxml2 where the
parser started using SAX APIs internally [1]. In this case the
error_type passed to php_libxml_internal_error_handler() changed from
PHP_LIBXML_ERROR to PHP_LIBXML_CTX_WARNING because it internally
started to use the SAX handlers instead of the generic handlers.
However, for the SAX handlers the current input stack is empty, so
nothing is actually printed. I fixed this by falling back to a
regular warning without a filename & line number reference, which
mimicks the old behaviour. Furthermore, this change now also shows
an additional warning in a test which was previously hidden.
[1] 9a82b94a94
Closes GH-11162.
We must never strip embedded whitespace; we only need to skip values
when that option is set, and make sure that we keep BC regarding the
different behavior for "cdata" and "complete" elements (for the former,
the whole element is skipped; for the latter only the "value" key).
We also fix erroneous `int` types which should actually be `size_t`.
Co-authored-by: Christoph M. Becker <cmbecker69@gmx.de>
Closes GH-7493.
This API had rather peculiar behavior in case the provided function
is not callable. For some types of failures, it would silently
return FAILURE (e.g. a function does not exist), while for others
(e.g. a class does not exist) it would generate a warning. Depending
on what the calling code does, this can either result in silent
failure or duplicate errors.
This commit switches the contract such that zend_call_function()
always (*) succeeds, though that success might be in the form of
throwing an exception. Calling a non-callable will now consistently
throw an exception.
There are some rare callers that do want to ignore missing methods,
for legacy APIs that are specific with optional methods. For these
use cases a new zend_call_method_if_exists() API is provided.
Calling code generally does not need to explicitly check for and
report zend_call_function() failures -- it can rely on
zend_call_function() having already done so. However, existing
code that does check for failure should continue to work fine.
(*) The only exception to this is if EG(active) being false during
late engine shutdown. This is not relevant to most code, but code
running in destructors and similar may need to be aware of the
possibility.
As of PHP 8.0.0, these functions are supposed to return int, so we
cannot return `false`. Since calling the parser recursively is a
programmer error, we throw an `Error` in this case.
Cf. <https://github.com/php/php-src/pull/7363>.
The fix for bug #73151[1] cured the symptoms, but not the root cause,
namely xmlParse() must not be called recursively. Since that bugfix
also messed up the error handling, we basically revert it (but also
simplify the return), and then prevent calling the parser recursively.
[1] <f2a8a8c068>
Co-authored-by: Nikita Popov <nikita.ppv@gmail.com>
Closes GH-7363.
We must not call `zend_list_delete()` in resource closer functions
exposed to userland, because decreasing the refcount there leads to
use-after-free scenarios. In this case, commit 4a42fbb worked for
typical use-cases where `xml_parser_free()` has been called exactly
once for the resource, because there is an internal zval (`->index`)
referencing the same resource which already increased the refcount by
one. However, when `xml_parser_free()` is called multiple times on the
same XML parser resource, the resource would be freed prematurely.
Instead we forcefully close the resource in `xml_parser_free()`. We
also could decrease the refcount of the resource there, but that would
require to call `xml_parser_free()` which is somewhat uncommon, and
would be particularly bad wrt. PHP 8 where that function is a NOP, and
as such doesn't have to be called. So we do no longer increase the
refcount of the resource when copying it to the internal zval, and let
the usualy refcounting semantics take care of the resource destruction.
[1] <http://git.php.net/?p=php-src.git;a=commit;h=4a42fbbbc73aad7427aef5c89974d1833636e082>