From 8b5ead371eda7708f4b6a39f309d1b179eda5912 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A1t=C3=A9=20Kocsis?= Date: Sat, 6 Sep 2025 23:00:18 +0200 Subject: [PATCH] Do not copy the normalized URI when cloning RFC 3986 URIs - alternative approach --- ext/uri/php_uri.c | 8 +++++++- ext/uri/php_uri_common.h | 3 ++- ext/uri/uri_parser_rfc3986.c | 10 +++++----- ext/uri/uri_parser_whatwg.c | 2 +- 4 files changed, 15 insertions(+), 8 deletions(-) diff --git a/ext/uri/php_uri.c b/ext/uri/php_uri.c index a0e264f04f3e2..242223efc3bcd 100644 --- a/ext/uri/php_uri.c +++ b/ext/uri/php_uri.c @@ -990,7 +990,13 @@ zend_object *uri_clone_obj_handler(zend_object *object) new_uri_object->internal.parser = internal_uri->parser; - void *uri = internal_uri->parser->clone_uri(internal_uri->uri); + zend_execute_data *execute_data = EG(current_execute_data); + bool is_clone_op = execute_data != NULL && + execute_data->func && + ZEND_USER_CODE(execute_data->func->type) && + execute_data->opline != NULL && + execute_data->opline->opcode == ZEND_CLONE; + void *uri = internal_uri->parser->clone_uri(internal_uri->uri, is_clone_op == false); ZEND_ASSERT(uri != NULL); new_uri_object->internal.uri = uri; diff --git a/ext/uri/php_uri_common.h b/ext/uri/php_uri_common.h index 2c461ab3fb0a4..b651af48bada1 100644 --- a/ext/uri/php_uri_common.h +++ b/ext/uri/php_uri_common.h @@ -99,9 +99,10 @@ typedef struct uri_parser_t { * * A deep-clone must be performed that copies all pointer members to a new memory address. * @param uri The input URI + * @param is_modified_after_cloning If the handler is called by a wither method that modifies the URI * @return The cloned URI */ - void *(*clone_uri)(void *uri); + void *(*clone_uri)(void *uri, bool is_modified_after_cloning); /** * Recomposes a URI as a string according to the recomposition_mode and exclude_fragment parameters. diff --git a/ext/uri/uri_parser_rfc3986.c b/ext/uri/uri_parser_rfc3986.c index 7a004a41b0a8f..a788d84444dc5 100644 --- a/ext/uri/uri_parser_rfc3986.c +++ b/ext/uri/uri_parser_rfc3986.c @@ -353,16 +353,16 @@ void *php_uri_parser_rfc3986_parse(const char *uri_str, size_t uri_str_len, cons return php_uri_parser_rfc3986_parse_ex(uri_str, uri_str_len, base_url, silent); } -/* When calling a wither successfully, the normalized URI is surely invalidated, therefore - * it doesn't make sense to copy it. In case of failure, an exception is thrown, and the URI object - * is discarded altogether. */ -ZEND_ATTRIBUTE_NONNULL static void *php_uri_parser_rfc3986_clone(void *uri) +ZEND_ATTRIBUTE_NONNULL static void *php_uri_parser_rfc3986_clone(void *uri, bool is_modified_after_cloning) { const php_uri_parser_rfc3986_uris *uriparser_uris = uri; php_uri_parser_rfc3986_uris *new_uriparser_uris = uriparser_create_uris(); copy_uri(&new_uriparser_uris->uri, &uriparser_uris->uri); - if (uriparser_uris->normalized_uri_initialized) { + /* Only copy the normalized URI if cloning won't immediately modify the URI, + * thus invalidating the normalized URI. This is the case when the call comes from + * a wither method. */ + if (is_modified_after_cloning == false && uriparser_uris->normalized_uri_initialized) { copy_uri(&new_uriparser_uris->normalized_uri, &uriparser_uris->normalized_uri); new_uriparser_uris->normalized_uri_initialized = true; } diff --git a/ext/uri/uri_parser_whatwg.c b/ext/uri/uri_parser_whatwg.c index 1403fe262b13c..02049c5293009 100644 --- a/ext/uri/uri_parser_whatwg.c +++ b/ext/uri/uri_parser_whatwg.c @@ -576,7 +576,7 @@ static void *php_uri_parser_whatwg_parse(const char *uri_str, size_t uri_str_len return php_uri_parser_whatwg_parse_ex(uri_str, uri_str_len, base_url, errors, silent); } -static void *php_uri_parser_whatwg_clone(void *uri) +static void *php_uri_parser_whatwg_clone(void *uri, bool is_modified_after_cloning) { const lxb_url_t *lexbor_uri = uri;