diff --git a/ext/phar/func_interceptors.c b/ext/phar/func_interceptors.c index 01a0faeaab9e..a8867ed57cd5 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:/// */ - 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:/// */ - 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:/// */ - 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:/// */ - 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:/// */ - 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 8cabe4bce2ab..b5cd3cbba437 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 bce0f03d6eb2..a2b7e67a2e81 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/phar_object.c b/ext/phar/phar_object.c index 5aeedbfcbdd7..f522d52ba6c4 100644 --- a/ext/phar/phar_object.c +++ b/ext/phar/phar_object.c @@ -1179,20 +1179,29 @@ PHP_METHOD(Phar, __construct) phar_obj->archive = phar_data; phar_obj->spl.oth_handler = &phar_spl_foreign_handler; + zend_string *file_name_for_recursive_director_iterator_constructor; if (entry) { - fname_len = spprintf(&fname, 0, "phar://%s%s", phar_data->fname, entry); + file_name_for_recursive_director_iterator_constructor = zend_string_concat3( + ZEND_STRL("phar://"), + phar_data->fname, phar_data->fname_len, + entry, entry_len + ); efree(entry); } else { - fname_len = spprintf(&fname, 0, "phar://%s", phar_data->fname); + file_name_for_recursive_director_iterator_constructor = zend_string_concat2( + ZEND_STRL("phar://"), + phar_data->fname, phar_data->fname_len + ); } - ZVAL_STRINGL(&arg1, fname, fname_len); + ZVAL_STR(&arg1, file_name_for_recursive_director_iterator_constructor); ZVAL_LONG(&arg2, flags); zend_call_known_instance_method_with_2_params(spl_ce_RecursiveDirectoryIterator->constructor, Z_OBJ_P(ZEND_THIS), NULL, &arg1, &arg2); - zval_ptr_dtor(&arg1); + /* Freeing arg1 */ + zend_string_release_ex(file_name_for_recursive_director_iterator_constructor, false); if (!phar_data->is_persistent) { phar_obj->archive->is_data = is_data; @@ -1202,7 +1211,6 @@ PHP_METHOD(Phar, __construct) } phar_obj->spl.info_class = phar_ce_entry; - efree(fname); } /* }}} */ diff --git a/ext/phar/util.c b/ext/phar/util.c index ad2c16de2ccc..aad6e5f7f085 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));