diff --git a/NEWS b/NEWS index 45f40a076078..3da5464750cc 100644 --- a/NEWS +++ b/NEWS @@ -205,6 +205,7 @@ PHP NEWS - Zlib: . deflate_init() now raises a TypeError when the value for option - "strategy" is not of type int. (Weilin Du) + "level", "memory", "window", or "strategy" is not of type int. + (Weilin Du) <<< NOTE: Insert NEWS from last stable release here prior to actual release! >>> diff --git a/UPGRADING b/UPGRADING index df81eb889699..56049f30cf93 100644 --- a/UPGRADING +++ b/UPGRADING @@ -103,7 +103,7 @@ PHP 8.6 UPGRADE NOTES - Zlib: . deflate_init() now raises a TypeError when the value for option - "strategy" is not of type int. + "level", "memory", "window", or "strategy" is not of type int. ======================================== 2. New Features diff --git a/Zend/zend_API.h b/Zend/zend_API.h index 7990726f7e69..7cc9b6ff38dd 100644 --- a/Zend/zend_API.h +++ b/Zend/zend_API.h @@ -524,8 +524,16 @@ ZEND_API const char *zend_get_type_by_const(int type); #define DLEXPORT #endif -#define array_init(arg) ZVAL_ARR((arg), zend_new_array(0)) -#define array_init_size(arg, size) ZVAL_ARR((arg), zend_new_array(size)) +static zend_always_inline void array_init_size(zval *arg, uint32_t size) +{ + ZVAL_ARR(arg, zend_new_array(size)); +} + +static zend_always_inline void array_init(zval *arg) +{ + array_init_size(arg, 0); +} + ZEND_API void object_init(zval *arg); ZEND_API zend_result object_init_ex(zval *arg, zend_class_entry *ce); ZEND_API zend_result object_init_with_constructor(zval *arg, zend_class_entry *class_type, uint32_t param_count, zval *params, HashTable *named_params); diff --git a/Zend/zend_portability.h b/Zend/zend_portability.h index 450e72a60eb5..c5b5fe02929f 100644 --- a/Zend/zend_portability.h +++ b/Zend/zend_portability.h @@ -130,7 +130,9 @@ #endif /* pseudo fallthrough keyword; */ -#if defined(__GNUC__) && __GNUC__ >= 7 +#if __STDC_VERSION__ >= 202311L || defined(__cplusplus) +# define ZEND_FALLTHROUGH [[fallthrough]] +#elif defined(__GNUC__) && __GNUC__ >= 7 # define ZEND_FALLTHROUGH __attribute__((__fallthrough__)) #else # define ZEND_FALLTHROUGH ((void)0) diff --git a/ext/phar/dirstream.c b/ext/phar/dirstream.c index 4bef14dfe6ae..6c356c04e5e1 100644 --- a/ext/phar/dirstream.c +++ b/ext/phar/dirstream.c @@ -19,8 +19,6 @@ #include "phar_internal.h" #include "dirstream.h" -void phar_dostat(phar_archive_data *phar, phar_entry_info *data, php_stream_statbuf *ssb, bool is_dir); - static const php_stream_ops phar_dir_ops = { phar_dir_write, /* write */ phar_dir_read, /* read */ @@ -248,7 +246,6 @@ static php_stream *phar_make_dirstream(const char *dir, size_t dirlen, const Has php_stream *phar_wrapper_open_dir(php_stream_wrapper *wrapper, const char *path, const char *mode, int options, zend_string **opened_path, php_stream_context *context STREAMS_DC) /* {{{ */ { char *error; - phar_archive_data *phar; php_url *resource = phar_parse_url(wrapper, path, mode, options); if (!resource) { @@ -276,7 +273,8 @@ php_stream *phar_wrapper_open_dir(php_stream_wrapper *wrapper, const char *path, phar_request_initialize(); - if (FAILURE == phar_get_archive(&phar, ZSTR_VAL(resource->host), ZSTR_LEN(resource->host), NULL, 0, &error)) { + const phar_archive_data *phar = phar_get_archive(ZSTR_VAL(resource->host), ZSTR_LEN(resource->host), NULL, 0, &error); + if (!phar) { if (error) { php_stream_wrapper_log_error(wrapper, options, "%s", error); efree(error); @@ -300,7 +298,7 @@ php_stream *phar_wrapper_open_dir(php_stream_wrapper *wrapper, const char *path, const char *internal_file = ZSTR_VAL(resource->path) + 1; /* strip leading "/" */ size_t internal_file_len = ZSTR_LEN(resource->path) - 1; - phar_entry_info *entry = zend_hash_str_find_ptr(&phar->manifest, internal_file, internal_file_len); + const phar_entry_info *entry = zend_hash_str_find_ptr(&phar->manifest, internal_file, internal_file_len); php_stream *ret; if (NULL != entry && !entry->is_dir) { @@ -340,7 +338,6 @@ php_stream *phar_wrapper_open_dir(php_stream_wrapper *wrapper, const char *path, int phar_wrapper_mkdir(php_stream_wrapper *wrapper, const char *url_from, int mode, int options, php_stream_context *context) /* {{{ */ { phar_entry_info entry; - phar_archive_data *phar = NULL; char *error; php_url *resource = NULL; @@ -351,9 +348,7 @@ int phar_wrapper_mkdir(php_stream_wrapper *wrapper, const char *url_from, int mo return 0; } - if (FAILURE == phar_get_archive(&phar, ZSTR_VAL(arch), ZSTR_LEN(arch), NULL, 0, NULL)) { - phar = NULL; - } + phar_archive_data *phar = phar_get_archive(ZSTR_VAL(arch), ZSTR_LEN(arch), NULL, 0, NULL); zend_string_release_ex(arch, false); @@ -379,7 +374,8 @@ int phar_wrapper_mkdir(php_stream_wrapper *wrapper, const char *url_from, int mo return 0; } - if (FAILURE == phar_get_archive(&phar, ZSTR_VAL(resource->host), ZSTR_LEN(resource->host), NULL, 0, &error)) { + phar = phar_get_archive(ZSTR_VAL(resource->host), ZSTR_LEN(resource->host), NULL, 0, &error); + if (!phar) { php_stream_wrapper_log_error(wrapper, options, "phar error: cannot create directory \"%s\" in phar \"%s\", error retrieving phar information: %s", ZSTR_VAL(resource->path) + 1, ZSTR_VAL(resource->host), error); efree(error); php_url_free(resource); @@ -467,7 +463,6 @@ int phar_wrapper_mkdir(php_stream_wrapper *wrapper, const char *url_from, int mo */ int phar_wrapper_rmdir(php_stream_wrapper *wrapper, const char *url, int options, php_stream_context *context) /* {{{ */ { - phar_archive_data *phar = NULL; char *error; /* pre-readonly check, we need to know if this is a data phar */ @@ -477,9 +472,7 @@ int phar_wrapper_rmdir(php_stream_wrapper *wrapper, const char *url, int options return 0; } - if (FAILURE == phar_get_archive(&phar, ZSTR_VAL(arch), ZSTR_LEN(arch), NULL, 0, NULL)) { - phar = NULL; - } + phar_archive_data *phar = phar_get_archive(ZSTR_VAL(arch), ZSTR_LEN(arch), NULL, 0, NULL); zend_string_release_ex(arch, false); @@ -506,7 +499,8 @@ int phar_wrapper_rmdir(php_stream_wrapper *wrapper, const char *url, int options return 0; } - if (FAILURE == phar_get_archive(&phar, ZSTR_VAL(resource->host), ZSTR_LEN(resource->host), NULL, 0, &error)) { + phar = phar_get_archive(ZSTR_VAL(resource->host), ZSTR_LEN(resource->host), NULL, 0, &error); + if (!phar) { php_stream_wrapper_log_error(wrapper, options, "phar error: cannot remove directory \"%s\" in phar \"%s\", error retrieving phar information: %s", ZSTR_VAL(resource->path)+1, ZSTR_VAL(resource->host), error); efree(error); php_url_free(resource); diff --git a/ext/phar/func_interceptors.c b/ext/phar/func_interceptors.c index 61bb9050550f..e2b45ac2a0ae 100644 --- a/ext/phar/func_interceptors.c +++ b/ext/phar/func_interceptors.c @@ -98,8 +98,8 @@ static zend_string* phar_get_name_for_relative_paths(zend_string *filename, bool /* fopen within phar, if :// is not in the url, then prepend phar:/// */ /* retrieving a file defaults to within the current directory, so use this if possible */ - phar_archive_data *phar; - if (FAILURE == phar_get_archive(&phar, ZSTR_VAL(arch), ZSTR_LEN(arch), NULL, 0, NULL)) { + phar_archive_data *phar = phar_get_archive(ZSTR_VAL(arch), ZSTR_LEN(arch), NULL, 0, NULL); + if (!phar) { zend_string_release_ex(arch, false); return NULL; } @@ -492,9 +492,9 @@ static void phar_file_stat(const char *filename, size_t filename_length, int typ zend_string *arch = phar_split_fname(ZSTR_VAL(fname), ZSTR_LEN(fname), NULL, 2, 0); if (arch) { /* fopen within phar, if :// is not in the url, then prepend phar:/// */ - zend_result has_archive = phar_get_archive(&phar, ZSTR_VAL(arch), ZSTR_LEN(arch), NULL, 0, NULL); + phar = phar_get_archive(ZSTR_VAL(arch), ZSTR_LEN(arch), NULL, 0, NULL); zend_string_release_ex(arch, false); - if (FAILURE == has_archive) { + if (!phar) { goto skip_phar; } splitted:; @@ -727,13 +727,13 @@ PHP_FUNCTION(phar_is_file) /* {{{ */ zend_string *arch = phar_split_fname(ZSTR_VAL(fname), ZSTR_LEN(fname), NULL, 2, 0); if (arch) { - phar_archive_data *phar; + ; /* fopen within phar, if :// is not in the url, then prepend phar:/// */ /* retrieving a file within the current directory, so use this if possible */ - zend_result has_archive = phar_get_archive(&phar, ZSTR_VAL(arch), ZSTR_LEN(arch), NULL, 0, NULL); + phar_archive_data *phar = phar_get_archive(ZSTR_VAL(arch), ZSTR_LEN(arch), NULL, 0, NULL); zend_string_release_ex(arch, false); - if (has_archive == SUCCESS) { + if (phar) { phar_entry_info *etemp; zend_string *entry = phar_fix_filepath(filename, filename_len, true); @@ -784,13 +784,11 @@ PHP_FUNCTION(phar_is_link) /* {{{ */ zend_string *arch = phar_split_fname(ZSTR_VAL(fname), ZSTR_LEN(fname), NULL, 2, 0); if (arch) { - phar_archive_data *phar; - /* fopen within phar, if :// is not in the url, then prepend phar:/// */ /* retrieving a file within the current directory, so use this if possible */ - zend_result has_archive = phar_get_archive(&phar, ZSTR_VAL(arch), ZSTR_LEN(arch), NULL, 0, NULL); + phar_archive_data *phar = phar_get_archive(ZSTR_VAL(arch), ZSTR_LEN(arch), NULL, 0, NULL); zend_string_release_ex(arch, false); - if (has_archive == SUCCESS) { + if (phar) { phar_entry_info *etemp; zend_string *entry = phar_fix_filepath(filename, filename_len, true); diff --git a/ext/phar/phar.c b/ext/phar/phar.c index a81a62a188f9..cd363fbd88ee 100644 --- a/ext/phar/phar.c +++ b/ext/phar/phar.c @@ -484,9 +484,8 @@ ZEND_ATTRIBUTE_NONNULL void phar_entry_remove(phar_entry_data *idata, char **err /** * Open an already loaded phar */ -static zend_result phar_open_parsed_phar(char *fname, size_t fname_len, char *alias, size_t alias_len, bool is_data, uint32_t options, phar_archive_data** pphar, char **error) /* {{{ */ +static zend_result phar_open_parsed_phar(char *fname, size_t fname_len, const char *alias, size_t alias_len, bool is_data, uint32_t options, phar_archive_data** pphar, char **error) /* {{{ */ { - phar_archive_data *phar; #ifdef PHP_WIN32 char *save_fname; ALLOCA_FLAG(fname_use_heap) @@ -504,12 +503,12 @@ static zend_result phar_open_parsed_phar(char *fname, size_t fname_len, char *al phar_unixify_path_separators(fname, fname_len); } #endif - zend_result archive_retrieved = phar_get_archive(&phar, fname, fname_len, alias, alias_len, error); + phar_archive_data *phar = phar_get_archive(fname, fname_len, alias, alias_len, error); /* logic is as follows: - If no alias was passed in, then it can match either and be valid - If an explicit alias was requested, ensure the filename passed in matches the phar's filename. */ - bool process_phar = SUCCESS == archive_retrieved && (!alias || zend_string_equals_cstr(phar->fname, fname, fname_len)); + bool process_phar = phar && (!alias || zend_string_equals_cstr(phar->fname, fname, fname_len)); #ifdef PHP_WIN32 if (fname != save_fname) { free_alloca(fname, fname_use_heap); @@ -721,7 +720,7 @@ void phar_parse_metadata_lazy(const char *buffer, phar_metadata_tracker *tracker * This is used by phar_open_from_filename to process the manifest, but can be called * directly. */ -static zend_result phar_parse_pharfile(php_stream *fp, char *fname, size_t fname_len, char *alias, size_t alias_len, zend_long halt_offset, phar_archive_data** pphar, uint32_t compression, char **error) /* {{{ */ +static zend_result phar_parse_pharfile(php_stream *fp, const char *fname, size_t fname_len, const char *alias, size_t alias_len, zend_long halt_offset, phar_archive_data** pphar, uint32_t compression, char **error) /* {{{ */ { char b32[4], *buffer, *endbuffer, *savebuf; phar_archive_data *mydata = NULL; @@ -1303,7 +1302,7 @@ static zend_result phar_parse_pharfile(php_stream *fp, char *fname, size_t fname /** * Create or open a phar for writing */ -ZEND_ATTRIBUTE_NONNULL_ARGS(1, 6, 7) zend_result phar_open_or_create_filename(zend_string *fname, char *alias, size_t alias_len, bool is_data, uint32_t options, phar_archive_data** pphar, char **error) /* {{{ */ +ZEND_ATTRIBUTE_NONNULL_ARGS(1, 6, 7) zend_result phar_open_or_create_filename(zend_string *fname, const char *alias, size_t alias_len, bool is_data, uint32_t options, phar_archive_data** pphar, char **error) /* {{{ */ { const char *ext_str, *z; char *my_error; @@ -1367,9 +1366,9 @@ ZEND_ATTRIBUTE_NONNULL_ARGS(1, 6, 7) zend_result phar_open_or_create_filename(ze } /* }}} */ -static zend_result phar_open_from_fp(php_stream* fp, char *fname, size_t fname_len, char *alias, size_t alias_len, uint32_t options, phar_archive_data** pphar, char **error); +static zend_result phar_open_from_fp(php_stream* fp, const char *fname, size_t fname_len, const char *alias, size_t alias_len, uint32_t options, phar_archive_data** pphar, char **error); -ZEND_ATTRIBUTE_NONNULL_ARGS(1, 6, 7) zend_result phar_create_or_parse_filename(zend_string *fname, char *alias, size_t alias_len, bool is_data, uint32_t options, phar_archive_data** pphar, char **error) /* {{{ */ +ZEND_ATTRIBUTE_NONNULL_ARGS(1, 6, 7) zend_result phar_create_or_parse_filename(zend_string *fname, const char *alias, size_t alias_len, bool is_data, uint32_t options, phar_archive_data** pphar, char **error) /* {{{ */ { php_stream *fp; zend_string *actual = NULL; @@ -1508,7 +1507,7 @@ ZEND_ATTRIBUTE_NONNULL_ARGS(1, 6, 7) zend_result phar_create_or_parse_filename(z * that the manifest is proper, then pass it to phar_parse_pharfile(). SUCCESS * or FAILURE is returned and pphar is set to a pointer to the phar's manifest */ -zend_result phar_open_from_filename(char *fname, size_t fname_len, char *alias, size_t alias_len, uint32_t options, phar_archive_data** pphar, char **error) /* {{{ */ +zend_result phar_open_from_filename(char *fname, size_t fname_len, const char *alias, size_t alias_len, uint32_t options, phar_archive_data** pphar, char **error) /* {{{ */ { php_stream *fp; zend_string *actual; @@ -1565,7 +1564,7 @@ zend_result phar_open_from_filename(char *fname, size_t fname_len, char *alias, * that the manifest is proper, then pass it to phar_parse_pharfile(). SUCCESS * or FAILURE is returned and pphar is set to a pointer to the phar's manifest */ -static zend_result phar_open_from_fp(php_stream* fp, char *fname, size_t fname_len, char *alias, size_t alias_len, uint32_t options, phar_archive_data** pphar, char **error) /* {{{ */ +static zend_result phar_open_from_fp(php_stream* fp, const char *fname, size_t fname_len, const char *alias, size_t alias_len, uint32_t options, phar_archive_data** pphar, char **error) /* {{{ */ { static const char token[] = "__HALT_COMPILER();"; static const char zip_magic[] = "PK\x03\x04"; @@ -2253,7 +2252,7 @@ zend_string* phar_split_fname(const char *filename, size_t filename_len, zend_st * Invoked when a user calls Phar::mapPhar() from within an executing .phar * to set up its manifest directly */ -ZEND_ATTRIBUTE_NONNULL_ARGS(3) zend_result phar_open_executed_filename(char *alias, size_t alias_len, char **error) /* {{{ */ +ZEND_ATTRIBUTE_NONNULL_ARGS(3) zend_result phar_open_executed_filename(const char *alias, size_t alias_len, char **error) /* {{{ */ { *error = NULL; diff --git a/ext/phar/phar_internal.h b/ext/phar/phar_internal.h index df4e58c7adbf..7a923fd15e18 100644 --- a/ext/phar/phar_internal.h +++ b/ext/phar/phar_internal.h @@ -406,13 +406,13 @@ void phar_object_init(void); void phar_destroy_phar_data(phar_archive_data *phar); ZEND_ATTRIBUTE_NONNULL zend_result phar_postprocess_file(phar_entry_data *idata, uint32_t crc32, char **error, int process_zip); -zend_result phar_open_from_filename(char *fname, size_t fname_len, char *alias, size_t alias_len, uint32_t options, phar_archive_data** pphar, char **error); -ZEND_ATTRIBUTE_NONNULL_ARGS(1, 6, 7) zend_result phar_open_or_create_filename(zend_string *fname, char *alias, size_t alias_len, bool is_data, uint32_t options, phar_archive_data** pphar, char **error); -ZEND_ATTRIBUTE_NONNULL_ARGS(1, 6, 7) zend_result phar_create_or_parse_filename(zend_string *fname, char *alias, size_t alias_len, bool is_data, uint32_t options, phar_archive_data** pphar, char **error); -ZEND_ATTRIBUTE_NONNULL_ARGS(3) zend_result phar_open_executed_filename(char *alias, size_t alias_len, char **error); +zend_result phar_open_from_filename(char *fname, size_t fname_len, const char *alias, size_t alias_len, uint32_t options, phar_archive_data** pphar, char **error); +ZEND_ATTRIBUTE_NONNULL_ARGS(1, 6, 7) zend_result phar_open_or_create_filename(zend_string *fname, const char *alias, size_t alias_len, bool is_data, uint32_t options, phar_archive_data** pphar, char **error); +ZEND_ATTRIBUTE_NONNULL_ARGS(1, 6, 7) zend_result phar_create_or_parse_filename(zend_string *fname, const char *alias, size_t alias_len, bool is_data, uint32_t options, phar_archive_data** pphar, char **error); +ZEND_ATTRIBUTE_NONNULL_ARGS(3) zend_result phar_open_executed_filename(const char *alias, size_t alias_len, char **error); 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); -zend_result phar_verify_signature(php_stream *fp, size_t end_of_phar, uint32_t sig_type, char *sig, size_t sig_len, const char *fname, char **signature, size_t *signature_len, char **error); +phar_archive_data* phar_get_archive(const char *fname, size_t fname_len, const char *alias, size_t alias_len, char **error); +zend_result phar_verify_signature(php_stream *fp, size_t end_of_phar, uint32_t sig_type, const char *sig, size_t sig_len, const char *fname, char **signature, size_t *signature_len, char **error); ZEND_ATTRIBUTE_NONNULL zend_string* phar_create_signature(phar_archive_data *phar, php_stream *fp, char **error); /* utility functions */ @@ -423,7 +423,7 @@ const char *phar_compress_filter(const phar_entry_info *entry, bool return_unkno /* void phar_remove_virtual_dirs(phar_archive_data *phar, char *filename, size_t filename_len); */ void phar_add_virtual_dirs(phar_archive_data *phar, const char *filename, size_t filename_len); zend_result phar_mount_entry(phar_archive_data *phar, const 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); +zend_string *phar_find_in_include_path(const zend_string *file, phar_archive_data **pphar); 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); @@ -446,12 +446,12 @@ zend_result phar_copy_on_write(phar_archive_data **pphar); /* tar functions in tar.c */ bool phar_is_tar(const char *buf, const char *fname); zend_result phar_parse_tarfile(php_stream* fp, const char *fname, size_t fname_len, const char *alias, size_t alias_len, phar_archive_data** pphar, uint32_t compression, char **error); -ZEND_ATTRIBUTE_NONNULL_ARGS(1, 6, 7) zend_result phar_open_or_create_tar(zend_string *fname, char *alias, size_t alias_len, bool is_data, uint32_t options, phar_archive_data** pphar, char **error); +ZEND_ATTRIBUTE_NONNULL_ARGS(1, 6, 7) zend_result phar_open_or_create_tar(zend_string *fname, const char *alias, size_t alias_len, bool is_data, uint32_t options, phar_archive_data** pphar, char **error); ZEND_ATTRIBUTE_NONNULL_ARGS(1, 4) int phar_tar_flush(phar_archive_data *phar, zend_string *user_stub, bool is_default_stub, char **error); /* zip functions in zip.c */ zend_result phar_parse_zipfile(php_stream *fp, const char *fname, size_t fname_len, const char *alias, size_t alias_len, phar_archive_data** pphar, char **error); -ZEND_ATTRIBUTE_NONNULL_ARGS(1, 6, 7) zend_result phar_open_or_create_zip(zend_string *fname, char *alias, size_t alias_len, bool is_data, uint32_t options, phar_archive_data** pphar, char **error); +ZEND_ATTRIBUTE_NONNULL_ARGS(1, 6, 7) zend_result phar_open_or_create_zip(zend_string *fname, const char *alias, size_t alias_len, bool is_data, uint32_t options, phar_archive_data** pphar, char **error); ZEND_ATTRIBUTE_NONNULL_ARGS(1, 4) int phar_zip_flush(phar_archive_data *archive, zend_string *user_stub, bool is_default_stub, char **error); #ifdef PHAR_MAIN diff --git a/ext/phar/phar_object.c b/ext/phar/phar_object.c index bc55c175f7ba..00a5ebf3058f 100644 --- a/ext/phar/phar_object.c +++ b/ext/phar/phar_object.c @@ -349,9 +349,10 @@ static void phar_do_404(phar_archive_data *phar, char *fname, size_t fname_len, /* post-process REQUEST_URI and retrieve the actual request URI. This is for cases like http://localhost/blah.phar/path/to/file.php/extra/stuff which calls "blah.phar" file "path/to/file.php" with PATH_INFO "/extra/stuff" */ -static void phar_postprocess_ru_web(const char *fname, size_t fname_len, char *entry, size_t *entry_len, char **ru, size_t *ru_len) /* {{{ */ +static void phar_postprocess_ru_web(const char *fname, size_t fname_len, const char *entry, size_t *entry_len, char **ru, size_t *ru_len) /* {{{ */ { - char *e = entry + 1, *u1 = NULL, *u = NULL, *saveu = NULL; + const char *e = entry + 1; + char *u1 = NULL, *u = NULL, *saveu = NULL; size_t e_len = *entry_len - 1, u_len = 0; phar_archive_data *pphar; @@ -752,8 +753,8 @@ PHP_METHOD(Phar, webPhar) entry_len = sizeof("/index.php")-1; } - if (FAILURE == phar_get_archive(&phar, fname, fname_len, NULL, 0, NULL) || - (info = phar_get_entry_info(phar, entry, entry_len, NULL, false)) == NULL) { + phar = phar_get_archive(fname, fname_len, NULL, 0, NULL); + if (!phar || (info = phar_get_entry_info(phar, entry, entry_len, NULL, false)) == NULL) { phar_do_404(phar, fname, fname_len, f404); } else { char *tmp = NULL, sa = '\0'; @@ -793,8 +794,8 @@ PHP_METHOD(Phar, webPhar) goto cleanup_skip_entry; } - if (FAILURE == phar_get_archive(&phar, fname, fname_len, NULL, 0, NULL) || - (info = phar_get_entry_info(phar, entry, entry_len, NULL, false)) == NULL) { + phar = phar_get_archive(fname, fname_len, NULL, 0, NULL); + if (!phar || (info = phar_get_entry_info(phar, entry, entry_len, NULL, false)) == NULL) { phar_do_404(phar, fname, fname_len, f404); goto cleanup; } diff --git a/ext/phar/stream.c b/ext/phar/stream.c index f49bc5e2deba..f9d19a04122a 100644 --- a/ext/phar/stream.c +++ b/ext/phar/stream.c @@ -230,7 +230,8 @@ static php_stream * phar_wrapper_open_url(php_stream_wrapper *wrapper, const cha } else { if (!*internal_file && (options & STREAM_OPEN_FOR_INCLUDE)) { /* retrieve the stub */ - if (FAILURE == phar_get_archive(&phar, ZSTR_VAL(resource->host), ZSTR_LEN(resource->host), NULL, 0, NULL)) { + phar = phar_get_archive(ZSTR_VAL(resource->host), ZSTR_LEN(resource->host), NULL, 0, NULL); + if (!phar) { php_stream_wrapper_log_error(wrapper, options, "file %s is not a valid phar archive", ZSTR_VAL(resource->host)); efree(internal_file); php_url_free(resource); @@ -363,7 +364,7 @@ static ssize_t phar_stream_read(php_stream *stream, char *buf, size_t count) /* { phar_entry_data *data = (phar_entry_data *)stream->abstract; ssize_t got; - phar_entry_info *entry; + const phar_entry_info *entry; if (data->internal_file->symlink) { entry = phar_get_link_source(data->internal_file); @@ -393,7 +394,7 @@ static ssize_t phar_stream_read(php_stream *stream, char *buf, size_t count) /* static int phar_stream_seek(php_stream *stream, zend_off_t offset, int whence, zend_off_t *newoffset) /* {{{ */ { phar_entry_data *data = (phar_entry_data *)stream->abstract; - phar_entry_info *entry; + const phar_entry_info *entry; int res; zend_ulong temp; @@ -461,7 +462,7 @@ static int phar_stream_flush(php_stream *stream) /* {{{ */ { char *error; int ret; - phar_entry_data *data = (phar_entry_data *) stream->abstract; + const phar_entry_data *data = stream->abstract; if (data->internal_file->is_modified) { data->internal_file->timestamp = time(0); @@ -481,7 +482,7 @@ static int phar_stream_flush(php_stream *stream) /* {{{ */ /** * stat an opened phar file handle stream, used by phar_stat() */ -void phar_dostat(phar_archive_data *phar, phar_entry_info *data, php_stream_statbuf *ssb, bool is_temp_dir) +static void phar_dostat(const phar_archive_data *phar, const phar_entry_info *data, php_stream_statbuf *ssb, bool is_temp_dir) { memset(ssb, 0, sizeof(php_stream_statbuf)); @@ -535,7 +536,7 @@ void phar_dostat(phar_archive_data *phar, phar_entry_info *data, php_stream_stat */ static int phar_stream_stat(php_stream *stream, php_stream_statbuf *ssb) /* {{{ */ { - phar_entry_data *data = (phar_entry_data *)stream->abstract; + const phar_entry_data *data = stream->abstract; /* If ssb is NULL then someone is misbehaving */ if (!ssb) { @@ -554,7 +555,6 @@ static int phar_wrapper_stat(php_stream_wrapper *wrapper, const char *url, int f php_stream_statbuf *ssb, php_stream_context *context) /* {{{ */ { char *internal_file; - phar_archive_data *phar; size_t internal_file_len; php_url *resource = phar_parse_url(wrapper, url, "r", flags|PHP_STREAM_URL_STAT_QUIET); @@ -577,7 +577,8 @@ static int phar_wrapper_stat(php_stream_wrapper *wrapper, const char *url, int f internal_file = ZSTR_VAL(resource->path) + 1; /* strip leading "/" */ /* find the phar in our trusty global hash indexed by alias (host of phar://blah.phar/file.whatever) */ - if (FAILURE == phar_get_archive(&phar, ZSTR_VAL(resource->host), ZSTR_LEN(resource->host), NULL, 0, NULL)) { + phar_archive_data *phar = phar_get_archive(ZSTR_VAL(resource->host), ZSTR_LEN(resource->host), NULL, 0, NULL); + if (!phar) { php_url_free(resource); return FAILURE; } @@ -658,7 +659,6 @@ static int phar_wrapper_unlink(php_stream_wrapper *wrapper, const char *url, int char *internal_file, *error; size_t internal_file_len; phar_entry_data *idata; - phar_archive_data *pphar; php_url *resource = phar_parse_url(wrapper, url, "rb", options); if (!resource) { @@ -681,7 +681,7 @@ static int phar_wrapper_unlink(php_stream_wrapper *wrapper, const char *url, int phar_request_initialize(); - pphar = zend_hash_find_ptr(&(PHAR_G(phar_fname_map)), resource->host); + const phar_archive_data *pphar = zend_hash_find_ptr(&(PHAR_G(phar_fname_map)), resource->host); if (PHAR_G(readonly) && (!pphar || !pphar->is_data)) { php_url_free(resource); php_stream_wrapper_log_error(wrapper, options, "phar error: write operations disabled by the php.ini setting phar.readonly"); @@ -725,7 +725,6 @@ static int phar_wrapper_unlink(php_stream_wrapper *wrapper, const char *url, int static int phar_wrapper_rename(php_stream_wrapper *wrapper, const char *url_from, const char *url_to, int options, php_stream_context *context) /* {{{ */ { char *error; - phar_archive_data *phar, *pfrom, *pto; bool is_dir = false; bool is_modified = false; @@ -736,9 +735,8 @@ static int phar_wrapper_rename(php_stream_wrapper *wrapper, const char *url_from php_error_docref(NULL, E_WARNING, "phar error: cannot rename \"%s\" to \"%s\": invalid or non-writable url \"%s\"", url_from, url_to, url_from); return 0; } - if (SUCCESS != phar_get_archive(&pfrom, ZSTR_VAL(resource_from->host), ZSTR_LEN(resource_from->host), NULL, 0, NULL)) { - pfrom = NULL; - } + + phar_archive_data *pfrom = phar_get_archive(ZSTR_VAL(resource_from->host), ZSTR_LEN(resource_from->host), NULL, 0, NULL); if (PHAR_G(readonly) && (!pfrom || !pfrom->is_data)) { php_url_free(resource_from); php_error_docref(NULL, E_WARNING, "phar error: Write operations disabled by the php.ini setting phar.readonly"); @@ -751,9 +749,8 @@ static int phar_wrapper_rename(php_stream_wrapper *wrapper, const char *url_from php_error_docref(NULL, E_WARNING, "phar error: cannot rename \"%s\" to \"%s\": invalid or non-writable url \"%s\"", url_from, url_to, url_to); return 0; } - if (SUCCESS != phar_get_archive(&pto, ZSTR_VAL(resource_to->host), ZSTR_LEN(resource_to->host), NULL, 0, NULL)) { - pto = NULL; - } + + phar_archive_data *pto = phar_get_archive(ZSTR_VAL(resource_to->host), ZSTR_LEN(resource_to->host), NULL, 0, NULL); if (PHAR_G(readonly) && (!pto || !pto->is_data)) { php_url_free(resource_from); php_url_free(resource_to); @@ -797,7 +794,8 @@ static int phar_wrapper_rename(php_stream_wrapper *wrapper, const char *url_from return 0; } - if (SUCCESS != phar_get_archive(&phar, ZSTR_VAL(resource_from->host), ZSTR_LEN(resource_from->host), NULL, 0, &error)) { + phar_archive_data *phar = phar_get_archive(ZSTR_VAL(resource_from->host), ZSTR_LEN(resource_from->host), NULL, 0, &error); + if (!phar) { php_url_free(resource_from); php_url_free(resource_to); php_error_docref(NULL, E_WARNING, "phar error: cannot rename \"%s\" to \"%s\": %s", url_from, url_to, error); diff --git a/ext/phar/tar.c b/ext/phar/tar.c index 761246000dd2..edb0707a6ff7 100644 --- a/ext/phar/tar.c +++ b/ext/phar/tar.c @@ -126,7 +126,7 @@ bool phar_is_tar(const char *buf, const char *fname) /* {{{ */ } /* }}} */ -ZEND_ATTRIBUTE_NONNULL_ARGS(1, 6, 7) zend_result phar_open_or_create_tar(zend_string *fname, char *alias, size_t alias_len, bool is_data, uint32_t options, phar_archive_data** pphar, char **error) /* {{{ */ +ZEND_ATTRIBUTE_NONNULL_ARGS(1, 6, 7) zend_result phar_open_or_create_tar(zend_string *fname, const char *alias, size_t alias_len, bool is_data, uint32_t options, phar_archive_data** pphar, char **error) /* {{{ */ { phar_archive_data *phar; zend_result ret = phar_create_or_parse_filename(fname, alias, alias_len, is_data, options, &phar, error); @@ -802,7 +802,7 @@ static int phar_tar_writeheaders_int(phar_entry_info *entry, void *argument) /* /* write header */ entry->header_offset = php_stream_tell(fp->new); - if (sizeof(header) != php_stream_write(fp->new, (char *) &header, sizeof(header))) { + if (sizeof(header) != php_stream_write(fp->new, (const char *) &header, sizeof(header))) { if (fp->error) { spprintf(fp->error, 4096, "tar-based phar \"%s\" cannot be created, header for file \"%s\" could not be written", ZSTR_VAL(entry->phar->fname), ZSTR_VAL(entry->filename)); } @@ -906,7 +906,7 @@ ZEND_ATTRIBUTE_NONNULL static int phar_tar_setmetadata(const phar_metadata_track ZEND_ATTRIBUTE_NONNULL static int phar_tar_setupmetadata(zval *zv, void *argument) /* {{{ */ { - struct _phar_pass_tar_info *i = (struct _phar_pass_tar_info *)argument; + const struct _phar_pass_tar_info *i = (struct _phar_pass_tar_info *)argument; char **error = i->error; phar_entry_info *entry = (phar_entry_info *)Z_PTR_P(zv), newentry = {0}; diff --git a/ext/phar/util.c b/ext/phar/util.c index ad7cdd6c9ae5..e501ccfaceba 100644 --- a/ext/phar/util.c +++ b/ext/phar/util.c @@ -34,7 +34,8 @@ #include #include #else -static zend_result phar_call_openssl_signverify(bool is_sign, php_stream *fp, zend_off_t end, const char *key, size_t key_len, char **signature, size_t *signature_len, uint32_t sig_type); +ZEND_ATTRIBUTE_NONNULL static bool phar_call_openssl_verify(php_stream *fp, zend_off_t end, zend_string *public_key, const char *signature, size_t signature_len, uint32_t sig_type); +static zend_result phar_call_openssl_sign(php_stream *fp, zend_off_t end, const char *key, size_t key_len, char **signature, size_t *signature_len, uint32_t sig_type); #endif /* for links to relative location, prepend cwd of the entry */ @@ -263,7 +264,7 @@ zend_result phar_mount_entry(phar_archive_data *phar, const char *filename, size } /* }}} */ -zend_string *phar_find_in_include_path(zend_string *filename, phar_archive_data **pphar) /* {{{ */ +zend_string *phar_find_in_include_path(const zend_string *filename, phar_archive_data **pphar) /* {{{ */ { zend_string *ret; char *path; @@ -308,7 +309,8 @@ zend_string *phar_find_in_include_path(zend_string *filename, phar_archive_data } if (*ZSTR_VAL(filename) == '.') { - if (FAILURE == phar_get_archive(&phar, ZSTR_VAL(arch), ZSTR_LEN(arch), NULL, 0, NULL)) { + phar = phar_get_archive(ZSTR_VAL(arch), ZSTR_LEN(arch), NULL, 0, NULL); + if (!phar) { zend_string_release_ex(arch, false); return NULL; } @@ -468,7 +470,6 @@ ZEND_ATTRIBUTE_NONNULL static zend_result phar_separate_entry_fp(phar_entry_info */ ZEND_ATTRIBUTE_NONNULL zend_result phar_get_entry_data(phar_entry_data **ret, const zend_string *fname, char *path, size_t path_len, const char *mode, char allow_dir, char **error, bool security) /* {{{ */ { - phar_archive_data *phar; phar_entry_info *entry; bool for_write = mode[0] != 'r' || mode[1] == '+'; bool for_append = mode[0] == 'a'; @@ -478,7 +479,8 @@ ZEND_ATTRIBUTE_NONNULL zend_result phar_get_entry_data(phar_entry_data **ret, co *ret = NULL; *error = NULL; - if (FAILURE == phar_get_archive(&phar, ZSTR_VAL(fname), ZSTR_LEN(fname), NULL, 0, error)) { + phar_archive_data *phar = phar_get_archive(ZSTR_VAL(fname), ZSTR_LEN(fname), NULL, 0, error); + if (!phar) { return FAILURE; } @@ -613,7 +615,6 @@ ZEND_ATTRIBUTE_NONNULL zend_result phar_get_entry_data(phar_entry_data **ret, co */ ZEND_ATTRIBUTE_NONNULL phar_entry_data *phar_get_or_create_entry_data(zend_string *fname, char *path, size_t path_len, const char *mode, char allow_dir, char **error, bool security, uint32_t timestamp) /* {{{ */ { - phar_archive_data *phar; phar_entry_info etemp; phar_entry_data *ret; const char *pcr_error; @@ -625,7 +626,8 @@ ZEND_ATTRIBUTE_NONNULL phar_entry_data *phar_get_or_create_entry_data(zend_strin is_dir = (path_len && path[path_len - 1] == '/') ? 1 : 0; - if (FAILURE == phar_get_archive(&phar, ZSTR_VAL(fname), ZSTR_LEN(fname), NULL, 0, error)) { + phar_archive_data *phar = phar_get_archive(ZSTR_VAL(fname), ZSTR_LEN(fname), NULL, 0, error); + if (!phar) { return NULL; } @@ -960,9 +962,9 @@ zend_result phar_free_alias(const phar_archive_data *phar) /* {{{ */ * Looks up a phar archive in the filename map, connecting it to the alias * (if any) or returns null */ -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* phar_get_archive(const char *fname, size_t fname_len, const char *alias, size_t alias_len, char **error) /* {{{ */ { - phar_archive_data *fd_ptr; + phar_archive_data *archive; phar_request_initialize(); @@ -970,142 +972,132 @@ zend_result phar_get_archive(phar_archive_data **archive, const char *fname, siz *error = NULL; } - *archive = NULL; - if (PHAR_G(last_phar) && zend_string_equals_cstr(PHAR_G(last_phar_name), fname, fname_len)) { - *archive = PHAR_G(last_phar); + archive = PHAR_G(last_phar); if (alias && alias_len) { if (!PHAR_G(last_phar)->is_temporary_alias && (alias_len != PHAR_G(last_phar)->alias_len || memcmp(PHAR_G(last_phar)->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(PHAR_G(last_phar)->fname), fname); } - *archive = NULL; - return FAILURE; + return NULL; } 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); } - zend_hash_str_add_ptr(&(PHAR_G(phar_alias_map)), alias, alias_len, *archive); + zend_hash_str_add_ptr(&(PHAR_G(phar_alias_map)), alias, alias_len, archive); PHAR_G(last_alias) = alias; PHAR_G(last_alias_len) = alias_len; } - return SUCCESS; + return archive; } if (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); + archive = PHAR_G(last_phar); } else { - fd_ptr = zend_hash_str_find_ptr(&(PHAR_G(phar_alias_map)), alias, alias_len); + archive = 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 (!archive && PHAR_G(manifest_cached)) { + archive = zend_hash_str_find_ptr(&cached_alias, alias, alias_len); } - if (fd_ptr) { - if (!zend_string_equals_cstr(fd_ptr->fname, fname, fname_len)) { + if (archive) { + if (!zend_string_equals_cstr(archive->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); + spprintf(error, 0, "alias \"%s\" is already used for archive \"%s\" cannot be overloaded with \"%s\"", alias, ZSTR_VAL(archive->fname), fname); } - if (SUCCESS == phar_free_alias(fd_ptr)) { + if (SUCCESS == phar_free_alias(archive)) { if (error) { efree(*error); *error = NULL; } } - return FAILURE; + return NULL; } - *archive = fd_ptr; - PHAR_G(last_phar) = fd_ptr; - PHAR_G(last_phar_name) = fd_ptr->fname; + PHAR_G(last_phar) = archive; + PHAR_G(last_phar_name) = archive->fname; PHAR_G(last_alias) = alias; PHAR_G(last_alias_len) = alias_len; - return SUCCESS; + return archive; } } 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; - + archive = zend_hash_str_find_ptr(&(PHAR_G(phar_fname_map)), fname, fname_len); + if (archive) { if (alias && alias_len) { - if (!fd_ptr->is_temporary_alias && (alias_len != fd_ptr->alias_len || memcmp(fd_ptr->alias, alias, alias_len))) { + if (!archive->is_temporary_alias && (alias_len != archive->alias_len || memcmp(archive->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); + spprintf(error, 0, "alias \"%s\" is already used for archive \"%s\" cannot be overloaded with \"%s\"", alias, ZSTR_VAL(archive->fname), fname); } - return FAILURE; + return NULL; } - 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); + if (archive->alias_len && zend_hash_str_exists(&(PHAR_G(phar_alias_map)), archive->alias, archive->alias_len)) { + zend_hash_str_del(&(PHAR_G(phar_alias_map)), archive->alias, archive->alias_len); } - zend_hash_str_add_ptr(&(PHAR_G(phar_alias_map)), alias, alias_len, fd_ptr); + zend_hash_str_add_ptr(&(PHAR_G(phar_alias_map)), alias, alias_len, archive); } - 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; + PHAR_G(last_phar) = archive; + PHAR_G(last_phar_name) = archive->fname; + PHAR_G(last_alias) = archive->alias; + PHAR_G(last_alias_len) = archive->alias_len; - return SUCCESS; + return archive; } - if (PHAR_G(manifest_cached) && NULL != (fd_ptr = zend_hash_str_find_ptr(&cached_phars, fname, fname_len))) { - *archive = fd_ptr; - + if (PHAR_G(manifest_cached) && NULL != (archive = zend_hash_str_find_ptr(&cached_phars, fname, fname_len))) { /* this could be problematic - alias should never be different from manifest alias for cached phars */ - if (!fd_ptr->is_temporary_alias && alias && alias_len) { - if (alias_len != fd_ptr->alias_len || memcmp(fd_ptr->alias, alias, alias_len)) { + if (!archive->is_temporary_alias && alias && alias_len) { + if (alias_len != archive->alias_len || memcmp(archive->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); + spprintf(error, 0, "alias \"%s\" is already used for archive \"%s\" cannot be overloaded with \"%s\"", alias, ZSTR_VAL(archive->fname), fname); } - return FAILURE; + return NULL; } } - 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; + PHAR_G(last_phar) = archive; + PHAR_G(last_phar_name) = archive->fname; + PHAR_G(last_alias) = archive->alias; + PHAR_G(last_alias_len) = archive->alias_len; - return SUCCESS; + return archive; } - fd_ptr = zend_hash_str_find_ptr(&(PHAR_G(phar_alias_map)), fname, fname_len); + archive = zend_hash_str_find_ptr(&(PHAR_G(phar_alias_map)), fname, fname_len); /* 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 (!archive && PHAR_G(manifest_cached)) { + archive = zend_hash_str_find_ptr(&cached_alias, fname, fname_len); } - if (fd_ptr) { - *archive = fd_ptr; - - 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; + if (archive) { + PHAR_G(last_phar) = archive; + PHAR_G(last_phar_name) = archive->fname; + PHAR_G(last_alias) = archive->alias; + PHAR_G(last_alias_len) = archive->alias_len; - return SUCCESS; + return archive; } /* not found, try converting \ to / */ char *my_realpath = expand_filepath(fname, NULL); if (UNEXPECTED(!my_realpath)) { - return FAILURE; + return NULL; } size_t my_realpath_len = strlen(my_realpath); @@ -1113,31 +1105,29 @@ zend_result phar_get_archive(phar_archive_data **archive, const char *fname, siz phar_unixify_path_separators(my_realpath, my_realpath_len); #endif - fd_ptr = zend_hash_str_find_ptr(&(PHAR_G(phar_fname_map)), my_realpath, my_realpath_len); + archive = 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); + if (!archive && PHAR_G(manifest_cached)) { + archive = zend_hash_str_find_ptr(&cached_phars, my_realpath, my_realpath_len); } efree(my_realpath); - if (fd_ptr) { - *archive = fd_ptr; - + if (archive) { if (alias && alias_len) { - zend_hash_str_add_ptr(&(PHAR_G(phar_alias_map)), alias, alias_len, fd_ptr); + zend_hash_str_add_ptr(&(PHAR_G(phar_alias_map)), alias, alias_len, archive); } - 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; + PHAR_G(last_phar) = archive; + PHAR_G(last_phar_name) = archive->fname; + PHAR_G(last_alias) = archive->alias; + PHAR_G(last_alias_len) = archive->alias_len; - return SUCCESS; + return archive; } } - return FAILURE; + return NULL; } /* }}} */ @@ -1372,36 +1362,44 @@ static int phar_hex_str(const char *digest, size_t digest_len, char **signature) /* }}} */ #ifndef PHAR_HAVE_OPENSSL -static zend_result phar_call_openssl_signverify(bool is_sign, php_stream *fp, zend_off_t end, const char *key, size_t key_len, char **signature, size_t *signature_len, uint32_t sig_type) /* {{{ */ -{ - zval retval, zp[4]; - zend_string *str; - - zend_function *fn = NULL; - if (is_sign) { - fn = zend_hash_str_find_ptr(CG(function_table), ZEND_STRL("openssl_sign")); - } else { - fn = zend_hash_str_find_ptr(CG(function_table), ZEND_STRL("openssl_verify")); - } +ZEND_ATTRIBUTE_NONNULL static bool phar_call_openssl_verify( + php_stream *fp, + zend_off_t end, + zend_string *public_key, + const char *signature, + size_t signature_len, + uint32_t sig_type +) { + ZEND_ASSERT(signature_len != 0); + zend_function *fn = zend_hash_str_find_ptr(CG(function_table), ZEND_STRL("openssl_verify")); /* OpenSSL is not available, even as a shared module */ - if (fn == NULL) { - return FAILURE; + if (UNEXPECTED(fn == NULL)) { + return false; } - if (*signature_len) { - ZVAL_STRINGL(&zp[1], *signature, *signature_len); - } else { - ZVAL_EMPTY_STRING(&zp[1]); - } - ZVAL_STRINGL(&zp[2], key, key_len); + /* Read and copy stream content */ php_stream_rewind(fp); - str = php_stream_copy_to_mem(fp, (size_t) end, 0); - if (str) { - ZVAL_STR(&zp[0], str); - } else { - ZVAL_EMPTY_STRING(&zp[0]); - } + zend_string *str = php_stream_copy_to_mem(fp, (size_t) end, false); + /* No content thus signing must fail */ + if (UNEXPECTED(str == NULL)) { + return false; + } + + /* Set up parameters for call to openssl_verify() + * openssl_verify( + * string $data, + * string $signature, + * OpenSSLAsymmetricKey|OpenSSLCertificate|array|string $public_key, + * string|int $algorithm = OPENSSL_ALGO_SHA1, + * int $padding = 0 + * ): int|false + */ + zval retval, zp[4]; + ZVAL_STR(&zp[0], str); + ZVAL_STRINGL(&zp[1], signature, signature_len); + /* Note we do not own the lifetime of the public key, but it is fine as calling the function will increase the refcount) */ + ZVAL_STR(&zp[2], public_key); if (sig_type == PHAR_SIG_OPENSSL_SHA512) { ZVAL_LONG(&zp[3], 9); /* value from openssl.c #define OPENSSL_ALGO_SHA512 9 */ } else if (sig_type == PHAR_SIG_OPENSSL_SHA256) { @@ -1410,52 +1408,84 @@ static zend_result phar_call_openssl_signverify(bool is_sign, php_stream *fp, ze /* don't rely on default value which may change in the future */ ZVAL_LONG(&zp[3], 1); /* value from openssl.c #define OPENSSL_ALGO_SHA1 1 */ } + zend_call_known_function(fn, NULL, NULL, &retval, /* param_count */ 4, zp, NULL); + /* Free string arguments that we own */ + zval_ptr_dtor_str(&zp[0]); + zval_ptr_dtor_str(&zp[1]); + + /* Returns 1 if the signature is correct, 0 if it is incorrect, and -1 or false on error. */ + switch (Z_TYPE(retval)) { + case IS_LONG: + if (1 == Z_LVAL(retval)) { + return true; + } + ZEND_FALLTHROUGH; + default: + /* Unlikely, but the openssl_verify() function may be disabled and redefined in userland and return bollocks */ + zval_ptr_dtor(&retval); + return false; + } +} - if ((size_t)end != Z_STRLEN(zp[0])) { - zval_ptr_dtor_str(&zp[0]); - zval_ptr_dtor_str(&zp[1]); - zval_ptr_dtor_str(&zp[2]); +static zend_result phar_call_openssl_sign(php_stream *fp, zend_off_t end, const char *key, size_t key_len, char **signature, size_t *signature_len, uint32_t sig_type) /* {{{ */ +{ + ZEND_ASSERT(end != 0); + ZEND_ASSERT(*signature_len == 0); + zval retval, zp[4]; + + zend_function *fn = zend_hash_str_find_ptr(CG(function_table), ZEND_STRL("openssl_sign")); + + /* OpenSSL is not available, even as a shared module */ + if (fn == NULL) { return FAILURE; } - Z_ADDREF(zp[0]); - if (is_sign) { - ZVAL_NEW_REF(&zp[1], &zp[1]); + /* Read and copy stream content */ + php_stream_rewind(fp); + zend_string *str = php_stream_copy_to_mem(fp, (size_t) end, false); + /* No content thus signing must fail */ + if (!str || (size_t)end != ZSTR_LEN(str)) { + return FAILURE; + } + + /* Set up parameters for call to openssl_sign() + * openssl_sign( + * string $data, + * string &$signature, + * #[\SensitiveParameter] OpenSSLAsymmetricKey|OpenSSLCertificate|array|string $private_key, + * string|int $algorithm = OPENSSL_ALGO_SHA1, + * int $padding = 0 + * ): bool + */ + ZVAL_STR(&zp[0], str); + ZVAL_EMPTY_STRING(&zp[1]); + ZVAL_NEW_REF(&zp[1], &zp[1]); + ZVAL_STRINGL(&zp[2], key, key_len); + if (sig_type == PHAR_SIG_OPENSSL_SHA512) { + ZVAL_LONG(&zp[3], 9); /* value from openssl.c #define OPENSSL_ALGO_SHA512 9 */ + } else if (sig_type == PHAR_SIG_OPENSSL_SHA256) { + ZVAL_LONG(&zp[3], 7); /* value from openssl.c #define OPENSSL_ALGO_SHA256 7 */ } else { - Z_ADDREF(zp[1]); + /* don't rely on default value which may change in the future */ + ZVAL_LONG(&zp[3], 1); /* value from openssl.c #define OPENSSL_ALGO_SHA1 1 */ } - Z_ADDREF(zp[2]); zend_call_known_function(fn, NULL, NULL, &retval, /* param_count */ 4, zp, NULL); - Z_DELREF(zp[0]); - - if (is_sign) { - ZVAL_UNREF(&zp[1]); - } else { - Z_DELREF(zp[1]); - } - Z_DELREF(zp[2]); + ZVAL_UNREF(&zp[1]); zval_ptr_dtor_str(&zp[0]); zval_ptr_dtor_str(&zp[2]); switch (Z_TYPE(retval)) { - case IS_LONG: - zval_ptr_dtor(&zp[1]); - if (1 == Z_LVAL(retval)) { - return SUCCESS; - } - return FAILURE; case IS_TRUE: *signature = estrndup(Z_STRVAL(zp[1]), Z_STRLEN(zp[1])); *signature_len = Z_STRLEN(zp[1]); zval_ptr_dtor(&zp[1]); return SUCCESS; default: + /* Unlikely, but the openssl_sign() function may be disabled and redefined in userland and return bollocks */ zval_ptr_dtor(&retval); - ZEND_FALLTHROUGH; - case IS_FALSE: zval_ptr_dtor(&zp[1]); return FAILURE; } @@ -1463,7 +1493,7 @@ static zend_result phar_call_openssl_signverify(bool is_sign, php_stream *fp, ze /* }}} */ #endif /* #ifndef PHAR_HAVE_OPENSSL */ -zend_result phar_verify_signature(php_stream *fp, size_t end_of_phar, uint32_t sig_type, char *sig, size_t sig_len, const char *fname, char **signature, size_t *signature_len, char **error) /* {{{ */ +zend_result phar_verify_signature(php_stream *fp, size_t end_of_phar, uint32_t sig_type, const char *sig, size_t sig_len, const char *fname, char **signature, size_t *signature_len, char **error) /* {{{ */ { size_t read_size, len; zend_off_t read_len; @@ -1488,8 +1518,6 @@ zend_result phar_verify_signature(php_stream *fp, size_t end_of_phar, uint32_t s } else { mdtype = EVP_sha1(); } -#else - size_t tempsig; #endif zend_string *pubkey = NULL; char *pfile; @@ -1524,9 +1552,7 @@ zend_result phar_verify_signature(php_stream *fp, size_t end_of_phar, uint32_t s } #ifndef PHAR_HAVE_OPENSSL - tempsig = sig_len; - - if (FAILURE == phar_call_openssl_signverify(false, fp, end_of_phar, ZSTR_VAL(pubkey), ZSTR_LEN(pubkey), &sig, &tempsig, sig_type)) { + if (!phar_call_openssl_verify(fp, end_of_phar, pubkey, sig, sig_len, sig_type)) { zend_string_release_ex(pubkey, 0); if (error) { @@ -1536,9 +1562,7 @@ zend_result phar_verify_signature(php_stream *fp, size_t end_of_phar, uint32_t s return FAILURE; } - zend_string_release_ex(pubkey, 0); - - sig_len = tempsig; + zend_string_release_ex(pubkey, false); #else in = BIO_new_mem_buf(ZSTR_VAL(pubkey), ZSTR_LEN(pubkey)); @@ -1610,7 +1634,7 @@ zend_result phar_verify_signature(php_stream *fp, size_t end_of_phar, uint32_t s EVP_MD_CTX_destroy(md_ctx); #endif - *signature_len = phar_hex_str((const char*)sig, sig_len, signature); + *signature_len = phar_hex_str(sig, sig_len, signature); } break; case PHAR_SIG_SHA512: { @@ -1909,7 +1933,7 @@ ZEND_ATTRIBUTE_NONNULL zend_string* phar_create_signature(phar_archive_data *pha siglen = 0; php_stream_seek(fp, 0, SEEK_END); - if (FAILURE == phar_call_openssl_signverify(true, fp, php_stream_tell(fp), PHAR_G(openssl_privatekey), PHAR_G(openssl_privatekey_len), (char **)&sigbuf, &siglen, phar->sig_flags)) { + if (FAILURE == phar_call_openssl_sign(fp, php_stream_tell(fp), PHAR_G(openssl_privatekey), PHAR_G(openssl_privatekey_len), (char **)&sigbuf, &siglen, phar->sig_flags)) { spprintf(error, 0, "unable to write phar \"%s\" with requested openssl signature", ZSTR_VAL(phar->fname)); return NULL; } diff --git a/ext/phar/zip.c b/ext/phar/zip.c index da934a4c0041..900b41f9c794 100644 --- a/ext/phar/zip.c +++ b/ext/phar/zip.c @@ -794,7 +794,7 @@ zend_result phar_parse_zipfile(php_stream *fp, const char *fname, size_t fname_l /** * Create or open a zip-based phar for writing */ -ZEND_ATTRIBUTE_NONNULL_ARGS(1, 6, 7) zend_result phar_open_or_create_zip(zend_string *fname, char *alias, size_t alias_len, bool is_data, uint32_t options, phar_archive_data** pphar, char **error) /* {{{ */ +ZEND_ATTRIBUTE_NONNULL_ARGS(1, 6, 7) zend_result phar_open_or_create_zip(zend_string *fname, const char *alias, size_t alias_len, bool is_data, uint32_t options, phar_archive_data** pphar, char **error) /* {{{ */ { phar_archive_data *phar; zend_result ret = phar_create_or_parse_filename(fname, alias, alias_len, is_data, options, &phar, error); @@ -1271,7 +1271,8 @@ ZEND_ATTRIBUTE_NONNULL_ARGS(1, 4) int phar_zip_flush(phar_archive_data *phar, ze /* register alias */ if (phar->alias_len) { - if (FAILURE == phar_get_archive(&phar, ZSTR_VAL(phar->fname), ZSTR_LEN(phar->fname), phar->alias, phar->alias_len, error)) { + phar = phar_get_archive(ZSTR_VAL(phar->fname), ZSTR_LEN(phar->fname), phar->alias, phar->alias_len, error); + if (!phar) { return EOF; } } diff --git a/ext/zlib/tests/deflate_init_strategy_type_error.phpt b/ext/zlib/tests/deflate_init_strategy_type_error.phpt index 0227d1bf6c29..2a59082bc320 100644 --- a/ext/zlib/tests/deflate_init_strategy_type_error.phpt +++ b/ext/zlib/tests/deflate_init_strategy_type_error.phpt @@ -1,16 +1,42 @@ --TEST-- -deflate_init(): strategy option type validation +deflate_init(): options type validation --EXTENSIONS-- zlib --FILE-- []]); + deflate_init(ZLIB_ENCODING_DEFLATE, ['level' => 'foo']); } catch (TypeError $e) { echo $e->getMessage(), PHP_EOL; } +try { + deflate_init(ZLIB_ENCODING_DEFLATE, ['memory' => []]); +} catch (TypeError $e) { + echo $e->getMessage(), PHP_EOL; +} + +try { + deflate_init(ZLIB_ENCODING_DEFLATE, ['window' => new A()]); +} catch (TypeError $e) { + echo $e->getMessage(), PHP_EOL; +} + +try { + deflate_init(ZLIB_ENCODING_DEFLATE, ['strategy' => $fp]); +} catch (TypeError $e) { + echo $e->getMessage(), PHP_EOL; +} + +fclose($fp); + ?> --EXPECT-- -deflate_init(): Argument #2 ($options) the value for option "strategy" must be of type int, array given +deflate_init(): Argument #2 ($options) the value for option "level" must be of type int, string given +deflate_init(): Argument #2 ($options) the value for option "memory" must be of type int, array given +deflate_init(): Argument #2 ($options) the value for option "window" must be of type int, A given +deflate_init(): Argument #2 ($options) the value for option "strategy" must be of type int, resource given diff --git a/ext/zlib/zlib.c b/ext/zlib/zlib.c index ae03496b7c19..b1ee09635e5a 100644 --- a/ext/zlib/zlib.c +++ b/ext/zlib/zlib.c @@ -854,6 +854,30 @@ static bool zlib_create_dictionary_string(HashTable *options, char **dict, size_ return true; } +ZEND_ATTRIBUTE_NONNULL static bool zlib_get_long_option(HashTable *options, const char *option_name, size_t option_name_len, zend_long *value) +{ + bool failed = false; + zval *option_buffer = zend_hash_str_find(options, option_name, option_name_len); + + if (!option_buffer) { + return true; + } + + /* The |H ZPP specifier may leave HashTable entries wrapped in IS_INDIRECT. */ + ZVAL_DEINDIRECT(option_buffer); + *value = zval_try_get_long(option_buffer, &failed); + if (UNEXPECTED(failed)) { + zend_argument_type_error( + 2, + "the value for option \"%.*s\" must be of type int, %s given", + (int) option_name_len, option_name, zend_zval_value_name(option_buffer) + ); + return false; + } + + return true; +} + /* {{{ Initialize an incremental inflate context with the specified encoding */ PHP_FUNCTION(inflate_init) { @@ -1080,49 +1104,38 @@ PHP_FUNCTION(deflate_init) zend_long encoding, level = -1, memory = 8, window = 15, strategy = Z_DEFAULT_STRATEGY; char *dict = NULL; size_t dictlen = 0; - HashTable *options = NULL; - zval *option_buffer; + HashTable *options = (HashTable*)&zend_empty_array; if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS(), "l|H", &encoding, &options)) { RETURN_THROWS(); } - if (options && (option_buffer = zend_hash_str_find(options, ZEND_STRL("level"))) != NULL) { - ZVAL_DEINDIRECT(option_buffer); - level = zval_get_long(option_buffer); + if (!zlib_get_long_option(options, ZEND_STRL("level"), &level)) { + RETURN_THROWS(); } if (level < -1 || level > 9) { zend_value_error("deflate_init(): \"level\" option must be between -1 and 9"); RETURN_THROWS(); } - if (options && (option_buffer = zend_hash_str_find(options, ZEND_STRL("memory"))) != NULL) { - ZVAL_DEINDIRECT(option_buffer); - memory = zval_get_long(option_buffer); + if (!zlib_get_long_option(options, ZEND_STRL("memory"), &memory)) { + RETURN_THROWS(); } if (memory < 1 || memory > 9) { zend_value_error("deflate_init(): \"memory\" option must be between 1 and 9"); RETURN_THROWS(); } - if (options && (option_buffer = zend_hash_str_find(options, ZEND_STRL("window"))) != NULL) { - ZVAL_DEINDIRECT(option_buffer); - window = zval_get_long(option_buffer); + if (!zlib_get_long_option(options, ZEND_STRL("window"), &window)) { + RETURN_THROWS(); } if (window < 8 || window > 15) { zend_value_error("deflate_init(): \"window\" option must be between 8 and 15"); RETURN_THROWS(); } - if (options && (option_buffer = zend_hash_str_find(options, ZEND_STRL("strategy"))) != NULL) { - bool failed = false; - - ZVAL_DEINDIRECT(option_buffer); - strategy = zval_try_get_long(option_buffer, &failed); - if (UNEXPECTED(failed)) { - zend_argument_type_error(2, "the value for option \"strategy\" must be of type int, %s given", zend_zval_value_name(option_buffer)); - RETURN_THROWS(); - } + if (!zlib_get_long_option(options, ZEND_STRL("strategy"), &strategy)) { + RETURN_THROWS(); } switch (strategy) { case Z_FILTERED: