From ccc7e1335d04ce199135df7b4989eeff4265e132 Mon Sep 17 00:00:00 2001 From: lamentxu <1372449351@qq.com> Date: Thu, 2 Apr 2026 21:34:19 +0800 Subject: [PATCH 1/6] Add new API --- Zend/zend_string.h | 38 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/Zend/zend_string.h b/Zend/zend_string.h index 97386ea6bad64..998e7f091aa2a 100644 --- a/Zend/zend_string.h +++ b/Zend/zend_string.h @@ -316,6 +316,44 @@ static zend_always_inline zend_string *zend_string_safe_realloc(zend_string *s, return ret; } +static zend_always_inline char *zend_str_append_char_to_raw(const char *str, size_t len, char c) { + char *res = (char *)emalloc(len + 2); + if (len > 0) { + memcpy(res, str, len); + } + res[len] = c; + res[len + 1] = '\0'; + return res; +} + +static zend_always_inline char *zend_str_concat_to_raw(const char *s1, size_t len1, const char *s2, size_t len2) { + char *res = (char *)emalloc(len1 + len2 + 1); + if (len1 > 0) { + memcpy(res, s1, len1); + } + if (len2 > 0) { + memcpy(res + len1, s2, len2); + } + res[len1 + len2] = '\0'; + return res; +} + +static zend_always_inline char *zend_str_concat3_to_raw(const char *s1, size_t len1, const char *s2, size_t len2, const char *s3, size_t len3) { + size_t total_len = len1 + len2 + len3; + char *res = (char *)emalloc(total_len + 1); + if (len1 > 0) { + memcpy(res, s1, len1); + } + if (len2 > 0) { + memcpy(res + len1, s2, len2); + } + if (len3 > 0) { + memcpy(res + len1 + len2, s3, len3); + } + res[total_len] = '\0'; + return res; +} + static zend_always_inline void zend_string_free(zend_string *s) { if (!ZSTR_IS_INTERNED(s)) { From fe4c5824ea90ecbf916e0ad51a087651dae4b130 Mon Sep 17 00:00:00 2001 From: lamentxu <1372449351@qq.com> Date: Thu, 2 Apr 2026 21:41:37 +0800 Subject: [PATCH 2/6] add tests --- Zend/tests/zend_str_raw_functions.phpt | 41 +++++++++++++++++++++++++ ext/zend_test/test.c | 42 ++++++++++++++++++++++++++ ext/zend_test/test.stub.php | 4 +++ ext/zend_test/test_arginfo.h | 19 ++++++++++++ 4 files changed, 106 insertions(+) create mode 100644 Zend/tests/zend_str_raw_functions.phpt diff --git a/Zend/tests/zend_str_raw_functions.phpt b/Zend/tests/zend_str_raw_functions.phpt new file mode 100644 index 0000000000000..44f92bc8e3b7d --- /dev/null +++ b/Zend/tests/zend_str_raw_functions.phpt @@ -0,0 +1,41 @@ +--TEST-- +Test zend_str_append_char_to_raw, zend_str_concat_to_raw, zend_str_concat3_to_raw functions +--EXTENSIONS-- +zend_test +--FILE-- + +--EXPECT-- +zend_str_append_char_to_raw('Hello', '!'): Hello! +zend_str_concat_to_raw('Hello', ' World'): Hello World +zend_str_concat3_to_raw('Hello', ' ', 'World'): Hello World +zend_str_append_char_to_raw('', 'a'): a +zend_str_concat_to_raw('', 'Test'): Test +zend_str_concat_to_raw('Test', ''): Test +zend_str_concat3_to_raw('', '', ''): diff --git a/ext/zend_test/test.c b/ext/zend_test/test.c index 0faf65f36437f..3d03c0cf43ea3 100644 --- a/ext/zend_test/test.c +++ b/ext/zend_test/test.c @@ -1021,6 +1021,48 @@ static ZEND_FUNCTION(zend_test_is_zend_ptr) RETURN_BOOL(is_zend_ptr((void*)addr)); } +static ZEND_FUNCTION(zend_test_str_append_char_to_raw) +{ + zend_string *str; + zend_string *c_str; + + ZEND_PARSE_PARAMETERS_START(2, 2) + Z_PARAM_STR(str); + Z_PARAM_STR(c_str); + ZEND_PARSE_PARAMETERS_END(); + + char c = ZSTR_LEN(c_str) > 0 ? ZSTR_VAL(c_str)[0] : '\0'; + char *result = zend_str_append_char_to_raw(ZSTR_VAL(str), ZSTR_LEN(str), c); + RETURN_STRING(result); +} + +static ZEND_FUNCTION(zend_test_str_concat_to_raw) +{ + zend_string *str1, *str2; + + ZEND_PARSE_PARAMETERS_START(2, 2) + Z_PARAM_STR(str1); + Z_PARAM_STR(str2); + ZEND_PARSE_PARAMETERS_END(); + + char *result = zend_str_concat_to_raw(ZSTR_VAL(str1), ZSTR_LEN(str1), ZSTR_VAL(str2), ZSTR_LEN(str2)); + RETURN_STRING(result); +} + +static ZEND_FUNCTION(zend_test_str_concat3_to_raw) +{ + zend_string *str1, *str2, *str3; + + ZEND_PARSE_PARAMETERS_START(3, 3) + Z_PARAM_STR(str1); + Z_PARAM_STR(str2); + Z_PARAM_STR(str3); + ZEND_PARSE_PARAMETERS_END(); + + char *result = zend_str_concat3_to_raw(ZSTR_VAL(str1), ZSTR_LEN(str1), ZSTR_VAL(str2), ZSTR_LEN(str2), ZSTR_VAL(str3), ZSTR_LEN(str3)); + RETURN_STRING(result); +} + static ZEND_FUNCTION(zend_test_log_err_debug) { zend_string *str; diff --git a/ext/zend_test/test.stub.php b/ext/zend_test/test.stub.php index e102082c6a95c..e22a48d0e1850 100644 --- a/ext/zend_test/test.stub.php +++ b/ext/zend_test/test.stub.php @@ -342,6 +342,10 @@ function zend_test_cast_fread($stream): void {} function zend_test_is_zend_ptr(int $addr): bool {} + function zend_test_str_append_char_to_raw(string $str, string $c): string {} + function zend_test_str_concat_to_raw(string $str1, string $str2): string {} + function zend_test_str_concat3_to_raw(string $str1, string $str2, string $str3): string {} + function zend_test_log_err_debug(string $str): void {} function zend_test_compile_to_ast(string $str): string {} diff --git a/ext/zend_test/test_arginfo.h b/ext/zend_test/test_arginfo.h index 30297234fc873..3ee0f9d509cd3 100644 --- a/ext/zend_test/test_arginfo.h +++ b/ext/zend_test/test_arginfo.h @@ -183,6 +183,22 @@ ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_zend_test_is_zend_ptr, 0, 1, _IS ZEND_ARG_TYPE_INFO(0, addr, IS_LONG, 0) ZEND_END_ARG_INFO() +ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_zend_test_str_append_char_to_raw, 0, 2, IS_STRING, 0) + ZEND_ARG_TYPE_INFO(0, str, IS_STRING, 0) + ZEND_ARG_TYPE_INFO(0, c, IS_STRING, 0) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_zend_test_str_concat_to_raw, 0, 2, IS_STRING, 0) + ZEND_ARG_TYPE_INFO(0, str1, IS_STRING, 0) + ZEND_ARG_TYPE_INFO(0, str2, IS_STRING, 0) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_zend_test_str_concat3_to_raw, 0, 3, IS_STRING, 0) + ZEND_ARG_TYPE_INFO(0, str1, IS_STRING, 0) + ZEND_ARG_TYPE_INFO(0, str2, IS_STRING, 0) + ZEND_ARG_TYPE_INFO(0, str3, IS_STRING, 0) +ZEND_END_ARG_INFO() + ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_zend_test_log_err_debug, 0, 1, IS_VOID, 0) ZEND_ARG_TYPE_INFO(0, str, IS_STRING, 0) ZEND_END_ARG_INFO() @@ -471,6 +487,9 @@ static const zend_function_entry ext_functions[] = { #endif ZEND_FE(zend_test_cast_fread, arginfo_zend_test_cast_fread) ZEND_FE(zend_test_is_zend_ptr, arginfo_zend_test_is_zend_ptr) + ZEND_FE(zend_test_str_append_char_to_raw, arginfo_zend_test_str_append_char_to_raw) + ZEND_FE(zend_test_str_concat_to_raw, arginfo_zend_test_str_concat_to_raw) + ZEND_FE(zend_test_str_concat3_to_raw, arginfo_zend_test_str_concat3_to_raw) ZEND_FE(zend_test_log_err_debug, arginfo_zend_test_log_err_debug) ZEND_FE(zend_test_compile_to_ast, arginfo_zend_test_compile_to_ast) ZEND_FE(zend_test_gh18756, arginfo_zend_test_gh18756) From 753f4109a0b7f1b8608625c3f852b10059570387 Mon Sep 17 00:00:00 2001 From: lamentxu <1372449351@qq.com> Date: Thu, 2 Apr 2026 21:59:06 +0800 Subject: [PATCH 3/6] Revert "add tests" This reverts commit fe4c5824ea90ecbf916e0ad51a087651dae4b130. --- Zend/tests/zend_str_raw_functions.phpt | 41 ------------------------- ext/zend_test/test.c | 42 -------------------------- ext/zend_test/test.stub.php | 4 --- ext/zend_test/test_arginfo.h | 19 ------------ 4 files changed, 106 deletions(-) delete mode 100644 Zend/tests/zend_str_raw_functions.phpt diff --git a/Zend/tests/zend_str_raw_functions.phpt b/Zend/tests/zend_str_raw_functions.phpt deleted file mode 100644 index 44f92bc8e3b7d..0000000000000 --- a/Zend/tests/zend_str_raw_functions.phpt +++ /dev/null @@ -1,41 +0,0 @@ ---TEST-- -Test zend_str_append_char_to_raw, zend_str_concat_to_raw, zend_str_concat3_to_raw functions ---EXTENSIONS-- -zend_test ---FILE-- - ---EXPECT-- -zend_str_append_char_to_raw('Hello', '!'): Hello! -zend_str_concat_to_raw('Hello', ' World'): Hello World -zend_str_concat3_to_raw('Hello', ' ', 'World'): Hello World -zend_str_append_char_to_raw('', 'a'): a -zend_str_concat_to_raw('', 'Test'): Test -zend_str_concat_to_raw('Test', ''): Test -zend_str_concat3_to_raw('', '', ''): diff --git a/ext/zend_test/test.c b/ext/zend_test/test.c index 3d03c0cf43ea3..0faf65f36437f 100644 --- a/ext/zend_test/test.c +++ b/ext/zend_test/test.c @@ -1021,48 +1021,6 @@ static ZEND_FUNCTION(zend_test_is_zend_ptr) RETURN_BOOL(is_zend_ptr((void*)addr)); } -static ZEND_FUNCTION(zend_test_str_append_char_to_raw) -{ - zend_string *str; - zend_string *c_str; - - ZEND_PARSE_PARAMETERS_START(2, 2) - Z_PARAM_STR(str); - Z_PARAM_STR(c_str); - ZEND_PARSE_PARAMETERS_END(); - - char c = ZSTR_LEN(c_str) > 0 ? ZSTR_VAL(c_str)[0] : '\0'; - char *result = zend_str_append_char_to_raw(ZSTR_VAL(str), ZSTR_LEN(str), c); - RETURN_STRING(result); -} - -static ZEND_FUNCTION(zend_test_str_concat_to_raw) -{ - zend_string *str1, *str2; - - ZEND_PARSE_PARAMETERS_START(2, 2) - Z_PARAM_STR(str1); - Z_PARAM_STR(str2); - ZEND_PARSE_PARAMETERS_END(); - - char *result = zend_str_concat_to_raw(ZSTR_VAL(str1), ZSTR_LEN(str1), ZSTR_VAL(str2), ZSTR_LEN(str2)); - RETURN_STRING(result); -} - -static ZEND_FUNCTION(zend_test_str_concat3_to_raw) -{ - zend_string *str1, *str2, *str3; - - ZEND_PARSE_PARAMETERS_START(3, 3) - Z_PARAM_STR(str1); - Z_PARAM_STR(str2); - Z_PARAM_STR(str3); - ZEND_PARSE_PARAMETERS_END(); - - char *result = zend_str_concat3_to_raw(ZSTR_VAL(str1), ZSTR_LEN(str1), ZSTR_VAL(str2), ZSTR_LEN(str2), ZSTR_VAL(str3), ZSTR_LEN(str3)); - RETURN_STRING(result); -} - static ZEND_FUNCTION(zend_test_log_err_debug) { zend_string *str; diff --git a/ext/zend_test/test.stub.php b/ext/zend_test/test.stub.php index e22a48d0e1850..e102082c6a95c 100644 --- a/ext/zend_test/test.stub.php +++ b/ext/zend_test/test.stub.php @@ -342,10 +342,6 @@ function zend_test_cast_fread($stream): void {} function zend_test_is_zend_ptr(int $addr): bool {} - function zend_test_str_append_char_to_raw(string $str, string $c): string {} - function zend_test_str_concat_to_raw(string $str1, string $str2): string {} - function zend_test_str_concat3_to_raw(string $str1, string $str2, string $str3): string {} - function zend_test_log_err_debug(string $str): void {} function zend_test_compile_to_ast(string $str): string {} diff --git a/ext/zend_test/test_arginfo.h b/ext/zend_test/test_arginfo.h index 3ee0f9d509cd3..30297234fc873 100644 --- a/ext/zend_test/test_arginfo.h +++ b/ext/zend_test/test_arginfo.h @@ -183,22 +183,6 @@ ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_zend_test_is_zend_ptr, 0, 1, _IS ZEND_ARG_TYPE_INFO(0, addr, IS_LONG, 0) ZEND_END_ARG_INFO() -ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_zend_test_str_append_char_to_raw, 0, 2, IS_STRING, 0) - ZEND_ARG_TYPE_INFO(0, str, IS_STRING, 0) - ZEND_ARG_TYPE_INFO(0, c, IS_STRING, 0) -ZEND_END_ARG_INFO() - -ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_zend_test_str_concat_to_raw, 0, 2, IS_STRING, 0) - ZEND_ARG_TYPE_INFO(0, str1, IS_STRING, 0) - ZEND_ARG_TYPE_INFO(0, str2, IS_STRING, 0) -ZEND_END_ARG_INFO() - -ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_zend_test_str_concat3_to_raw, 0, 3, IS_STRING, 0) - ZEND_ARG_TYPE_INFO(0, str1, IS_STRING, 0) - ZEND_ARG_TYPE_INFO(0, str2, IS_STRING, 0) - ZEND_ARG_TYPE_INFO(0, str3, IS_STRING, 0) -ZEND_END_ARG_INFO() - ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_zend_test_log_err_debug, 0, 1, IS_VOID, 0) ZEND_ARG_TYPE_INFO(0, str, IS_STRING, 0) ZEND_END_ARG_INFO() @@ -487,9 +471,6 @@ static const zend_function_entry ext_functions[] = { #endif ZEND_FE(zend_test_cast_fread, arginfo_zend_test_cast_fread) ZEND_FE(zend_test_is_zend_ptr, arginfo_zend_test_is_zend_ptr) - ZEND_FE(zend_test_str_append_char_to_raw, arginfo_zend_test_str_append_char_to_raw) - ZEND_FE(zend_test_str_concat_to_raw, arginfo_zend_test_str_concat_to_raw) - ZEND_FE(zend_test_str_concat3_to_raw, arginfo_zend_test_str_concat3_to_raw) ZEND_FE(zend_test_log_err_debug, arginfo_zend_test_log_err_debug) ZEND_FE(zend_test_compile_to_ast, arginfo_zend_test_compile_to_ast) ZEND_FE(zend_test_gh18756, arginfo_zend_test_gh18756) From 695cbbbdd492c8f26cfcd4162de8d7f07ef417cb Mon Sep 17 00:00:00 2001 From: lamentxu <1372449351@qq.com> Date: Fri, 3 Apr 2026 09:41:55 +0800 Subject: [PATCH 4/6] apply suggestions from code review --- Zend/zend_string.h | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/Zend/zend_string.h b/Zend/zend_string.h index 998e7f091aa2a..9811fdd218cd7 100644 --- a/Zend/zend_string.h +++ b/Zend/zend_string.h @@ -316,8 +316,8 @@ static zend_always_inline zend_string *zend_string_safe_realloc(zend_string *s, return ret; } -static zend_always_inline char *zend_str_append_char_to_raw(const char *str, size_t len, char c) { - char *res = (char *)emalloc(len + 2); +static zend_always_inline char *zend_string_append_char_to_raw(const char *str, size_t len, char c) { + char *res = (char *)safe_emalloc(len, 1, 2); if (len > 0) { memcpy(res, str, len); } @@ -326,8 +326,8 @@ static zend_always_inline char *zend_str_append_char_to_raw(const char *str, siz return res; } -static zend_always_inline char *zend_str_concat_to_raw(const char *s1, size_t len1, const char *s2, size_t len2) { - char *res = (char *)emalloc(len1 + len2 + 1); +static zend_always_inline char *zend_string_concat_to_raw(const char *s1, size_t len1, const char *s2, size_t len2) { + char *res = (char *)safe_emalloc(len1, 1, len2 + 1); if (len1 > 0) { memcpy(res, s1, len1); } @@ -338,9 +338,8 @@ static zend_always_inline char *zend_str_concat_to_raw(const char *s1, size_t le return res; } -static zend_always_inline char *zend_str_concat3_to_raw(const char *s1, size_t len1, const char *s2, size_t len2, const char *s3, size_t len3) { - size_t total_len = len1 + len2 + len3; - char *res = (char *)emalloc(total_len + 1); +static zend_always_inline char *zend_string_concat3_to_raw(const char *s1, size_t len1, const char *s2, size_t len2, const char *s3, size_t len3) { + char *res = (char *)safe_emalloc(len1, 1, len2 + len3 + 1); if (len1 > 0) { memcpy(res, s1, len1); } @@ -350,7 +349,7 @@ static zend_always_inline char *zend_str_concat3_to_raw(const char *s1, size_t l if (len3 > 0) { memcpy(res + len1 + len2, s3, len3); } - res[total_len] = '\0'; + res[len1 + len2 + len3] = '\0'; return res; } From b6d3514e9cbc9f27e5a995c1cfe664ea475b3263 Mon Sep 17 00:00:00 2001 From: lamentxu <1372449351@qq.com> Date: Fri, 3 Apr 2026 14:09:12 +0800 Subject: [PATCH 5/6] Update zend_string.h --- Zend/zend_string.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Zend/zend_string.h b/Zend/zend_string.h index 9811fdd218cd7..063b1de6e8abd 100644 --- a/Zend/zend_string.h +++ b/Zend/zend_string.h @@ -316,7 +316,7 @@ static zend_always_inline zend_string *zend_string_safe_realloc(zend_string *s, return ret; } -static zend_always_inline char *zend_string_append_char_to_raw(const char *str, size_t len, char c) { +static zend_always_inline char *zend_string_append_char_to_cstr(const char *str, size_t len, char c) { char *res = (char *)safe_emalloc(len, 1, 2); if (len > 0) { memcpy(res, str, len); @@ -326,7 +326,7 @@ static zend_always_inline char *zend_string_append_char_to_raw(const char *str, return res; } -static zend_always_inline char *zend_string_concat_to_raw(const char *s1, size_t len1, const char *s2, size_t len2) { +static zend_always_inline char *zend_string_concat_to_cstr(const char *s1, size_t len1, const char *s2, size_t len2) { char *res = (char *)safe_emalloc(len1, 1, len2 + 1); if (len1 > 0) { memcpy(res, s1, len1); @@ -338,7 +338,7 @@ static zend_always_inline char *zend_string_concat_to_raw(const char *s1, size_t return res; } -static zend_always_inline char *zend_string_concat3_to_raw(const char *s1, size_t len1, const char *s2, size_t len2, const char *s3, size_t len3) { +static zend_always_inline char *zend_string_concat3_to_cstr(const char *s1, size_t len1, const char *s2, size_t len2, const char *s3, size_t len3) { char *res = (char *)safe_emalloc(len1, 1, len2 + len3 + 1); if (len1 > 0) { memcpy(res, s1, len1); From 19fbe9162e739beb58bda96917272db2d33d99ed Mon Sep 17 00:00:00 2001 From: lamentxu <1372449351@qq.com> Date: Fri, 3 Apr 2026 14:33:16 +0800 Subject: [PATCH 6/6] Update zend_string.h --- Zend/zend_string.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Zend/zend_string.h b/Zend/zend_string.h index 063b1de6e8abd..30fa7ff735f34 100644 --- a/Zend/zend_string.h +++ b/Zend/zend_string.h @@ -316,7 +316,7 @@ static zend_always_inline zend_string *zend_string_safe_realloc(zend_string *s, return ret; } -static zend_always_inline char *zend_string_append_char_to_cstr(const char *str, size_t len, char c) { +static zend_always_inline char *zend_cstr_append_char(const char *str, size_t len, char c) { char *res = (char *)safe_emalloc(len, 1, 2); if (len > 0) { memcpy(res, str, len); @@ -326,7 +326,7 @@ static zend_always_inline char *zend_string_append_char_to_cstr(const char *str, return res; } -static zend_always_inline char *zend_string_concat_to_cstr(const char *s1, size_t len1, const char *s2, size_t len2) { +static zend_always_inline char *zend_cstr_concat(const char *s1, size_t len1, const char *s2, size_t len2) { char *res = (char *)safe_emalloc(len1, 1, len2 + 1); if (len1 > 0) { memcpy(res, s1, len1); @@ -338,7 +338,7 @@ static zend_always_inline char *zend_string_concat_to_cstr(const char *s1, size_ return res; } -static zend_always_inline char *zend_string_concat3_to_cstr(const char *s1, size_t len1, const char *s2, size_t len2, const char *s3, size_t len3) { +static zend_always_inline char *zend_cstr_concat3(const char *s1, size_t len1, const char *s2, size_t len2, const char *s3, size_t len3) { char *res = (char *)safe_emalloc(len1, 1, len2 + len3 + 1); if (len1 > 0) { memcpy(res, s1, len1);