Skip to content
52 changes: 34 additions & 18 deletions Zend/zend_string.h
Original file line number Diff line number Diff line change
Expand Up @@ -71,33 +71,49 @@ END_EXTERN_C()

/*---*/

#define ZSTR_IS_INTERNED(s) (GC_FLAGS(s) & IS_STR_INTERNED)
#define ZSTR_IS_VALID_UTF8(s) (GC_FLAGS(s) & IS_STR_VALID_UTF8)
static zend_always_inline bool ZSTR_IS_INTERNED(const zend_string *s) {
return GC_FLAGS(s) & IS_STR_INTERNED;
}

static inline bool ZSTR_IS_VALID_UTF8(const zend_string *s) {
return GC_FLAGS(s) & IS_STR_VALID_UTF8;
}

/* These are properties, encoded as flags, that will hold on the resulting string
* after concatenating two strings that have these property.
* Example: concatenating two UTF-8 strings yields another UTF-8 string. */
#define ZSTR_COPYABLE_CONCAT_PROPERTIES (IS_STR_VALID_UTF8)

#define ZSTR_GET_COPYABLE_CONCAT_PROPERTIES(s) (GC_FLAGS(s) & ZSTR_COPYABLE_CONCAT_PROPERTIES)
/* This macro returns the copyable concat properties which hold on both strings. */
#define ZSTR_GET_COPYABLE_CONCAT_PROPERTIES_BOTH(s1, s2) (GC_FLAGS(s1) & GC_FLAGS(s2) & ZSTR_COPYABLE_CONCAT_PROPERTIES)
static inline uint32_t ZSTR_GET_COPYABLE_CONCAT_PROPERTIES(const zend_string *s) {
return GC_FLAGS(s) & ZSTR_COPYABLE_CONCAT_PROPERTIES;
}

#define ZSTR_COPY_CONCAT_PROPERTIES(out, in) do { \
zend_string *_out = (out); \
uint32_t properties = ZSTR_GET_COPYABLE_CONCAT_PROPERTIES((in)); \
GC_ADD_FLAGS(_out, properties); \
} while (0)
/* This function returns the copyable concat properties which hold on both strings. */
static inline uint32_t ZSTR_GET_COPYABLE_CONCAT_PROPERTIES_BOTH(const zend_string *s1, const zend_string *s2) {
return ZSTR_GET_COPYABLE_CONCAT_PROPERTIES(s1) & ZSTR_GET_COPYABLE_CONCAT_PROPERTIES(s2);
}

#define ZSTR_COPY_CONCAT_PROPERTIES_BOTH(out, in1, in2) do { \
zend_string *_out = (out); \
uint32_t properties = ZSTR_GET_COPYABLE_CONCAT_PROPERTIES_BOTH((in1), (in2)); \
GC_ADD_FLAGS(_out, properties); \
} while (0)
static inline void ZSTR_COPY_CONCAT_PROPERTIES(zend_string *out, const zend_string *in) {
uint32_t properties = ZSTR_GET_COPYABLE_CONCAT_PROPERTIES(in);
GC_ADD_FLAGS(out, properties);
}

#define ZSTR_EMPTY_ALLOC() zend_empty_string
#define ZSTR_CHAR(c) zend_one_char_string[c]
#define ZSTR_KNOWN(idx) zend_known_strings[idx]
static inline void ZSTR_COPY_CONCAT_PROPERTIES_BOTH(zend_string *out, const zend_string *in1, const zend_string *in2) {
uint32_t properties = ZSTR_GET_COPYABLE_CONCAT_PROPERTIES_BOTH(in1, in2);
GC_ADD_FLAGS(out, properties);
}

static zend_always_inline zend_string *ZSTR_EMPTY_ALLOC(void) {
return zend_empty_string;
}

static zend_always_inline zend_string *ZSTR_CHAR(unsigned char c) {
return zend_one_char_string[c];
}

static zend_always_inline zend_string *ZSTR_KNOWN(size_t idx) {
return zend_known_strings[idx];
}

#define _ZSTR_HEADER_SIZE XtOffsetOf(zend_string, val)

Expand Down
4 changes: 0 additions & 4 deletions ext/phar/dirstream.c
Original file line number Diff line number Diff line change
Expand Up @@ -287,10 +287,6 @@ php_stream *phar_wrapper_open_dir(php_stream_wrapper *wrapper, const char *path,
return NULL;
}

if (error) {
efree(error);
}

if (zend_string_equals(resource->path, ZSTR_CHAR('/'))) {
/* root directory requested */
php_url_free(resource);
Expand Down
11 changes: 0 additions & 11 deletions ext/phar/phar_object.c
Original file line number Diff line number Diff line change
Expand Up @@ -1655,9 +1655,6 @@ static int phar_build(zend_object_iterator *iter, void *puser) /* {{{ */
return ZEND_HASH_APPLY_STOP;

} else {
if (error) {
efree(error);
}
/* convert to PHAR_UFP */
if (data->internal_file->fp_type == PHAR_MOD) {
php_stream_close(data->internal_file->fp);
Expand Down Expand Up @@ -3603,10 +3600,6 @@ static void phar_add_file(phar_archive_data **pphar, zend_string *file_name, con
}
goto finish;
} else {
if (error) {
efree(error);
}

if (!data->internal_file->is_dir) {
size_t contents_len = 0;
if (content) {
Expand Down Expand Up @@ -3683,10 +3676,6 @@ static void phar_mkdir(phar_archive_data **pphar, zend_string *dir_name)

return;
} else {
if (error) {
efree(error);
}

/* check for copy on write */
if (data->phar != *pphar) {
*pphar = data->phar;
Expand Down
6 changes: 0 additions & 6 deletions ext/phar/stream.c
Original file line number Diff line number Diff line change
Expand Up @@ -200,9 +200,6 @@ static php_stream * phar_wrapper_open_url(php_stream_wrapper *wrapper, const cha
php_url_free(resource);
return NULL;
}
if (error) {
efree(error);
}
fpf = php_stream_alloc(&phar_ops, idata, NULL, mode);
php_url_free(resource);
efree(internal_file);
Expand Down Expand Up @@ -706,9 +703,6 @@ static int phar_wrapper_unlink(php_stream_wrapper *wrapper, const char *url, int
php_url_free(resource);
return 0;
}
if (error) {
efree(error);
}
if (idata->internal_file->fp_refcount > 1) {
/* more than just our fp resource is open for this file */
php_stream_wrapper_log_error(wrapper, options, "phar error: \"%s\" in phar \"%s\", has open file pointers, cannot unlink", internal_file, ZSTR_VAL(resource->host));
Expand Down
136 changes: 59 additions & 77 deletions ext/phar/util.c
Original file line number Diff line number Diff line change
Expand Up @@ -962,8 +962,7 @@ zend_result phar_free_alias(const phar_archive_data *phar) /* {{{ */
*/
zend_result phar_get_archive(phar_archive_data **archive, const char *fname, size_t fname_len, const char *alias, size_t alias_len, char **error) /* {{{ */
{
phar_archive_data *fd, *fd_ptr;
char *my_realpath;
phar_archive_data *fd_ptr;

phar_request_initialize();

Expand All @@ -985,7 +984,7 @@ zend_result phar_get_archive(phar_archive_data **archive, const char *fname, siz
return FAILURE;
}

if (PHAR_G(last_phar)->alias_len && NULL != (fd_ptr = zend_hash_str_find_ptr(&(PHAR_G(phar_alias_map)), PHAR_G(last_phar)->alias, PHAR_G(last_phar)->alias_len))) {
if (PHAR_G(last_phar)->alias_len && zend_hash_str_exists(&(PHAR_G(phar_alias_map)), PHAR_G(last_phar)->alias, PHAR_G(last_phar)->alias_len)) {
zend_hash_str_del(&(PHAR_G(phar_alias_map)), PHAR_G(last_phar)->alias, PHAR_G(last_phar)->alias_len);
}

Expand All @@ -997,16 +996,20 @@ zend_result phar_get_archive(phar_archive_data **archive, const char *fname, siz
return SUCCESS;
}

if (alias && alias_len && PHAR_G(last_phar) && alias_len == PHAR_G(last_alias_len) && !memcmp(alias, PHAR_G(last_alias), alias_len)) {
fd = PHAR_G(last_phar);
fd_ptr = fd;
goto alias_success;
}

if (alias && alias_len) {
fd_ptr = zend_hash_str_find_ptr(&(PHAR_G(phar_alias_map)), alias, alias_len);
/* If the alias stored in the last_phar cache matches, just use it directly */
if (PHAR_G(last_phar) && alias_len == PHAR_G(last_alias_len) && !memcmp(alias, PHAR_G(last_alias), alias_len)) {
fd_ptr = PHAR_G(last_phar);
} else {
fd_ptr = zend_hash_str_find_ptr(&(PHAR_G(phar_alias_map)), alias, alias_len);
}

/* If we didn't find the alias, check in the cached manifest to see if we can find it */
if (!fd_ptr && PHAR_G(manifest_cached)) {
fd_ptr = zend_hash_str_find_ptr(&cached_alias, alias, alias_len);
}

if (fd_ptr) {
alias_success:
if (!zend_string_equals_cstr(fd_ptr->fname, fname, fname_len)) {
if (error) {
spprintf(error, 0, "alias \"%s\" is already used for archive \"%s\" cannot be overloaded with \"%s\"", alias, ZSTR_VAL(fd_ptr->fname), fname);
Expand All @@ -1021,138 +1024,117 @@ zend_result phar_get_archive(phar_archive_data **archive, const char *fname, siz
}

*archive = fd_ptr;
fd = fd_ptr;
PHAR_G(last_phar) = fd;
PHAR_G(last_phar_name) = fd->fname;
PHAR_G(last_phar) = fd_ptr;
PHAR_G(last_phar_name) = fd_ptr->fname;
PHAR_G(last_alias) = alias;
PHAR_G(last_alias_len) = alias_len;

return SUCCESS;
}

if (PHAR_G(manifest_cached) && NULL != (fd_ptr = zend_hash_str_find_ptr(&cached_alias, alias, alias_len))) {
goto alias_success;
}
}

my_realpath = NULL;
const char *save = fname;
size_t save_len = fname_len;

if (fname && fname_len) {
fd_ptr = zend_hash_str_find_ptr(&(PHAR_G(phar_fname_map)), fname, fname_len);
if (fd_ptr) {
*archive = fd_ptr;
fd = fd_ptr;

if (alias && alias_len) {
if (!fd->is_temporary_alias && (alias_len != fd->alias_len || memcmp(fd->alias, alias, alias_len))) {
if (!fd_ptr->is_temporary_alias && (alias_len != fd_ptr->alias_len || memcmp(fd_ptr->alias, alias, alias_len))) {
if (error) {
spprintf(error, 0, "alias \"%s\" is already used for archive \"%s\" cannot be overloaded with \"%s\"", alias, ZSTR_VAL(fd_ptr->fname), fname);
}
return FAILURE;
}

if (fd->alias_len && NULL != (fd_ptr = zend_hash_str_find_ptr(&(PHAR_G(phar_alias_map)), fd->alias, fd->alias_len))) {
zend_hash_str_del(&(PHAR_G(phar_alias_map)), fd->alias, fd->alias_len);
if (fd_ptr->alias_len && zend_hash_str_exists(&(PHAR_G(phar_alias_map)), fd_ptr->alias, fd_ptr->alias_len)) {
zend_hash_str_del(&(PHAR_G(phar_alias_map)), fd_ptr->alias, fd_ptr->alias_len);
}

zend_hash_str_add_ptr(&(PHAR_G(phar_alias_map)), alias, alias_len, fd);
zend_hash_str_add_ptr(&(PHAR_G(phar_alias_map)), alias, alias_len, fd_ptr);
}

PHAR_G(last_phar) = fd;
PHAR_G(last_phar_name) = fd->fname;
PHAR_G(last_alias) = fd->alias;
PHAR_G(last_alias_len) = fd->alias_len;
PHAR_G(last_phar) = fd_ptr;
PHAR_G(last_phar_name) = fd_ptr->fname;
PHAR_G(last_alias) = fd_ptr->alias;
PHAR_G(last_alias_len) = fd_ptr->alias_len;

return SUCCESS;
}

if (PHAR_G(manifest_cached) && NULL != (fd_ptr = zend_hash_str_find_ptr(&cached_phars, fname, fname_len))) {
*archive = fd_ptr;
fd = fd_ptr;

/* this could be problematic - alias should never be different from manifest alias
for cached phars */
if (!fd->is_temporary_alias && alias && alias_len) {
if (alias_len != fd->alias_len || memcmp(fd->alias, alias, alias_len)) {
if (!fd_ptr->is_temporary_alias && alias && alias_len) {
if (alias_len != fd_ptr->alias_len || memcmp(fd_ptr->alias, alias, alias_len)) {
if (error) {
spprintf(error, 0, "alias \"%s\" is already used for archive \"%s\" cannot be overloaded with \"%s\"", alias, ZSTR_VAL(fd_ptr->fname), fname);
}
return FAILURE;
}
}

PHAR_G(last_phar) = fd;
PHAR_G(last_phar_name) = fd->fname;
PHAR_G(last_alias) = fd->alias;
PHAR_G(last_alias_len) = fd->alias_len;
PHAR_G(last_phar) = fd_ptr;
PHAR_G(last_phar_name) = fd_ptr->fname;
PHAR_G(last_alias) = fd_ptr->alias;
PHAR_G(last_alias_len) = fd_ptr->alias_len;

return SUCCESS;
}

fd_ptr = zend_hash_str_find_ptr(&(PHAR_G(phar_alias_map)), save, save_len);
if (fd_ptr) {
fd = *archive = fd_ptr;

PHAR_G(last_phar) = fd;
PHAR_G(last_phar_name) = fd->fname;
PHAR_G(last_alias) = fd->alias;
PHAR_G(last_alias_len) = fd->alias_len;
fd_ptr = zend_hash_str_find_ptr(&(PHAR_G(phar_alias_map)), fname, fname_len);

return SUCCESS;
/* If we didn't find the fname in the alias map, check in the cached manifest to see if we can find it */
if (!fd_ptr && PHAR_G(manifest_cached)) {
fd_ptr = zend_hash_str_find_ptr(&cached_alias, fname, fname_len);
}

if (PHAR_G(manifest_cached) && NULL != (fd_ptr = zend_hash_str_find_ptr(&cached_alias, save, save_len))) {
fd = *archive = fd_ptr;
if (fd_ptr) {
*archive = fd_ptr;

PHAR_G(last_phar) = fd;
PHAR_G(last_phar_name) = fd->fname;
PHAR_G(last_alias) = fd->alias;
PHAR_G(last_alias_len) = fd->alias_len;
PHAR_G(last_phar) = fd_ptr;
PHAR_G(last_phar_name) = fd_ptr->fname;
PHAR_G(last_alias) = fd_ptr->alias;
PHAR_G(last_alias_len) = fd_ptr->alias_len;

return SUCCESS;
}

/* not found, try converting \ to / */
my_realpath = expand_filepath(fname, my_realpath);
char *my_realpath = expand_filepath(fname, NULL);

if (my_realpath) {
size_t my_realpath_len = strlen(my_realpath);
if (UNEXPECTED(!my_realpath)) {
return FAILURE;
}

size_t my_realpath_len = strlen(my_realpath);
#ifdef PHP_WIN32
phar_unixify_path_separators(my_realpath, my_realpath_len);
phar_unixify_path_separators(my_realpath, my_realpath_len);
#endif
fname_len = my_realpath_len;
fname = my_realpath;
} else {
return FAILURE;

fd_ptr = zend_hash_str_find_ptr(&(PHAR_G(phar_fname_map)), my_realpath, my_realpath_len);

/* If we didn't find the path in the fname map, check in the cached manifest to see if we can find it */
if (!fd_ptr && PHAR_G(manifest_cached)) {
fd_ptr = zend_hash_str_find_ptr(&cached_phars, my_realpath, my_realpath_len);
}
efree(my_realpath);

fd_ptr = zend_hash_str_find_ptr(&(PHAR_G(phar_fname_map)), fname, fname_len);
if (fd_ptr) {
realpath_success:
*archive = fd_ptr;
fd = fd_ptr;

if (alias && alias_len) {
zend_hash_str_add_ptr(&(PHAR_G(phar_alias_map)), alias, alias_len, fd);
zend_hash_str_add_ptr(&(PHAR_G(phar_alias_map)), alias, alias_len, fd_ptr);
}

efree(my_realpath);

PHAR_G(last_phar) = fd;
PHAR_G(last_phar_name) = fd->fname;
PHAR_G(last_alias) = fd->alias;
PHAR_G(last_alias_len) = fd->alias_len;
PHAR_G(last_phar) = fd_ptr;
PHAR_G(last_phar_name) = fd_ptr->fname;
PHAR_G(last_alias) = fd_ptr->alias;
PHAR_G(last_alias_len) = fd_ptr->alias_len;

return SUCCESS;
}

if (PHAR_G(manifest_cached) && NULL != (fd_ptr = zend_hash_str_find_ptr(&cached_phars, fname, fname_len))) {
goto realpath_success;
}

efree(my_realpath);
}

return FAILURE;
Expand Down