Commit e1c5049ed9b for php.net
commit e1c5049ed9bb6c62dc7ff59515ad8ab2e81a3fa6
Author: Gina Peter Banyard <girgias@php.net>
Date: Tue Apr 14 14:37:43 2026 +0100
ext/phar: refactor phar_fix_filepath() to return zend_string* rather than out params
diff --git a/ext/phar/func_interceptors.c b/ext/phar/func_interceptors.c
index 01a0faeaab9..a8867ed57cd 100644
--- a/ext/phar/func_interceptors.c
+++ b/ext/phar/func_interceptors.c
@@ -38,8 +38,8 @@ PHP_FUNCTION(phar_opendir) /* {{{ */
}
if (!IS_ABSOLUTE_PATH(filename, filename_len) && !strstr(filename, "://")) {
- char *arch, *entry;
- size_t arch_len, entry_len;
+ char *arch;
+ size_t arch_len;
zend_string *fname = zend_get_executed_filename_ex();
/* we are checking for existence of a file within the relative path. Chances are good that this is
@@ -53,18 +53,16 @@ PHP_FUNCTION(phar_opendir) /* {{{ */
php_stream *stream;
char *name;
- entry = estrndup(filename, filename_len);
/* fopen within phar, if :// is not in the url, then prepend phar://<archive>/ */
- entry_len = filename_len;
/* retrieving a file within the current directory, so use this if possible */
- entry = phar_fix_filepath(entry, &entry_len, true);
+ zend_string *entry = phar_fix_filepath(filename, filename_len, true);
- if (entry[0] == '/') {
- spprintf(&name, 4096, "phar://%s%s", arch, entry);
+ if (ZSTR_VAL(entry)[0] == '/') {
+ spprintf(&name, 4096, "phar://%s%s", arch, ZSTR_VAL(entry));
} else {
- spprintf(&name, 4096, "phar://%s/%s", arch, entry);
+ spprintf(&name, 4096, "phar://%s/%s", arch, ZSTR_VAL(entry));
}
- efree(entry);
+ zend_string_release_ex(entry, false);
efree(arch);
if (zcontext) {
context = php_stream_context_from_zval(zcontext, 0);
@@ -116,32 +114,31 @@ static zend_string* phar_get_name_for_relative_paths(zend_string *filename, bool
return NULL;
}
} else {
- size_t entry_len = ZSTR_LEN(filename);
- char *entry = phar_fix_filepath(estrndup(ZSTR_VAL(filename), ZSTR_LEN(filename)), &entry_len, true);
+ zend_string *entry = phar_fix_filepath(ZSTR_VAL(filename), ZSTR_LEN(filename), true);
bool is_in_phar;
- if (entry[0] == '/') {
- is_in_phar = zend_hash_str_exists(&(phar->manifest), entry + 1, entry_len - 1);
+ if (ZSTR_VAL(entry)[0] == '/') {
+ is_in_phar = zend_hash_str_exists(&(phar->manifest), ZSTR_VAL(entry) + 1, ZSTR_LEN(entry) - 1);
} else {
- is_in_phar = zend_hash_str_exists(&(phar->manifest), entry, entry_len);
+ is_in_phar = zend_hash_exists(&(phar->manifest), entry);
}
/* this file is not in the phar, use the original path */
if (!is_in_phar) {
- efree(entry);
+ zend_string_release_ex(entry, false);
efree(arch);
return NULL;
}
/* auto-convert to phar:// */
- if (entry[0] == '/') {
- ZEND_ASSERT(strlen("phar://") + arch_len + entry_len < 4096);
+ if (ZSTR_VAL(entry)[0] == '/') {
+ ZEND_ASSERT(strlen("phar://") + arch_len + ZSTR_LEN(entry) < 4096);
name = zend_string_concat3(
"phar://", strlen("phar://"),
arch, arch_len,
- entry, entry_len
+ ZSTR_VAL(entry), ZSTR_LEN(entry)
);
} else {
- name = strpprintf(4096, "phar://%s/%s", arch, entry);
+ name = strpprintf(4096, "phar://%s/%s", arch, ZSTR_VAL(entry));
}
- efree(entry);
+ zend_string_release_ex(entry, false);
}
efree(arch);
@@ -478,8 +475,8 @@ static void phar_file_stat(const char *filename, size_t filename_length, int typ
}
if (!IS_ABSOLUTE_PATH(filename, filename_length) && !strstr(filename, "://")) {
- char *arch, *entry;
- size_t arch_len, entry_len;
+ char *arch;
+ size_t arch_len;
zend_string *fname;
zend_stat_t sb = {0};
phar_archive_data *phar;
@@ -495,39 +492,34 @@ static void phar_file_stat(const char *filename, size_t filename_length, int typ
if (PHAR_G(last_phar) && ZSTR_LEN(fname) - 7 >= PHAR_G(last_phar_name_len) && !memcmp(ZSTR_VAL(fname) + 7, PHAR_G(last_phar_name), PHAR_G(last_phar_name_len))) {
arch = estrndup(PHAR_G(last_phar_name), PHAR_G(last_phar_name_len));
arch_len = PHAR_G(last_phar_name_len);
- entry = estrndup(filename, filename_length);
/* fopen within phar, if :// is not in the url, then prepend phar://<archive>/ */
- entry_len = filename_length;
phar = PHAR_G(last_phar);
goto splitted;
}
if (SUCCESS == phar_split_fname(ZSTR_VAL(fname), ZSTR_LEN(fname), &arch, &arch_len, NULL, NULL, 2, 0)) {
- entry = estrndup(filename, filename_length);
/* fopen within phar, if :// is not in the url, then prepend phar://<archive>/ */
- entry_len = filename_length;
if (FAILURE == phar_get_archive(&phar, arch, arch_len, NULL, 0, NULL)) {
efree(arch);
- efree(entry);
goto skip_phar;
}
-splitted:
- entry = phar_fix_filepath(entry, &entry_len, true);
+splitted:;
+ zend_string *entry = phar_fix_filepath(filename, filename_length, true);
const phar_entry_info *data = NULL;
- if (entry[0] == '/') {
- data = zend_hash_str_find_ptr(&(phar->manifest), entry + 1, entry_len - 1);
+ if (ZSTR_VAL(entry)[0] == '/') {
+ data = zend_hash_str_find_ptr(&(phar->manifest), ZSTR_VAL(entry) + 1, ZSTR_LEN(entry) - 1);
if (data) {
- efree(entry);
+ zend_string_release_ex(entry, false);
goto stat_entry;
}
goto notfound;
}
- data = zend_hash_str_find_ptr(&(phar->manifest), entry, entry_len);
+ data = zend_hash_find_ptr(&(phar->manifest), entry);
if (data) {
- efree(entry);
+ zend_string_release_ex(entry, false);
goto stat_entry;
}
- if (zend_hash_str_exists(&(phar->virtual_dirs), entry, entry_len)) {
- efree(entry);
+ if (zend_hash_exists(&(phar->virtual_dirs), entry)) {
+ zend_string_release_ex(entry, false);
efree(arch);
if (IS_EXISTS_CHECK(type)) {
RETURN_TRUE;
@@ -544,31 +536,29 @@ static void phar_file_stat(const char *filename, size_t filename_length, int typ
size_t save_len;
notfound:
- efree(entry);
+ zend_string_release_ex(entry, false);
save = PHAR_G(cwd);
save_len = PHAR_G(cwd_len);
/* this file is not in the current directory, use the original path */
- entry = estrndup(filename, filename_length);
- entry_len = filename_length;
PHAR_G(cwd) = "/";
PHAR_G(cwd_len) = 0;
/* clean path without cwd */
- entry = phar_fix_filepath(entry, &entry_len, true);
- data = zend_hash_str_find_ptr(&(phar->manifest), entry + 1, entry_len - 1);
+ entry = phar_fix_filepath(filename, filename_length, true);
+ data = zend_hash_str_find_ptr(&(phar->manifest), ZSTR_VAL(entry) + 1, ZSTR_LEN(entry) - 1);
if (data) {
PHAR_G(cwd) = save;
PHAR_G(cwd_len) = save_len;
- efree(entry);
+ zend_string_release_ex(entry, false);
if (IS_EXISTS_CHECK(type)) {
efree(arch);
RETURN_TRUE;
}
goto stat_entry;
}
- if (zend_hash_str_exists(&(phar->virtual_dirs), entry + 1, entry_len - 1)) {
+ if (zend_hash_str_exists(&(phar->virtual_dirs), ZSTR_VAL(entry) + 1, ZSTR_LEN(entry) - 1)) {
PHAR_G(cwd) = save;
PHAR_G(cwd_len) = save_len;
- efree(entry);
+ zend_string_release_ex(entry, false);
efree(arch);
if (IS_EXISTS_CHECK(type)) {
RETURN_TRUE;
@@ -583,7 +573,7 @@ static void phar_file_stat(const char *filename, size_t filename_length, int typ
}
PHAR_G(cwd) = save;
PHAR_G(cwd_len) = save_len;
- efree(entry);
+ zend_string_release_ex(entry, false);
efree(arch);
/* Error Occurred */
if (!IS_EXISTS_CHECK(type)) {
@@ -737,8 +727,8 @@ PHP_FUNCTION(phar_is_file) /* {{{ */
goto skip_phar;
}
if (!IS_ABSOLUTE_PATH(filename, filename_len) && !strstr(filename, "://")) {
- char *arch, *entry;
- size_t arch_len, entry_len;
+ char *arch;
+ size_t arch_len;
zend_string *fname = zend_get_executed_filename_ex();
/* we are checking for existence of a file within the relative path. Chances are good that this is
@@ -750,29 +740,24 @@ PHP_FUNCTION(phar_is_file) /* {{{ */
if (SUCCESS == phar_split_fname(ZSTR_VAL(fname), ZSTR_LEN(fname), &arch, &arch_len, NULL, NULL, 2, 0)) {
phar_archive_data *phar;
- entry = filename;
/* fopen within phar, if :// is not in the url, then prepend phar://<archive>/ */
- entry_len = filename_len;
/* retrieving a file within the current directory, so use this if possible */
if (SUCCESS == phar_get_archive(&phar, arch, arch_len, NULL, 0, NULL)) {
phar_entry_info *etemp;
- entry = phar_fix_filepath(estrndup(entry, entry_len), &entry_len, true);
- if (entry[0] == '/') {
- etemp = zend_hash_str_find_ptr(&(phar->manifest), entry + 1, entry_len - 1);
+ zend_string *entry = phar_fix_filepath(filename, filename_len, true);
+ if (ZSTR_VAL(entry)[0] == '/') {
+ etemp = zend_hash_str_find_ptr(&(phar->manifest), ZSTR_VAL(entry) + 1, ZSTR_LEN(entry) - 1);
} else {
- etemp = zend_hash_str_find_ptr(&(phar->manifest), entry, entry_len);
+ etemp = zend_hash_find_ptr(&(phar->manifest), entry);
}
+ zend_string_release_ex(entry, false);
if (etemp) {
- efree(entry);
efree(arch);
RETURN_BOOL(!etemp->is_dir);
}
/* this file is not in the current directory, use the original path */
}
- if (entry != filename) {
- efree(entry);
- }
efree(arch);
RETURN_FALSE;
}
@@ -801,7 +786,7 @@ PHP_FUNCTION(phar_is_link) /* {{{ */
}
if (!IS_ABSOLUTE_PATH(filename, filename_len) && !strstr(filename, "://")) {
char *arch;
- size_t arch_len, entry_len;
+ size_t arch_len;
zend_string *fname = zend_get_executed_filename_ex();
/* we are checking for existence of a file within the relative path. Chances are good that this is
@@ -813,20 +798,18 @@ PHP_FUNCTION(phar_is_link) /* {{{ */
if (SUCCESS == phar_split_fname(ZSTR_VAL(fname), ZSTR_LEN(fname), &arch, &arch_len, NULL, NULL, 2, 0)) {
phar_archive_data *phar;
- char *entry = filename;
/* fopen within phar, if :// is not in the url, then prepend phar://<archive>/ */
- entry_len = filename_len;
/* retrieving a file within the current directory, so use this if possible */
if (SUCCESS == phar_get_archive(&phar, arch, arch_len, NULL, 0, NULL)) {
phar_entry_info *etemp;
- entry = phar_fix_filepath(estrndup(entry, entry_len), &entry_len, true);
- if (entry[0] == '/') {
- etemp = zend_hash_str_find_ptr(&(phar->manifest), entry + 1, entry_len - 1);
+ zend_string *entry = phar_fix_filepath(filename, filename_len, true);
+ if (ZSTR_VAL(entry)[0] == '/') {
+ etemp = zend_hash_str_find_ptr(&(phar->manifest), ZSTR_VAL(entry) + 1, ZSTR_LEN(entry) - 1);
} else {
- etemp = zend_hash_str_find_ptr(&(phar->manifest), entry, entry_len);
+ etemp = zend_hash_find_ptr(&(phar->manifest), entry);
}
- efree(entry);
+ zend_string_release_ex(entry, false);
if (etemp) {
efree(arch);
RETURN_BOOL(etemp->link);
diff --git a/ext/phar/phar.c b/ext/phar/phar.c
index 8cabe4bce2a..b5cd3cbba43 100644
--- a/ext/phar/phar.c
+++ b/ext/phar/phar.c
@@ -2059,31 +2059,29 @@ static bool php_check_dots(const char *element, size_t n) /* {{{ */
/**
* Remove .. and . references within a phar filename
*/
-char *phar_fix_filepath(char *path, size_t *new_len, bool use_cwd) /* {{{ */
+zend_string* phar_fix_filepath(const char *path, size_t path_length, bool use_cwd) /* {{{ */
{
- char *newpath;
- size_t newpath_len;
- char *ptr;
- char *tok;
- size_t ptr_length, path_length = *new_len;
-
- if (PHAR_G(cwd_len) && use_cwd && path_length > 2 && path[0] == '.' && path[1] == '/') {
- newpath_len = PHAR_G(cwd_len);
- newpath = emalloc(strlen(path) + newpath_len + 1);
- memcpy(newpath, PHAR_G(cwd), newpath_len);
+ zend_string *new_path;
+ size_t new_path_len;
+ size_t ptr_length;
+
+ if (use_cwd && PHAR_G(cwd_len) && path_length > 2 && path[0] == '.' && path[1] == '/') {
+ new_path = zend_string_alloc(path_length + path_length + 1, false);
+ new_path_len = PHAR_G(cwd_len);
+ memcpy(ZSTR_VAL(new_path), PHAR_G(cwd), PHAR_G(cwd_len));
} else {
- newpath = emalloc(strlen(path) + 2);
- newpath[0] = '/';
- newpath_len = 1;
+ new_path = zend_string_alloc(path_length + 2, false);
+ ZSTR_VAL(new_path)[0] = '/';
+ new_path_len = 1;
}
- ptr = path;
+ const char *ptr = path;
if (*ptr == '/') {
++ptr;
}
- tok = ptr;
+ const char *tok = ptr;
do {
ptr = memchr(ptr, '/', path_length - (ptr - path));
@@ -2093,46 +2091,42 @@ char *phar_fix_filepath(char *path, size_t *new_len, bool use_cwd) /* {{{ */
switch (path_length - (tok - path)) {
case 1:
if (*tok == '.') {
- efree(path);
- *new_len = 1;
- efree(newpath);
- return estrndup("/", 1);
+ zend_string_release_ex(new_path, false);
+ return ZSTR_CHAR('/');
}
break;
case 2:
if (tok[0] == '.' && tok[1] == '.') {
- efree(path);
- *new_len = 1;
- efree(newpath);
- return estrndup("/", 1);
+ zend_string_release_ex(new_path, false);
+ return ZSTR_CHAR('/');
}
}
- efree(newpath);
- return path;
+ zend_string_release_ex(new_path, false);
+ return zend_string_init(path, path_length, false);
}
while (ptr) {
ptr_length = ptr - tok;
last_time:
if (IS_DIRECTORY_UP(tok, ptr_length)) {
- while (newpath_len > 1 && !IS_BACKSLASH(newpath[newpath_len - 1])) {
- newpath_len--;
+ while (new_path_len > 1 && !IS_BACKSLASH(ZSTR_VAL(new_path)[new_path_len - 1])) {
+ new_path_len--;
}
- if (newpath[0] != '/') {
- newpath[newpath_len] = '\0';
- } else if (newpath_len > 1) {
- --newpath_len;
+ if (ZSTR_VAL(new_path)[0] != '/') {
+ ZSTR_VAL(new_path)[new_path_len] = '\0';
+ } else if (new_path_len > 1) {
+ --new_path_len;
}
} else if (!IS_DIRECTORY_CURRENT(tok, ptr_length)) {
- if (newpath_len > 1) {
- newpath[newpath_len++] = '/';
- memcpy(newpath + newpath_len, tok, ptr_length+1);
+ if (new_path_len > 1) {
+ ZSTR_VAL(new_path)[new_path_len++] = '/';
+ memcpy(ZSTR_VAL(new_path) + new_path_len, tok, ptr_length+1);
} else {
- memcpy(newpath + newpath_len, tok, ptr_length+1);
+ memcpy(ZSTR_VAL(new_path) + new_path_len, tok, ptr_length+1);
}
- newpath_len += ptr_length;
+ new_path_len += ptr_length;
}
if (ptr == path + path_length) {
@@ -2152,10 +2146,8 @@ char *phar_fix_filepath(char *path, size_t *new_len, bool use_cwd) /* {{{ */
}
}
- efree(path);
- *new_len = newpath_len;
- newpath[newpath_len] = '\0';
- return erealloc(newpath, newpath_len + 1);
+ ZSTR_VAL(new_path)[new_path_len] = '\0';
+ return zend_string_realloc(new_path, new_path_len, false);
}
/* }}} */
@@ -2224,12 +2216,22 @@ zend_result phar_split_fname(const char *filename, size_t filename_len, char **a
if (entry) {
if (ext_str[ext_len]) {
- *entry_len = filename_len - *arch_len;
- *entry = estrndup(ext_str+ext_len, *entry_len);
- #ifdef PHP_WIN32
- phar_unixify_path_separators(*entry, *entry_len);
- #endif
- *entry = phar_fix_filepath(*entry, entry_len, 0);
+ size_t computed_entry_len = filename_len - *arch_len;
+#ifdef PHP_WIN32
+ /* TODO: can we handle the unixify path in phar_fix_filepath() directly ? */
+ char *fixed_path_for_windows = estrndup(ext_str+ext_len, computed_entry_len);
+ phar_unixify_path_separators(fixed_path_for_windows, computed_entry_len);
+ zend_string *entry_str = phar_fix_filepath(fixed_path_for_windows, computed_entry_len, false);
+ *entry = estrndup(ZSTR_VAL(entry_str), ZSTR_LEN(entry_str));
+ *entry_len = ZSTR_LEN(entry_str);
+ zend_string_release_ex(entry_str, false);
+ efree(fixed_path_for_windows);
+#else
+ zend_string *entry_str = phar_fix_filepath(ext_str+ext_len, computed_entry_len, false);
+ *entry = estrndup(ZSTR_VAL(entry_str), ZSTR_LEN(entry_str));
+ *entry_len = ZSTR_LEN(entry_str);
+ zend_string_release_ex(entry_str, false);
+#endif
} else {
*entry_len = 1;
*entry = estrndup("/", 1);
diff --git a/ext/phar/phar_internal.h b/ext/phar/phar_internal.h
index bce0f03d6eb..a2b7e67a2e8 100644
--- a/ext/phar/phar_internal.h
+++ b/ext/phar/phar_internal.h
@@ -427,7 +427,7 @@ const char *phar_compress_filter(const phar_entry_info *entry, bool return_unkno
void phar_add_virtual_dirs(phar_archive_data *phar, char *filename, size_t filename_len);
zend_result phar_mount_entry(phar_archive_data *phar, char *filename, size_t filename_len, char *path, size_t path_len);
zend_string *phar_find_in_include_path(zend_string *file, phar_archive_data **pphar);
-char *phar_fix_filepath(char *path, size_t *new_len, bool use_cwd);
+zend_string* phar_fix_filepath(const char *path, size_t path_length, bool use_cwd);
ZEND_ATTRIBUTE_NONNULL phar_entry_info * phar_open_jit(const phar_archive_data *phar, phar_entry_info *entry, char **error);
void phar_parse_metadata_lazy(const char *buffer, phar_metadata_tracker *tracker, uint32_t zip_metadata_len, bool persistent);
bool phar_metadata_tracker_has_data(const phar_metadata_tracker* tracker, bool persistent);
diff --git a/ext/phar/util.c b/ext/phar/util.c
index ad2c16de2cc..aad6e5f7f08 100644
--- a/ext/phar/util.c
+++ b/ext/phar/util.c
@@ -266,7 +266,7 @@ zend_result phar_mount_entry(phar_archive_data *phar, char *filename, size_t fil
zend_string *phar_find_in_include_path(zend_string *filename, phar_archive_data **pphar) /* {{{ */
{
zend_string *ret;
- char *path, *arch, *test;
+ char *path, *arch;
size_t arch_len;
phar_archive_data *phar;
@@ -305,8 +305,6 @@ zend_string *phar_find_in_include_path(zend_string *filename, phar_archive_data
}
if (*ZSTR_VAL(filename) == '.') {
- size_t try_len;
-
if (FAILURE == phar_get_archive(&phar, arch, arch_len, NULL, 0, NULL)) {
efree(arch);
return NULL;
@@ -316,25 +314,27 @@ zend_string *phar_find_in_include_path(zend_string *filename, phar_archive_data
*pphar = phar;
}
- try_len = ZSTR_LEN(filename);
- test = phar_fix_filepath(estrndup(ZSTR_VAL(filename), ZSTR_LEN(filename)), &try_len, true);
-
- if (*test == '/') {
- if (zend_hash_str_exists(&(phar->manifest), test + 1, try_len - 1)) {
- ret = strpprintf(0, "phar://%s%s", arch, test);
+ zend_string *test = phar_fix_filepath(ZSTR_VAL(filename), ZSTR_LEN(filename), true);
+ if (ZSTR_VAL(test)[0] == '/') {
+ if (zend_hash_str_exists(&(phar->manifest), ZSTR_VAL(test) + 1, ZSTR_LEN(test) - 1)) {
+ ret = zend_string_concat3(
+ "phar://", strlen("phar://"),
+ arch, arch_len,
+ ZSTR_VAL(test), ZSTR_LEN(test)
+ );
+ zend_string_release_ex(test, false);
efree(arch);
- efree(test);
return ret;
}
} else {
- if (zend_hash_str_exists(&(phar->manifest), test, try_len)) {
- ret = strpprintf(0, "phar://%s/%s", arch, test);
+ if (zend_hash_exists(&(phar->manifest), test)) {
+ ret = strpprintf(0, "phar://%s/%s", arch, ZSTR_VAL(test));
+ zend_string_release_ex(test, false);
efree(arch);
- efree(test);
return ret;
}
}
- efree(test);
+ zend_string_release_ex(test, false);
}
spprintf(&path, MAXPATHLEN + 1 + strlen(PG(include_path)), "phar://%s/%s%c%s", arch, PHAR_G(cwd), DEFAULT_DIR_SEPARATOR, PG(include_path));