From e2f30746715374d714182ec9d9ff824afbb370c2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim=20D=C3=BCsterhus?= Date: 2025年8月25日 20:53:55 +0200 Subject: [PATCH 1/2] uri: Simplify memory-management in `php_uri_parse()` We can try parsing before allocating the `uri_internal_t` struct. --- ext/uri/php_uri.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/ext/uri/php_uri.c b/ext/uri/php_uri.c index e5436d7f1e36..df865349edba 100644 --- a/ext/uri/php_uri.c +++ b/ext/uri/php_uri.c @@ -112,15 +112,16 @@ PHPAPI const php_uri_parser *php_uri_get_parser(zend_string *uri_parser_name) ZEND_ATTRIBUTE_NONNULL PHPAPI uri_internal_t *php_uri_parse(const php_uri_parser *uri_parser, const char *uri_str, size_t uri_str_len, bool silent) { - uri_internal_t *internal_uri = emalloc(sizeof(*internal_uri)); - internal_uri->parser = uri_parser; - internal_uri->uri = uri_parser->parse(uri_str, uri_str_len, NULL, NULL, silent); + void *parsed = uri_parser->parse(uri_str, uri_str_len, NULL, NULL, silent); - if (UNEXPECTED(internal_uri->uri == NULL)) { - efree(internal_uri); + if (parsed == NULL) { return NULL; } + uri_internal_t *internal_uri = emalloc(sizeof(*internal_uri)); + internal_uri->parser = uri_parser; + internal_uri->uri = parsed; + return internal_uri; } From 48c5abb424417080739903fd4c41f3a02dcfcf7a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim=20D=C3=BCsterhus?= Date: 2025年8月25日 20:57:32 +0200 Subject: [PATCH 2/2] uri: Remove `php_uri_parse()` and `php_uri_free()` This API is both less powerful as well as less efficient compared to just calling the `->parse_uri()` handler of the parser directly. With regard to efficiency it needlessly allocates 32 byte of memory to store two pointers, of which one is already known, because it's the input. While it would be possible to just return the resulting `uri_internal_t` struct (instead of a pointer to a freshly allocated one), which would be returned as a register pair, users of the API can also just create the struct themselves for even more flexibility in allocations. The API is also less powerful, because it does not support base URIs. --- ext/openssl/xp_ssl.c | 13 +++++++--- ext/uri/php_uri.c | 60 +++++++++++++++++--------------------------- ext/uri/php_uri.h | 9 ------- ext/zend_test/test.c | 44 ++++++++++++++++++-------------- 4 files changed, 57 insertions(+), 69 deletions(-) diff --git a/ext/openssl/xp_ssl.c b/ext/openssl/xp_ssl.c index 23f37355af56..fe6cc99038e2 100644 --- a/ext/openssl/xp_ssl.c +++ b/ext/openssl/xp_ssl.c @@ -2640,14 +2640,19 @@ static char *php_openssl_get_url_name(const char *resourcename, return NULL; } - uri_internal_t *internal_uri = php_uri_parse(uri_parser, resourcename, resourcenamelen, true); - if (internal_uri == NULL) { + void *parsed = uri_parser->parse(resourcename, resourcenamelen, + /* base_url */ NULL, /* errors */ NULL, /* silent */ true); + if (parsed == NULL) { return NULL; } + uri_internal_t internal_uri = { + .parser = uri_parser, + .uri = parsed, + }; char * url_name = NULL; zval host_zv; - zend_result result = php_uri_get_host(internal_uri, PHP_URI_COMPONENT_READ_MODE_RAW, &host_zv); + zend_result result = php_uri_get_host(&internal_uri, PHP_URI_COMPONENT_READ_MODE_RAW, &host_zv); if (result == SUCCESS && Z_TYPE(host_zv) == IS_STRING) { const char * host = Z_STRVAL(host_zv); size_t len = Z_STRLEN(host_zv); @@ -2662,7 +2667,7 @@ static char *php_openssl_get_url_name(const char *resourcename, } } - php_uri_free(internal_uri); + uri_parser->free(parsed); zval_ptr_dtor(&host_zv); return url_name; diff --git a/ext/uri/php_uri.c b/ext/uri/php_uri.c index df865349edba..388c15266704 100644 --- a/ext/uri/php_uri.c +++ b/ext/uri/php_uri.c @@ -110,21 +110,6 @@ PHPAPI const php_uri_parser *php_uri_get_parser(zend_string *uri_parser_name) return zend_hash_find_ptr(&uri_parsers, uri_parser_name); } -ZEND_ATTRIBUTE_NONNULL PHPAPI uri_internal_t *php_uri_parse(const php_uri_parser *uri_parser, const char *uri_str, size_t uri_str_len, bool silent) -{ - void *parsed = uri_parser->parse(uri_str, uri_str_len, NULL, NULL, silent); - - if (parsed == NULL) { - return NULL; - } - - uri_internal_t *internal_uri = emalloc(sizeof(*internal_uri)); - internal_uri->parser = uri_parser; - internal_uri->uri = parsed; - - return internal_uri; -} - ZEND_ATTRIBUTE_NONNULL PHPAPI zend_result php_uri_get_scheme(const uri_internal_t *internal_uri, php_uri_component_read_mode read_mode, zval *zv) { return internal_uri->parser->property_handler.scheme.read(internal_uri->uri, read_mode, zv); @@ -165,27 +150,25 @@ ZEND_ATTRIBUTE_NONNULL PHPAPI zend_result php_uri_get_fragment(const uri_interna return internal_uri->parser->property_handler.fragment.read(internal_uri->uri, read_mode, zv); } -ZEND_ATTRIBUTE_NONNULL PHPAPI void php_uri_free(uri_internal_t *internal_uri) -{ - internal_uri->parser->free(internal_uri->uri); - internal_uri->uri = NULL; - internal_uri->parser = NULL; - efree(internal_uri); -} - ZEND_ATTRIBUTE_NONNULL PHPAPI php_uri *php_uri_parse_to_struct( const php_uri_parser *uri_parser, const char *uri_str, size_t uri_str_len, php_uri_component_read_mode read_mode, bool silent ) { - uri_internal_t *uri_internal = php_uri_parse(uri_parser, uri_str, uri_str_len, silent); - if (uri_internal == NULL) { + void *parsed = uri_parser->parse(uri_str, uri_str_len, + /* base_url */ NULL, /* errors */ NULL, silent); + if (parsed == NULL) { return NULL; } + uri_internal_t uri_internal = { + .parser = uri_parser, + .uri = parsed, + }; + php_uri *uri = ecalloc(1, sizeof(*uri)); zval tmp; zend_result result; - result = php_uri_get_scheme(uri_internal, read_mode, &tmp); + result = php_uri_get_scheme(&uri_internal, read_mode, &tmp); if (result == FAILURE) { goto error; } @@ -193,7 +176,7 @@ ZEND_ATTRIBUTE_NONNULL PHPAPI php_uri *php_uri_parse_to_struct( uri->scheme = Z_STR(tmp); } - result = php_uri_get_username(uri_internal, read_mode, &tmp); + result = php_uri_get_username(&uri_internal, read_mode, &tmp); if (result == FAILURE) { goto error; } @@ -201,7 +184,7 @@ ZEND_ATTRIBUTE_NONNULL PHPAPI php_uri *php_uri_parse_to_struct( uri->user = Z_STR(tmp); } - result = php_uri_get_password(uri_internal, read_mode, &tmp); + result = php_uri_get_password(&uri_internal, read_mode, &tmp); if (result == FAILURE) { goto error; } @@ -209,7 +192,7 @@ ZEND_ATTRIBUTE_NONNULL PHPAPI php_uri *php_uri_parse_to_struct( uri->password = Z_STR(tmp); } - result = php_uri_get_host(uri_internal, read_mode, &tmp); + result = php_uri_get_host(&uri_internal, read_mode, &tmp); if (result == FAILURE) { goto error; } @@ -217,7 +200,7 @@ ZEND_ATTRIBUTE_NONNULL PHPAPI php_uri *php_uri_parse_to_struct( uri->host = Z_STR(tmp); } - result = php_uri_get_port(uri_internal, read_mode, &tmp); + result = php_uri_get_port(&uri_internal, read_mode, &tmp); if (result == FAILURE) { goto error; } @@ -225,7 +208,7 @@ ZEND_ATTRIBUTE_NONNULL PHPAPI php_uri *php_uri_parse_to_struct( uri->port = Z_LVAL(tmp); } - result = php_uri_get_path(uri_internal, read_mode, &tmp); + result = php_uri_get_path(&uri_internal, read_mode, &tmp); if (result == FAILURE) { goto error; } @@ -233,7 +216,7 @@ ZEND_ATTRIBUTE_NONNULL PHPAPI php_uri *php_uri_parse_to_struct( uri->path = Z_STR(tmp); } - result = php_uri_get_query(uri_internal, read_mode, &tmp); + result = php_uri_get_query(&uri_internal, read_mode, &tmp); if (result == FAILURE) { goto error; } @@ -241,7 +224,7 @@ ZEND_ATTRIBUTE_NONNULL PHPAPI php_uri *php_uri_parse_to_struct( uri->query = Z_STR(tmp); } - result = php_uri_get_fragment(uri_internal, read_mode, &tmp); + result = php_uri_get_fragment(&uri_internal, read_mode, &tmp); if (result == FAILURE) { goto error; } @@ -249,12 +232,13 @@ ZEND_ATTRIBUTE_NONNULL PHPAPI php_uri *php_uri_parse_to_struct( uri->fragment = Z_STR(tmp); } - php_uri_free(uri_internal); + uri_parser->free(parsed); return uri; error: - php_uri_free(uri_internal); + + uri_parser->free(parsed); php_uri_struct_free(uri); return NULL; @@ -351,7 +335,8 @@ ZEND_ATTRIBUTE_NONNULL_ARGS(1, 2) PHPAPI void php_uri_instantiate_uri( base_url = internal_base_url->uri; } - void *uri = uri_parser->parse(ZSTR_VAL(uri_str), ZSTR_LEN(uri_str), base_url, errors_zv != NULL ? &errors : NULL, !should_throw); + void *uri = uri_parser->parse(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); @@ -853,7 +838,8 @@ static void uri_unserialize(INTERNAL_FUNCTION_PARAMETERS) 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); + internal_uri->uri = internal_uri->parser->parse(Z_STRVAL_P(uri_zv), Z_STRLEN_P(uri_zv), + /* base_url */ NULL, /* errors */ NULL, /* silent */ true); if (internal_uri->uri == NULL) { zend_throw_exception_ex(NULL, 0, "Invalid serialization data for %s object", ZSTR_VAL(object->ce->name)); RETURN_THROWS(); diff --git a/ext/uri/php_uri.h b/ext/uri/php_uri.h index 97125f2b2700..1f5b7705cb28 100644 --- a/ext/uri/php_uri.h +++ b/ext/uri/php_uri.h @@ -49,8 +49,6 @@ PHPAPI zend_result php_uri_parser_register(const php_uri_parser *uri_parser); */ PHPAPI const php_uri_parser *php_uri_get_parser(zend_string *uri_parser_name); -ZEND_ATTRIBUTE_NONNULL PHPAPI uri_internal_t *php_uri_parse(const php_uri_parser *uri_parser, const char *uri_str, size_t uri_str_len, bool silent); - /** * Retrieves the scheme component based on the read_mode and passes it to the zv ZVAL in case of success. * @@ -171,13 +169,6 @@ ZEND_ATTRIBUTE_NONNULL PHPAPI zend_result php_uri_get_query(const uri_internal_t */ ZEND_ATTRIBUTE_NONNULL PHPAPI zend_result php_uri_get_fragment(const uri_internal_t *internal_uri, php_uri_component_read_mode read_mode, zval *zv); -/** - * Frees the uri member within the provided internal URI. - * - * @param internal_uri The internal URI - */ -ZEND_ATTRIBUTE_NONNULL PHPAPI void php_uri_free(uri_internal_t *internal_uri); - /** * Creates a new php_uri struct containing all the URI components. The components are retrieved based on the read_mode parameter. * diff --git a/ext/zend_test/test.c b/ext/zend_test/test.c index 99bdae0bcc7a..45ddf24c4bff 100644 --- a/ext/zend_test/test.c +++ b/ext/zend_test/test.c @@ -741,54 +741,60 @@ static ZEND_FUNCTION(zend_test_uri_parser) RETURN_THROWS(); } - uri_internal_t *uri = php_uri_parse(parser, ZSTR_VAL(uri_string), ZSTR_LEN(uri_string), false); - if (uri == NULL) { + void *parsed = parser->parse(ZSTR_VAL(uri_string), ZSTR_LEN(uri_string), + /* base_url */ NULL, /* errors */ NULL, /* silent */ false); + if (parsed == NULL) { RETURN_THROWS(); } + uri_internal_t uri = { + .parser = parser, + .uri = parsed, + }; + zval value; array_init(return_value); zval normalized; array_init(&normalized); - php_uri_get_scheme(uri, PHP_URI_COMPONENT_READ_MODE_NORMALIZED_ASCII, &value); + php_uri_get_scheme(&uri, PHP_URI_COMPONENT_READ_MODE_NORMALIZED_ASCII, &value); zend_hash_add(Z_ARR(normalized), ZSTR_KNOWN(ZEND_STR_SCHEME), &value); - php_uri_get_username(uri, PHP_URI_COMPONENT_READ_MODE_NORMALIZED_ASCII, &value); + php_uri_get_username(&uri, PHP_URI_COMPONENT_READ_MODE_NORMALIZED_ASCII, &value); zend_hash_add(Z_ARR(normalized), ZSTR_KNOWN(ZEND_STR_USERNAME), &value); - php_uri_get_password(uri, PHP_URI_COMPONENT_READ_MODE_NORMALIZED_ASCII, &value); + php_uri_get_password(&uri, PHP_URI_COMPONENT_READ_MODE_NORMALIZED_ASCII, &value); zend_hash_add(Z_ARR(normalized), ZSTR_KNOWN(ZEND_STR_PASSWORD), &value); - php_uri_get_host(uri, PHP_URI_COMPONENT_READ_MODE_NORMALIZED_ASCII, &value); + php_uri_get_host(&uri, PHP_URI_COMPONENT_READ_MODE_NORMALIZED_ASCII, &value); zend_hash_add(Z_ARR(normalized), ZSTR_KNOWN(ZEND_STR_HOST), &value); - php_uri_get_port(uri, PHP_URI_COMPONENT_READ_MODE_NORMALIZED_ASCII, &value); + php_uri_get_port(&uri, PHP_URI_COMPONENT_READ_MODE_NORMALIZED_ASCII, &value); zend_hash_add(Z_ARR(normalized), ZSTR_KNOWN(ZEND_STR_PORT), &value); - php_uri_get_path(uri, PHP_URI_COMPONENT_READ_MODE_NORMALIZED_ASCII, &value); + php_uri_get_path(&uri, PHP_URI_COMPONENT_READ_MODE_NORMALIZED_ASCII, &value); zend_hash_add(Z_ARR(normalized), ZSTR_KNOWN(ZEND_STR_PATH), &value); - php_uri_get_query(uri, PHP_URI_COMPONENT_READ_MODE_NORMALIZED_ASCII, &value); + php_uri_get_query(&uri, PHP_URI_COMPONENT_READ_MODE_NORMALIZED_ASCII, &value); zend_hash_add(Z_ARR(normalized), ZSTR_KNOWN(ZEND_STR_QUERY), &value); - php_uri_get_fragment(uri, PHP_URI_COMPONENT_READ_MODE_NORMALIZED_ASCII, &value); + php_uri_get_fragment(&uri, PHP_URI_COMPONENT_READ_MODE_NORMALIZED_ASCII, &value); zend_hash_add(Z_ARR(normalized), ZSTR_KNOWN(ZEND_STR_FRAGMENT), &value); zend_hash_str_add(Z_ARR_P(return_value), "normalized", strlen("normalized"), &normalized); zval raw; array_init(&raw); - php_uri_get_scheme(uri, PHP_URI_COMPONENT_READ_MODE_RAW, &value); + php_uri_get_scheme(&uri, PHP_URI_COMPONENT_READ_MODE_RAW, &value); zend_hash_add(Z_ARR(raw), ZSTR_KNOWN(ZEND_STR_SCHEME), &value); - php_uri_get_username(uri, PHP_URI_COMPONENT_READ_MODE_RAW, &value); + php_uri_get_username(&uri, PHP_URI_COMPONENT_READ_MODE_RAW, &value); zend_hash_add(Z_ARR(raw), ZSTR_KNOWN(ZEND_STR_USERNAME), &value); - php_uri_get_password(uri, PHP_URI_COMPONENT_READ_MODE_RAW, &value); + php_uri_get_password(&uri, PHP_URI_COMPONENT_READ_MODE_RAW, &value); zend_hash_add(Z_ARR(raw), ZSTR_KNOWN(ZEND_STR_PASSWORD), &value); - php_uri_get_host(uri, PHP_URI_COMPONENT_READ_MODE_RAW, &value); + php_uri_get_host(&uri, PHP_URI_COMPONENT_READ_MODE_RAW, &value); zend_hash_add(Z_ARR(raw), ZSTR_KNOWN(ZEND_STR_HOST), &value); - php_uri_get_port(uri, PHP_URI_COMPONENT_READ_MODE_RAW, &value); + php_uri_get_port(&uri, PHP_URI_COMPONENT_READ_MODE_RAW, &value); zend_hash_add(Z_ARR(raw), ZSTR_KNOWN(ZEND_STR_PORT), &value); - php_uri_get_path(uri, PHP_URI_COMPONENT_READ_MODE_RAW, &value); + php_uri_get_path(&uri, PHP_URI_COMPONENT_READ_MODE_RAW, &value); zend_hash_add(Z_ARR(raw), ZSTR_KNOWN(ZEND_STR_PATH), &value); - php_uri_get_query(uri, PHP_URI_COMPONENT_READ_MODE_RAW, &value); + php_uri_get_query(&uri, PHP_URI_COMPONENT_READ_MODE_RAW, &value); zend_hash_add(Z_ARR(raw), ZSTR_KNOWN(ZEND_STR_QUERY), &value); - php_uri_get_fragment(uri, PHP_URI_COMPONENT_READ_MODE_RAW, &value); + php_uri_get_fragment(&uri, PHP_URI_COMPONENT_READ_MODE_RAW, &value); zend_hash_add(Z_ARR(raw), ZSTR_KNOWN(ZEND_STR_FRAGMENT), &value); zend_hash_str_add(Z_ARR_P(return_value), "raw", strlen("raw"), &raw); - php_uri_free(uri); + parser->free(parsed); } static bool has_opline(zend_execute_data *execute_data)

AltStyle によって変換されたページ (->オリジナル) /