diff --git a/ext/uri/php_uri.c b/ext/uri/php_uri.c index a09a93dbc0365..e5436d7f1e369 100644 --- a/ext/uri/php_uri.c +++ b/ext/uri/php_uri.c @@ -323,6 +323,10 @@ ZEND_ATTRIBUTE_NONNULL_ARGS(1, 2) PHPAPI void php_uri_instantiate_uri( uri_object_t *uri_object; if (should_update_this_object) { uri_object = Z_URI_OBJECT_P(ZEND_THIS); + if (uri_object->internal.uri != NULL) { + zend_throw_error(NULL, "Cannot modify readonly object of class %s", ZSTR_VAL(Z_OBJCE_P(ZEND_THIS)->name)); + RETURN_THROWS(); + } } else { if (EX(func)->common.fn_flags & ZEND_ACC_STATIC) { object_init_ex(return_value, Z_CE_P(ZEND_THIS)); @@ -842,7 +846,12 @@ static void uri_unserialize(INTERNAL_FUNCTION_PARAMETERS) } uri_internal_t *internal_uri = uri_internal_from_obj(object); - internal_uri->parser->free(internal_uri->uri); + if (internal_uri->uri != NULL) { + /* Intentionally throw two exceptions for proper chaining. */ + zend_throw_error(NULL, "Cannot modify readonly object of class %s", ZSTR_VAL(Z_OBJCE_P(ZEND_THIS)->name)); + zend_throw_exception_ex(NULL, 0, "Invalid serialization data for %s object", ZSTR_VAL(object->ce->name)); + RETURN_THROWS(); + } internal_uri->uri = internal_uri->parser->parse(Z_STRVAL_P(uri_zv), Z_STRLEN_P(uri_zv), NULL, NULL, true); if (internal_uri->uri == NULL) { zend_throw_exception_ex(NULL, 0, "Invalid serialization data for %s object", ZSTR_VAL(object->ce->name)); diff --git a/ext/uri/tests/065.phpt b/ext/uri/tests/065.phpt new file mode 100644 index 0000000000000..d9a6c905c9ef8 --- /dev/null +++ b/ext/uri/tests/065.phpt @@ -0,0 +1,117 @@ +--TEST-- +Test that overwriting the URI is not possible +--EXTENSIONS-- +uri +--FILE-- +__construct('ftp://example.org'); +} catch (Throwable $e) { + echo $e::class, ": ", $e->getMessage(), PHP_EOL; +} +var_dump($uri); + +$uri = new Uri\WhatWg\Url('https://example.com'); +try { + $uri->__unserialize([['uri' => 'ftp://example.org'], []]); +} catch (Throwable $e) { + echo $e::class, ": ", $e->getMessage(), PHP_EOL; +} +var_dump($uri); + +$uri = new Uri\Rfc3986\Uri('https://example.com'); +try { + $uri->__construct('ftp://example.org'); +} catch (Throwable $e) { + echo $e::class, ": ", $e->getMessage(), PHP_EOL; +} +var_dump($uri); + +$uri = new Uri\Rfc3986\Uri('https://example.com'); +try { + $uri->__unserialize([['uri' => 'ftp://example.org'], []]); +} catch (Throwable $e) { + echo $e::class, ": ", $e->getMessage(), PHP_EOL; +} +var_dump($uri); + +?> +--EXPECTF-- +Error: Cannot modify readonly object of class Uri\WhatWg\Url +object(Uri\WhatWg\Url)#%d (8) { + ["scheme"]=> + string(5) "https" + ["username"]=> + NULL + ["password"]=> + NULL + ["host"]=> + string(11) "example.com" + ["port"]=> + NULL + ["path"]=> + string(1) "/" + ["query"]=> + NULL + ["fragment"]=> + NULL +} +Exception: Invalid serialization data for Uri\WhatWg\Url object +object(Uri\WhatWg\Url)#%d (8) { + ["scheme"]=> + string(5) "https" + ["username"]=> + NULL + ["password"]=> + NULL + ["host"]=> + string(11) "example.com" + ["port"]=> + NULL + ["path"]=> + string(1) "/" + ["query"]=> + NULL + ["fragment"]=> + NULL +} +Error: Cannot modify readonly object of class Uri\Rfc3986\Uri +object(Uri\Rfc3986\Uri)#%d (8) { + ["scheme"]=> + string(5) "https" + ["username"]=> + NULL + ["password"]=> + NULL + ["host"]=> + string(11) "example.com" + ["port"]=> + NULL + ["path"]=> + string(0) "" + ["query"]=> + NULL + ["fragment"]=> + NULL +} +Exception: Invalid serialization data for Uri\Rfc3986\Uri object +object(Uri\Rfc3986\Uri)#%d (8) { + ["scheme"]=> + string(5) "https" + ["username"]=> + NULL + ["password"]=> + NULL + ["host"]=> + string(11) "example.com" + ["port"]=> + NULL + ["path"]=> + string(0) "" + ["query"]=> + NULL + ["fragment"]=> + NULL +}