1
0
mirror of https://github.com/php/php-src.git synced 2026-03-24 00:02:20 +01:00

uri: Fix handling of the errors == NULL && !silent for uri_parser_whatwg (#19748)

* uri: Fix handling of the `errors == NULL && !silent` for uri_parser_whatwg

Previously, when `errors` was `NULL`, the `errors` pointer was used to set the
`$errors` property when throwing the exception, leading to a crash. Use a local
zval to pass the errors to the Exception and copy it into the `errors` input
when it is non-`NULL`.

* uri: Only pass the `errors` zval when interested in it in `php_uri_instantiate_uri()`

This is no longer necessary since the previous commit and also is a layering
violation, since `php_uri_instantiate_uri()` should not care how `parse_uri()`
works internally.

* uri: Use `ZVAL_EMPTY_ARRAY()` when no parsing errors are available

* uri: Avoid redundant refcounting in error handling of uri_parser_whatwg

* NEWS
This commit is contained in:
Tim Düsterhus
2025-09-09 00:10:39 +02:00
committed by GitHub
parent 79eca3f2bf
commit 156c847467
4 changed files with 57 additions and 15 deletions

2
NEWS
View File

@@ -87,6 +87,8 @@ PHP NEWS
(timwolla)
. Return null instead of 0 for Uri\Rfc3986\Uri::getPort() when the
URI contains an empty port. (timwolla)
. Fixed creation of the InvalidUrlException when not passing an
errors zval to the internal whatwg parser. (timwolla)
. Clean up naming of internal API. (timwolla)
28 Aug 2025, PHP 8.5.0beta2

View File

@@ -360,7 +360,7 @@ ZEND_ATTRIBUTE_NONNULL_ARGS(1, 2) PHPAPI void php_uri_instantiate_uri(
base_url = internal_base_url->uri;
}
void *uri = uri_parser->parse_uri(ZSTR_VAL(uri_str), ZSTR_LEN(uri_str), base_url, should_throw || errors_zv != NULL ? &errors : NULL, !should_throw);
void *uri = uri_parser->parse_uri(ZSTR_VAL(uri_str), ZSTR_LEN(uri_str), base_url, errors_zv != NULL ? &errors : NULL, !should_throw);
if (UNEXPECTED(uri == NULL)) {
if (should_throw) {
zval_ptr_dtor(&errors);

29
ext/uri/tests/101.phpt Normal file
View File

@@ -0,0 +1,29 @@
--TEST--
Test the Lexbor-based URI parser
--EXTENSIONS--
uri
zend_test
--FILE--
<?php
try {
var_dump(zend_test_uri_parser('invalid uri', "Uri\\WhatWg\\Url"));
} catch (\Uri\WhatWg\InvalidUrlException $e) {
echo $e->getMessage(), PHP_EOL;
var_dump($e->errors);
}
?>
--EXPECTF--
The specified URI is malformed (MissingSchemeNonRelativeUrl)
array(1) {
[0]=>
object(Uri\WhatWg\UrlValidationError)#%d (3) {
["context"]=>
string(11) "invalid uri"
["type"]=>
enum(Uri\WhatWg\UrlValidationErrorType::MissingSchemeNonRelativeUrl)
["failure"]=>
bool(true)
}
}

View File

@@ -65,19 +65,14 @@ static zend_always_inline void zval_long_or_null_to_lexbor_str(zval *value, lexb
*/
static const char *fill_errors(zval *errors)
{
if (errors == NULL) {
if (lexbor_parser.log == NULL || lexbor_plog_length(lexbor_parser.log) == 0) {
ZVAL_EMPTY_ARRAY(errors);
return NULL;
}
ZEND_ASSERT(Z_ISUNDEF_P(errors));
array_init(errors);
if (lexbor_parser.log == NULL) {
return NULL;
}
const char *result = NULL;
lexbor_plog_entry_t *lxb_error;
while ((lxb_error = lexbor_array_obj_pop(&lexbor_parser.log->list)) != NULL) {
zval error;
@@ -224,7 +219,8 @@ static const char *fill_errors(zval *errors)
static void throw_invalid_url_exception_during_write(zval *errors, const char *component)
{
const char *reason = fill_errors(errors);
zval err;
const char *reason = fill_errors(&err);
zend_object *exception = zend_throw_exception_ex(
uri_whatwg_invalid_url_exception_ce,
0,
@@ -234,7 +230,13 @@ static void throw_invalid_url_exception_during_write(zval *errors, const char *c
reason ? reason : "",
reason ? ")" : ""
);
zend_update_property(exception->ce, exception, ZEND_STRL("errors"), errors);
zend_update_property(exception->ce, exception, ZEND_STRL("errors"), &err);
if (errors) {
zval_ptr_dtor(errors);
ZVAL_COPY_VALUE(errors, &err);
} else {
zval_ptr_dtor(&err);
}
}
static lxb_status_t serialize_to_smart_str_callback(const lxb_char_t *data, size_t length, void *ctx)
@@ -561,11 +563,20 @@ lxb_url_t *php_uri_parser_whatwg_parse_ex(const char *uri_str, size_t uri_str_le
lxb_url_parser_clean(&lexbor_parser);
lxb_url_t *url = lxb_url_parse(&lexbor_parser, lexbor_base_url, (unsigned char *) uri_str, uri_str_len);
const char *reason = fill_errors(errors);
if (url == NULL && !silent) {
zend_object *exception = zend_throw_exception_ex(uri_whatwg_invalid_url_exception_ce, 0, "The specified URI is malformed%s%s%s", reason ? " (" : "", reason ? reason : "", reason ? ")" : "");
zend_update_property(exception->ce, exception, ZEND_STRL("errors"), errors);
if ((url == NULL && !silent) || errors != NULL) {
zval err;
const char *reason = fill_errors(&err);
if (url == NULL && !silent) {
zend_object *exception = zend_throw_exception_ex(uri_whatwg_invalid_url_exception_ce, 0, "The specified URI is malformed%s%s%s", reason ? " (" : "", reason ? reason : "", reason ? ")" : "");
zend_update_property(exception->ce, exception, ZEND_STRL("errors"), &err);
}
if (errors != NULL) {
zval_ptr_dtor(errors);
ZVAL_COPY_VALUE(errors, &err);
} else {
zval_ptr_dtor(&err);
}
}
return url;