Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit e99f1b4

Browse files
uri: Fix normalization memory management for uri_parser_php_parse_url.c (#19600)
There were two issues with the previous implementation of normalization: - `php_raw_url_decode_ex()` would be used to modify a string with RC >1. - The return value of `php_raw_url_decode_ex()` was not used, resulting in incorrect string lengths when percent-encoded characters are decoded. Additionally there was a bogus assertion that verified that strings returned from the read handlers are RC =2, which was not the case for the `parse_url`-based parser when repeatedly retrieving a component even without normalization happening. Remove that assertion, since its usefulness is questionable. Any obvious data type issues with read handlers should be detectable when testing during development.
1 parent 423960a commit e99f1b4

File tree

6 files changed

+149
-29
lines changed

6 files changed

+149
-29
lines changed

‎ext/uri/php_uri.c

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -137,11 +137,7 @@ ZEND_ATTRIBUTE_NONNULL static zend_result php_uri_get_property(const uri_interna
137137
return FAILURE;
138138
}
139139

140-
zend_result result = property_handler->read_func(internal_uri, read_mode, zv);
141-
142-
ZEND_ASSERT(result == FAILURE || (Z_TYPE_P(zv) == IS_STRING && GC_REFCOUNT(Z_STR_P(zv)) == 2) || Z_TYPE_P(zv) == IS_NULL || Z_TYPE_P(zv) == IS_LONG);
143-
144-
return result;
140+
return property_handler->read_func(internal_uri, read_mode, zv);
145141
}
146142

147143
ZEND_ATTRIBUTE_NONNULL PHPAPI zend_result php_uri_get_scheme(const uri_internal_t *internal_uri, uri_component_read_mode_t read_mode, zval *zv)

‎ext/uri/tests/100.phpt

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
--TEST--
2+
Test the parse_url-based URI parser
3+
--EXTENSIONS--
4+
uri
5+
zend_test
6+
--FILE--
7+
<?php
8+
9+
var_dump(zend_test_uri_parser("https://%65xample:%65xample@%65xample.com:123/%65xample.html?%65xample=%65xample#%65xample", "parse_url"));
10+
11+
?>
12+
--EXPECT--
13+
array(2) {
14+
["normalized"]=>
15+
array(8) {
16+
["scheme"]=>
17+
string(5) "https"
18+
["username"]=>
19+
string(7) "example"
20+
["password"]=>
21+
string(7) "example"
22+
["host"]=>
23+
string(11) "example.com"
24+
["port"]=>
25+
int(123)
26+
["path"]=>
27+
string(13) "/example.html"
28+
["query"]=>
29+
string(15) "example=example"
30+
["fragment"]=>
31+
string(7) "example"
32+
}
33+
["raw"]=>
34+
array(8) {
35+
["scheme"]=>
36+
string(5) "https"
37+
["username"]=>
38+
string(9) "%65xample"
39+
["password"]=>
40+
string(9) "%65xample"
41+
["host"]=>
42+
string(13) "%65xample.com"
43+
["port"]=>
44+
int(123)
45+
["path"]=>
46+
string(15) "/%65xample.html"
47+
["query"]=>
48+
string(19) "%65xample=%65xample"
49+
["fragment"]=>
50+
string(9) "%65xample"
51+
}
52+
}

‎ext/uri/uri_parser_php_parse_url.c

Lines changed: 19 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -21,26 +21,29 @@
2121
#include "Zend/zend_exceptions.h"
2222
#include "ext/standard/url.h"
2323

24-
static voiddecode_component(zval*zv, uri_component_read_mode_t read_mode)
24+
static zend_string*decode_component(zend_string*in, uri_component_read_mode_t read_mode)
2525
{
26-
if (Z_TYPE_P(zv) != IS_STRING) {
27-
return;
28-
}
26+
switch (read_mode) {
27+
case URI_COMPONENT_READ_RAW:
28+
return zend_string_copy(in);
29+
case URI_COMPONENT_READ_NORMALIZED_ASCII:
30+
case URI_COMPONENT_READ_NORMALIZED_UNICODE: {
31+
zend_string *out = zend_string_alloc(ZSTR_LEN(in), false);
2932

30-
if (read_mode == URI_COMPONENT_READ_RAW) {
31-
return;
32-
}
33+
ZSTR_LEN(out) = php_raw_url_decode_ex(ZSTR_VAL(out), ZSTR_VAL(in), ZSTR_LEN(in));
3334

34-
php_raw_url_decode(Z_STRVAL_P(zv), Z_STRLEN_P(zv));
35+
return out;
36+
}
37+
EMPTY_SWITCH_DEFAULT_CASE();
38+
}
3539
}
3640

3741
static zend_result uri_parser_php_parse_url_scheme_read(const uri_internal_t *internal_uri, uri_component_read_mode_t read_mode, zval *retval)
3842
{
3943
const php_url *parse_url_uri = internal_uri->uri;
4044

4145
if (parse_url_uri->scheme) {
42-
ZVAL_STR_COPY(retval, parse_url_uri->scheme);
43-
decode_component(retval, read_mode);
46+
ZVAL_STR(retval, decode_component(parse_url_uri->scheme, read_mode));
4447
} else {
4548
ZVAL_NULL(retval);
4649
}
@@ -53,8 +56,7 @@ static zend_result uri_parser_php_parse_url_username_read(const uri_internal_t *
5356
const php_url *parse_url_uri = internal_uri->uri;
5457

5558
if (parse_url_uri->user) {
56-
ZVAL_STR_COPY(retval, parse_url_uri->user);
57-
decode_component(retval, read_mode);
59+
ZVAL_STR(retval, decode_component(parse_url_uri->user, read_mode));
5860
} else {
5961
ZVAL_NULL(retval);
6062
}
@@ -67,8 +69,7 @@ static zend_result uri_parser_php_parse_url_password_read(const uri_internal_t *
6769
const php_url *parse_url_uri = internal_uri->uri;
6870

6971
if (parse_url_uri->pass) {
70-
ZVAL_STR_COPY(retval, parse_url_uri->pass);
71-
decode_component(retval, read_mode);
72+
ZVAL_STR(retval, decode_component(parse_url_uri->pass, read_mode));
7273
} else {
7374
ZVAL_NULL(retval);
7475
}
@@ -81,8 +82,7 @@ static zend_result uri_parser_php_parse_url_host_read(const uri_internal_t *inte
8182
const php_url *parse_url_uri = internal_uri->uri;
8283

8384
if (parse_url_uri->host) {
84-
ZVAL_STR_COPY(retval, parse_url_uri->host);
85-
decode_component(retval, read_mode);
85+
ZVAL_STR(retval, decode_component(parse_url_uri->host, read_mode));
8686
} else {
8787
ZVAL_NULL(retval);
8888
}
@@ -96,7 +96,6 @@ static zend_result uri_parser_php_parse_url_port_read(const uri_internal_t *inte
9696

9797
if (parse_url_uri->port) {
9898
ZVAL_LONG(retval, parse_url_uri->port);
99-
decode_component(retval, read_mode);
10099
} else {
101100
ZVAL_NULL(retval);
102101
}
@@ -109,8 +108,7 @@ static zend_result uri_parser_php_parse_url_path_read(const uri_internal_t *inte
109108
const php_url *parse_url_uri = internal_uri->uri;
110109

111110
if (parse_url_uri->path) {
112-
ZVAL_STR_COPY(retval, parse_url_uri->path);
113-
decode_component(retval, read_mode);
111+
ZVAL_STR(retval, decode_component(parse_url_uri->path, read_mode));
114112
} else {
115113
ZVAL_NULL(retval);
116114
}
@@ -123,8 +121,7 @@ static zend_result uri_parser_php_parse_url_query_read(const uri_internal_t *int
123121
const php_url *parse_url_uri = internal_uri->uri;
124122

125123
if (parse_url_uri->query) {
126-
ZVAL_STR_COPY(retval, parse_url_uri->query);
127-
decode_component(retval, read_mode);
124+
ZVAL_STR(retval, decode_component(parse_url_uri->query, read_mode));
128125
} else {
129126
ZVAL_NULL(retval);
130127
}
@@ -137,8 +134,7 @@ static zend_result uri_parser_php_parse_url_fragment_read(const uri_internal_t *
137134
const php_url *parse_url_uri = internal_uri->uri;
138135

139136
if (parse_url_uri->fragment) {
140-
ZVAL_STR_COPY(retval, parse_url_uri->fragment);
141-
decode_component(retval, read_mode);
137+
ZVAL_STR(retval, decode_component(parse_url_uri->fragment, read_mode));
142138
} else {
143139
ZVAL_NULL(retval);
144140
}

‎ext/zend_test/test.c

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@
4040
#include "zend_call_stack.h"
4141
#include "zend_exceptions.h"
4242
#include "zend_mm_custom_handlers.h"
43+
#include "ext/uri/php_uri.h"
4344

4445
#if defined(HAVE_LIBXML) && !defined(PHP_WIN32)
4546
# include <libxml/globals.h>
@@ -724,6 +725,72 @@ static ZEND_FUNCTION(zend_test_crash)
724725
php_printf("%s", invalid);
725726
}
726727

728+
static ZEND_FUNCTION(zend_test_uri_parser)
729+
{
730+
zend_string *uri_string;
731+
zend_string *parser_name;
732+
733+
ZEND_PARSE_PARAMETERS_START(2, 2)
734+
Z_PARAM_STR(uri_string)
735+
Z_PARAM_STR(parser_name)
736+
ZEND_PARSE_PARAMETERS_END();
737+
738+
uri_parser_t *parser = php_uri_get_parser(parser_name);
739+
if (parser == NULL) {
740+
zend_argument_value_error(1, "Unknown parser");
741+
RETURN_THROWS();
742+
}
743+
744+
uri_internal_t *uri = php_uri_parse(parser, ZSTR_VAL(uri_string), ZSTR_LEN(uri_string), false);
745+
if (uri == NULL) {
746+
RETURN_THROWS();
747+
}
748+
749+
zval value;
750+
751+
array_init(return_value);
752+
zval normalized;
753+
array_init(&normalized);
754+
php_uri_get_scheme(uri, URI_COMPONENT_READ_NORMALIZED_ASCII, &value);
755+
zend_hash_add(Z_ARR(normalized), ZSTR_KNOWN(ZEND_STR_SCHEME), &value);
756+
php_uri_get_username(uri, URI_COMPONENT_READ_NORMALIZED_ASCII, &value);
757+
zend_hash_add(Z_ARR(normalized), ZSTR_KNOWN(ZEND_STR_USERNAME), &value);
758+
php_uri_get_password(uri, URI_COMPONENT_READ_NORMALIZED_ASCII, &value);
759+
zend_hash_add(Z_ARR(normalized), ZSTR_KNOWN(ZEND_STR_PASSWORD), &value);
760+
php_uri_get_host(uri, URI_COMPONENT_READ_NORMALIZED_ASCII, &value);
761+
zend_hash_add(Z_ARR(normalized), ZSTR_KNOWN(ZEND_STR_HOST), &value);
762+
php_uri_get_port(uri, URI_COMPONENT_READ_NORMALIZED_ASCII, &value);
763+
zend_hash_add(Z_ARR(normalized), ZSTR_KNOWN(ZEND_STR_PORT), &value);
764+
php_uri_get_path(uri, URI_COMPONENT_READ_NORMALIZED_ASCII, &value);
765+
zend_hash_add(Z_ARR(normalized), ZSTR_KNOWN(ZEND_STR_PATH), &value);
766+
php_uri_get_query(uri, URI_COMPONENT_READ_NORMALIZED_ASCII, &value);
767+
zend_hash_add(Z_ARR(normalized), ZSTR_KNOWN(ZEND_STR_QUERY), &value);
768+
php_uri_get_fragment(uri, URI_COMPONENT_READ_NORMALIZED_ASCII, &value);
769+
zend_hash_add(Z_ARR(normalized), ZSTR_KNOWN(ZEND_STR_FRAGMENT), &value);
770+
zend_hash_str_add(Z_ARR_P(return_value), "normalized", strlen("normalized"), &normalized);
771+
zval raw;
772+
array_init(&raw);
773+
php_uri_get_scheme(uri, URI_COMPONENT_READ_RAW, &value);
774+
zend_hash_add(Z_ARR(raw), ZSTR_KNOWN(ZEND_STR_SCHEME), &value);
775+
php_uri_get_username(uri, URI_COMPONENT_READ_RAW, &value);
776+
zend_hash_add(Z_ARR(raw), ZSTR_KNOWN(ZEND_STR_USERNAME), &value);
777+
php_uri_get_password(uri, URI_COMPONENT_READ_RAW, &value);
778+
zend_hash_add(Z_ARR(raw), ZSTR_KNOWN(ZEND_STR_PASSWORD), &value);
779+
php_uri_get_host(uri, URI_COMPONENT_READ_RAW, &value);
780+
zend_hash_add(Z_ARR(raw), ZSTR_KNOWN(ZEND_STR_HOST), &value);
781+
php_uri_get_port(uri, URI_COMPONENT_READ_RAW, &value);
782+
zend_hash_add(Z_ARR(raw), ZSTR_KNOWN(ZEND_STR_PORT), &value);
783+
php_uri_get_path(uri, URI_COMPONENT_READ_RAW, &value);
784+
zend_hash_add(Z_ARR(raw), ZSTR_KNOWN(ZEND_STR_PATH), &value);
785+
php_uri_get_query(uri, URI_COMPONENT_READ_RAW, &value);
786+
zend_hash_add(Z_ARR(raw), ZSTR_KNOWN(ZEND_STR_QUERY), &value);
787+
php_uri_get_fragment(uri, URI_COMPONENT_READ_RAW, &value);
788+
zend_hash_add(Z_ARR(raw), ZSTR_KNOWN(ZEND_STR_FRAGMENT), &value);
789+
zend_hash_str_add(Z_ARR_P(return_value), "raw", strlen("raw"), &raw);
790+
791+
php_uri_free(uri);
792+
}
793+
727794
static bool has_opline(zend_execute_data *execute_data)
728795
{
729796
return execute_data

‎ext/zend_test/test.stub.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -342,6 +342,8 @@ function zend_test_compile_to_ast(string $str): string {}
342342
function zend_test_gh18756(): void {}
343343

344344
function zend_test_opcache_preloading(): bool {}
345+
346+
function zend_test_uri_parser(string $uri, string $parser): array { }
345347
}
346348

347349
namespace ZendTestNS {

‎ext/zend_test/test_arginfo.h

Lines changed: 8 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
(0)

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