From 670a8f73ccf54edd37b8f24f13953c699904ee4c Mon Sep 17 00:00:00 2001 From: Gina Peter Banyard Date: Thu, 16 Oct 2025 21:02:08 +0100 Subject: [PATCH 01/14] ext/phar: Improve signature tests --- ext/phar/tests/phar_setsignaturealgo2.phpt | 54 ++++++++++----- .../tests/tar/phar_setsignaturealgo2.phpt | 66 +++++++++++++------ .../tests/zip/phar_setsignaturealgo2.phpt | 64 +++++++++++------- 3 files changed, 122 insertions(+), 62 deletions(-) diff --git a/ext/phar/tests/phar_setsignaturealgo2.phpt b/ext/phar/tests/phar_setsignaturealgo2.phpt index 4f31836fbbbcc..82615a13da478 100644 --- a/ext/phar/tests/phar_setsignaturealgo2.phpt +++ b/ext/phar/tests/phar_setsignaturealgo2.phpt @@ -2,6 +2,7 @@ Phar::setSupportedSignatures() with hash --EXTENSIONS-- phar +openssl --SKIPIF-- getSignature()); + +echo "Set MD5:\n"; $p->setSignatureAlgorithm(Phar::MD5); var_dump($p->getSignature()); + +echo "Set SHA1:\n"; $p->setSignatureAlgorithm(Phar::SHA1); var_dump($p->getSignature()); + +echo "Set SHA256:\n"; try { -$p->setSignatureAlgorithm(Phar::SHA256); -var_dump($p->getSignature()); -} catch (Exception $e) { -echo $e->getMessage(); + $p->setSignatureAlgorithm(Phar::SHA256); + var_dump($p->getSignature()); +} catch (Throwable $e) { + echo $e::class, ': ', $e->getMessage(), PHP_EOL; } + +echo "Set SHA512:\n"; try { -$p->setSignatureAlgorithm(Phar::SHA512); -var_dump($p->getSignature()); -} catch (Exception $e) { -echo $e->getMessage(); + $p->setSignatureAlgorithm(Phar::SHA512); + var_dump($p->getSignature()); +} catch (Throwable $e) { + echo $e::class, ': ', $e->getMessage(), PHP_EOL; } + +echo "Set OPENSSL:\n"; try { -$config = __DIR__ . '/files/openssl.cnf'; -$config_arg = array('config' => $config); -$private = openssl_get_privatekey(file_get_contents(__DIR__ . '/files/private.pem')); -$pkey = ''; -openssl_pkey_export($private, $pkey, NULL, $config_arg); -$p->setSignatureAlgorithm(Phar::OPENSSL, $pkey); -var_dump($p->getSignature()); -} catch (Exception $e) { -echo $e->getMessage(); + $config = __DIR__ . '/files/openssl.cnf'; + $config_arg = array('config' => $config); + $private = openssl_get_privatekey(file_get_contents(__DIR__ . '/files/private.pem')); + $pkey = ''; + openssl_pkey_export($private, $pkey, NULL, $config_arg); + $p->setSignatureAlgorithm(Phar::OPENSSL, $pkey); + var_dump($p->getSignature()); +} catch (Throwable $e) { + echo $e::class, ': ', $e->getMessage(), PHP_EOL; } + ?> --CLEAN-- --EXPECTF-- +Default: array(2) { ["hash"]=> string(%d) "%s" ["hash_type"]=> string(7) "SHA-256" } +Set MD5: array(2) { ["hash"]=> string(%d) "%s" ["hash_type"]=> string(3) "MD5" } +Set SHA1: array(2) { ["hash"]=> string(%d) "%s" ["hash_type"]=> string(5) "SHA-1" } +Set SHA256: array(2) { ["hash"]=> string(%d) "%s" ["hash_type"]=> string(7) "SHA-256" } +Set SHA512: array(2) { ["hash"]=> string(%d) "%s" ["hash_type"]=> string(7) "SHA-512" } +Set OPENSSL: array(2) { ["hash"]=> string(%d) "%s" diff --git a/ext/phar/tests/tar/phar_setsignaturealgo2.phpt b/ext/phar/tests/tar/phar_setsignaturealgo2.phpt index 1a3a84303ea1b..6d60d3a680a1d 100644 --- a/ext/phar/tests/tar/phar_setsignaturealgo2.phpt +++ b/ext/phar/tests/tar/phar_setsignaturealgo2.phpt @@ -2,6 +2,7 @@ Phar::setSupportedSignatures() with hash, tar-based --EXTENSIONS-- phar +openssl --SKIPIF-- getSignature()); + +echo "Set MD5:\n"; $p->setSignatureAlgorithm(Phar::MD5); var_dump($p->getSignature()); + +echo "Set SHA1:\n"; $p->setSignatureAlgorithm(Phar::SHA1); var_dump($p->getSignature()); + +echo "Set SHA256:\n"; try { -$p->setSignatureAlgorithm(Phar::SHA256); -var_dump($p->getSignature()); -} catch (Exception $e) { -echo $e->getMessage(); + $p->setSignatureAlgorithm(Phar::SHA256); + var_dump($p->getSignature()); +} catch (Throwable $e) { + echo $e::class, ': ', $e->getMessage(), PHP_EOL; } + +echo "Set SHA512:\n"; try { -$p->setSignatureAlgorithm(Phar::SHA512); -var_dump($p->getSignature()); -} catch (Exception $e) { -echo $e->getMessage(); + $p->setSignatureAlgorithm(Phar::SHA512); + var_dump($p->getSignature()); +} catch (Throwable $e) { + echo $e::class, ': ', $e->getMessage(), PHP_EOL; } + +echo "Set OPENSSL:\n"; try { -$config = __DIR__ . '/../files/openssl.cnf'; -$config_arg = array('config' => $config); -$private = openssl_get_privatekey(file_get_contents(dirname(__DIR__) . '/files/private.pem')); -$pkey = ''; -openssl_pkey_export($private, $pkey, NULL, $config_arg); -$p->setSignatureAlgorithm(Phar::OPENSSL, $pkey); -var_dump($p->getSignature()); -$p->setSignatureAlgorithm(Phar::OPENSSL_SHA512, $pkey); -var_dump($p->getSignature()); -$p->setSignatureAlgorithm(Phar::OPENSSL_SHA256, $pkey); -var_dump($p->getSignature()); -} catch (Exception $e) { -echo $e->getMessage(); + $config = __DIR__ . '/../files/openssl.cnf'; + $config_arg = array('config' => $config); + $private = openssl_get_privatekey(file_get_contents(dirname(__DIR__) . '/files/private.pem')); + $pkey = ''; + openssl_pkey_export($private, $pkey, NULL, $config_arg); + $p->setSignatureAlgorithm(Phar::OPENSSL, $pkey); + var_dump($p->getSignature()); + echo "Set OPENSSL_SHA512:\n"; + $p->setSignatureAlgorithm(Phar::OPENSSL_SHA512, $pkey); + var_dump($p->getSignature()); + echo "Set OPENSSL_SHA256:\n"; + $p->setSignatureAlgorithm(Phar::OPENSSL_SHA256, $pkey); + var_dump($p->getSignature()); +} catch (Throwable $e) { + echo $e::class, ': ', $e->getMessage(), PHP_EOL; } + ?> --CLEAN-- --EXPECTF-- +Default: array(2) { ["hash"]=> string(%d) "%s" ["hash_type"]=> string(7) "SHA-256" } +Set MD5: array(2) { ["hash"]=> string(%d) "%s" ["hash_type"]=> string(3) "MD5" } +Set SHA1: array(2) { ["hash"]=> string(%d) "%s" ["hash_type"]=> string(5) "SHA-1" } +Set SHA256: array(2) { ["hash"]=> string(%d) "%s" ["hash_type"]=> string(7) "SHA-256" } +Set SHA512: array(2) { ["hash"]=> string(%d) "%s" ["hash_type"]=> string(7) "SHA-512" } +Set OPENSSL: array(2) { ["hash"]=> string(%d) "%s" ["hash_type"]=> string(7) "OpenSSL" } +Set OPENSSL_SHA512: array(2) { ["hash"]=> string(%d) "%s" ["hash_type"]=> string(14) "OpenSSL_SHA512" } +Set OPENSSL_SHA256: array(2) { ["hash"]=> string(%d) "%s" diff --git a/ext/phar/tests/zip/phar_setsignaturealgo2.phpt b/ext/phar/tests/zip/phar_setsignaturealgo2.phpt index 4fb9a155c5f57..8e3eed61cf781 100644 --- a/ext/phar/tests/zip/phar_setsignaturealgo2.phpt +++ b/ext/phar/tests/zip/phar_setsignaturealgo2.phpt @@ -20,49 +20,59 @@ $fname5 = __DIR__ . '/' . basename(__FILE__, '.php') . '.5.phar.zip'; $fname6 = __DIR__ . '/' . basename(__FILE__, '.php') . '.6.phar.zip'; $p = new Phar($fname); $p['file1.txt'] = 'hi'; + +echo "Default:\n"; var_dump($p->getSignature()); + +echo "Set MD5:\n"; $p->setSignatureAlgorithm(Phar::MD5); copy($fname, $fname2); $p = new Phar($fname2); var_dump($p->getSignature()); +echo "Set SHA1:\n"; $p->setSignatureAlgorithm(Phar::SHA1); copy($fname2, $fname3); $p = new Phar($fname3); var_dump($p->getSignature()); +echo "Set SHA256:\n"; try { -$p->setSignatureAlgorithm(Phar::SHA256); -copy($fname3, $fname4); -$p = new Phar($fname4); -var_dump($p->getSignature()); -} catch (Exception $e) { -echo $e->getMessage(); + $p->setSignatureAlgorithm(Phar::SHA256); + copy($fname3, $fname4); + $p = new Phar($fname4); + var_dump($p->getSignature()); +} catch (Throwable $e) { + echo $e::class, ': ', $e->getMessage(), PHP_EOL; } + +echo "Set SHA512:\n"; try { -$p->setSignatureAlgorithm(Phar::SHA512); -copy($fname4, $fname5); -$p = new Phar($fname5); -var_dump($p->getSignature()); -} catch (Exception $e) { -echo $e->getMessage(); + $p->setSignatureAlgorithm(Phar::SHA512); + copy($fname4, $fname5); + $p = new Phar($fname5); + var_dump($p->getSignature()); +} catch (Throwable $e) { + echo $e::class, ': ', $e->getMessage(), PHP_EOL; } + +echo "Set OPENSSL:\n"; try { -$config = __DIR__ . '/../files/openssl.cnf'; -$config_arg = array('config' => $config); -$keys=openssl_pkey_new($config_arg); -openssl_pkey_export($keys, $privkey, NULL, $config_arg); -$pubkey=openssl_pkey_get_details($keys); -$p->setSignatureAlgorithm(Phar::OPENSSL, $privkey); + $config = __DIR__ . '/../files/openssl.cnf'; + $config_arg = array('config' => $config); + $keys=openssl_pkey_new($config_arg); + openssl_pkey_export($keys, $privkey, NULL, $config_arg); + $pubkey=openssl_pkey_get_details($keys); + $p->setSignatureAlgorithm(Phar::OPENSSL, $privkey); -copy($fname5, $fname6); -file_put_contents($fname6 . '.pubkey', $pubkey['key']); -$p = new Phar($fname6); -var_dump($p->getSignature()); -} catch (Exception $e) { -echo $e->getMessage(); + copy($fname5, $fname6); + file_put_contents($fname6 . '.pubkey', $pubkey['key']); + $p = new Phar($fname6); + var_dump($p->getSignature()); +} catch (Throwable $e) { + echo $e::class, ': ', $e->getMessage(), PHP_EOL; } ?> --CLEAN-- @@ -76,36 +86,42 @@ unlink(__DIR__ . '/' . basename(__FILE__, '.clean.php') . '.6.phar.zip'); unlink(__DIR__ . '/' . basename(__FILE__, '.clean.php') . '.6.phar.zip.pubkey'); ?> --EXPECTF-- +Default: array(2) { ["hash"]=> string(%d) "%s" ["hash_type"]=> string(7) "SHA-256" } +Set MD5: array(2) { ["hash"]=> string(%d) "%s" ["hash_type"]=> string(3) "MD5" } +Set SHA1: array(2) { ["hash"]=> string(%d) "%s" ["hash_type"]=> string(5) "SHA-1" } +Set SHA256: array(2) { ["hash"]=> string(%d) "%s" ["hash_type"]=> string(7) "SHA-256" } +Set SHA512: array(2) { ["hash"]=> string(%d) "%s" ["hash_type"]=> string(7) "SHA-512" } +Set OPENSSL: array(2) { ["hash"]=> string(%d) "%s" From 9a24c6a89f137e1ce046270a8efa9a7f156584b4 Mon Sep 17 00:00:00 2001 From: Gina Peter Banyard Date: Thu, 16 Oct 2025 21:01:29 +0100 Subject: [PATCH 02/14] ext/phar: assert function are not passed NULL pointers This simplifies some of the logic and makes the assumptions clear --- ext/phar/phar.c | 235 ++++++++++++------------------------ ext/phar/phar_internal.h | 34 +++--- ext/phar/phar_object.c | 11 +- ext/phar/phar_path_check.re | 2 +- ext/phar/stream.h | 2 +- ext/phar/tar.c | 85 +++++-------- ext/phar/util.c | 149 ++++++++--------------- ext/phar/zip.c | 99 ++++++--------- 8 files changed, 218 insertions(+), 399 deletions(-) diff --git a/ext/phar/phar.c b/ext/phar/phar.c index b1f6d39171e4d..cec38aa33533e 100644 --- a/ext/phar/phar.c +++ b/ext/phar/phar.c @@ -414,7 +414,7 @@ void phar_entry_delref(phar_entry_data *idata) /* {{{ */ /** * Removes an entry, either by actually removing it or by marking it. */ -void phar_entry_remove(phar_entry_data *idata, char **error) /* {{{ */ +ZEND_ATTRIBUTE_NONNULL void phar_entry_remove(phar_entry_data *idata, char **error) /* {{{ */ { phar_archive_data *phar; @@ -1310,7 +1310,7 @@ static zend_result phar_parse_pharfile(php_stream *fp, char *fname, size_t fname /** * Create or open a phar for writing */ -zend_result phar_open_or_create_filename(char *fname, size_t fname_len, char *alias, size_t alias_len, bool is_data, uint32_t options, phar_archive_data** pphar, char **error) /* {{{ */ +ZEND_ATTRIBUTE_NONNULL_ARGS(1, 7, 8) zend_result phar_open_or_create_filename(char *fname, size_t fname_len, 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; @@ -1319,9 +1319,7 @@ zend_result phar_open_or_create_filename(char *fname, size_t fname_len, char *al test = &unused; - if (error) { - *error = NULL; - } + *error = NULL; /* first try to open an existing file */ if (phar_detect_phar_fname_ext(fname, fname_len, &ext_str, &ext_len, !is_data, 0, true) == SUCCESS) { @@ -1330,25 +1328,19 @@ zend_result phar_open_or_create_filename(char *fname, size_t fname_len, char *al /* next try to create a new file */ if (FAILURE == phar_detect_phar_fname_ext(fname, fname_len, &ext_str, &ext_len, !is_data, 1, true)) { - if (error) { - if (ext_len == -2) { - spprintf(error, 0, "Cannot create a phar archive from a URL like \"%s\". Phar objects can only be created from local files", fname); - } else { - spprintf(error, 0, "Cannot create phar '%s', file extension (or combination) not recognised or the directory does not exist", fname); - } + if (ext_len == -2) { + spprintf(error, 0, "Cannot create a phar archive from a URL like \"%s\". Phar objects can only be created from local files", fname); + } else { + spprintf(error, 0, "Cannot create phar '%s', file extension (or combination) not recognised or the directory does not exist", fname); } return FAILURE; } check_file: if (phar_open_parsed_phar(fname, fname_len, alias, alias_len, is_data, options, test, &my_error) == SUCCESS) { - if (pphar) { - *pphar = *test; - } + *pphar = *test; if ((*test)->is_data && !(*test)->is_tar && !(*test)->is_zip) { - if (error) { - spprintf(error, 0, "Cannot open '%s' as a PharData object. Use Phar::__construct() for executable archives", fname); - } + spprintf(error, 0, "Cannot open '%s' as a PharData object. Use Phar::__construct() for executable archives", fname); return FAILURE; } @@ -1364,11 +1356,7 @@ zend_result phar_open_or_create_filename(char *fname, size_t fname_len, char *al } return SUCCESS; } else if (my_error) { - if (error) { - *error = my_error; - } else { - efree(my_error); - } + *error = my_error; return FAILURE; } @@ -1388,16 +1376,12 @@ zend_result phar_open_or_create_filename(char *fname, size_t fname_len, char *al 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); -zend_result phar_create_or_parse_filename(char *fname, size_t fname_len, char *alias, size_t alias_len, bool is_data, uint32_t options, phar_archive_data** pphar, char **error) /* {{{ */ +ZEND_ATTRIBUTE_NONNULL_ARGS(1, 7, 8) zend_result phar_create_or_parse_filename(char *fname, size_t fname_len, char *alias, size_t alias_len, bool is_data, uint32_t options, phar_archive_data** pphar, char **error) /* {{{ */ { - phar_archive_data *mydata; php_stream *fp; zend_string *actual = NULL; char *p; - if (!pphar) { - pphar = &mydata; - } if (php_check_open_basedir(fname)) { return FAILURE; } @@ -1434,15 +1418,13 @@ zend_result phar_create_or_parse_filename(char *fname, size_t fname_len, char *a if (PHAR_G(readonly) && !is_data) { if (options & REPORT_ERRORS) { - if (error) { - spprintf(error, 0, "creating archive \"%s\" disabled by the php.ini setting phar.readonly", fname); - } + spprintf(error, 0, "creating archive \"%s\" disabled by the php.ini setting phar.readonly", fname); } return FAILURE; } /* set up our manifest */ - mydata = ecalloc(1, sizeof(phar_archive_data)); + phar_archive_data *mydata = ecalloc(1, sizeof(phar_archive_data)); mydata->fname = expand_filepath(fname, NULL); if (mydata->fname == NULL) { efree(mydata); @@ -1464,10 +1446,6 @@ zend_result phar_create_or_parse_filename(char *fname, size_t fname_len, char *a } } - if (pphar) { - *pphar = mydata; - } - zend_hash_init(&mydata->manifest, sizeof(phar_entry_info), zend_get_hash_value, destroy_phar_manifest_entry, 0); zend_hash_init(&mydata->mounted_dirs, sizeof(char *), @@ -1494,15 +1472,11 @@ zend_result phar_create_or_parse_filename(char *fname, size_t fname_len, char *a if (alias && NULL != (fd_ptr = zend_hash_str_find_ptr(&(PHAR_G(phar_alias_map)), alias, alias_len))) { if (SUCCESS != phar_free_alias(fd_ptr, alias, alias_len)) { - if (error) { - spprintf(error, 4096, "phar error: phar \"%s\" cannot set alias \"%s\", already in use by another phar archive", mydata->fname, alias); - } + spprintf(error, 4096, "phar error: phar \"%s\" cannot set alias \"%s\", already in use by another phar archive", mydata->fname, alias); zend_hash_str_del(&(PHAR_G(phar_fname_map)), mydata->fname, fname_len); - if (pphar) { - *pphar = NULL; - } + *pphar = NULL; return FAILURE; } @@ -1516,21 +1490,18 @@ zend_result phar_create_or_parse_filename(char *fname, size_t fname_len, char *a if (alias_len && alias) { if (NULL == zend_hash_str_add_ptr(&(PHAR_G(phar_alias_map)), alias, alias_len, mydata)) { if (options & REPORT_ERRORS) { - if (error) { - spprintf(error, 0, "archive \"%s\" cannot be associated with alias \"%s\", already in use", fname, alias); - } + spprintf(error, 0, "archive \"%s\" cannot be associated with alias \"%s\", already in use", fname, alias); } zend_hash_str_del(&(PHAR_G(phar_fname_map)), mydata->fname, fname_len); - if (pphar) { - *pphar = NULL; - } + *pphar = NULL; return FAILURE; } } + *pphar = mydata; return SUCCESS; } /* }}}*/ @@ -2320,29 +2291,23 @@ zend_result phar_split_fname(const char *filename, size_t filename_len, char **a * Invoked when a user calls Phar::mapPhar() from within an executing .phar * to set up its manifest directly */ -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(char *alias, size_t alias_len, char **error) /* {{{ */ { - if (error) { - *error = NULL; - } + *error = NULL; zend_string *fname = zend_get_executed_filename_ex(); if (!fname) { - if (error) { - spprintf(error, 0, "cannot initialize a phar outside of PHP execution"); - } + *error = estrdup("cannot initialize a phar outside of PHP execution"); return FAILURE; } - if (phar_open_parsed_phar(ZSTR_VAL(fname), ZSTR_LEN(fname), alias, alias_len, false, REPORT_ERRORS, NULL, 0) == SUCCESS) { + if (phar_open_parsed_phar(ZSTR_VAL(fname), ZSTR_LEN(fname), alias, alias_len, false, REPORT_ERRORS, NULL, NULL) == SUCCESS) { return SUCCESS; } - if (0 == zend_get_constant_str("__COMPILER_HALT_OFFSET__", sizeof("__COMPILER_HALT_OFFSET__")-1)) { - if (error) { - spprintf(error, 0, "__HALT_COMPILER(); must be declared in a phar"); - } + if (NULL == zend_get_constant_str("__COMPILER_HALT_OFFSET__", sizeof("__COMPILER_HALT_OFFSET__")-1)) { + *error = estrdup("__HALT_COMPILER(); must be declared in a phar"); return FAILURE; } @@ -2355,9 +2320,7 @@ zend_result phar_open_executed_filename(char *alias, size_t alias_len, char **er fp = php_stream_open_wrapper(ZSTR_VAL(fname), "rb", IGNORE_URL|STREAM_MUST_SEEK|REPORT_ERRORS, &actual); if (!fp) { - if (error) { - spprintf(error, 0, "unable to open phar for reading \"%s\"", ZSTR_VAL(fname)); - } + spprintf(error, 0, "unable to open phar for reading \"%s\"", ZSTR_VAL(fname)); if (actual) { zend_string_release_ex(actual, 0); } @@ -2381,14 +2344,12 @@ zend_result phar_open_executed_filename(char *alias, size_t alias_len, char **er /** * Validate the CRC32 of a file opened from within the phar */ -zend_result phar_postprocess_file(phar_entry_data *idata, uint32_t crc32, char **error, int process_zip) /* {{{ */ +ZEND_ATTRIBUTE_NONNULL zend_result phar_postprocess_file(phar_entry_data *idata, uint32_t crc32, char **error, int process_zip) /* {{{ */ { php_stream *fp = idata->fp; phar_entry_info *entry = idata->internal_file; - if (error) { - *error = NULL; - } + *error = NULL; if (entry->is_zip && process_zip > 0) { /* verify local file header */ @@ -2396,14 +2357,15 @@ zend_result phar_postprocess_file(phar_entry_data *idata, uint32_t crc32, char * phar_zip_data_desc desc; if (SUCCESS != phar_open_archive_fp(idata->phar)) { - spprintf(error, 0, "phar error: unable to open zip-based phar archive \"%s\" to verify local file header for file \"%s\"", idata->phar->fname, ZSTR_VAL(entry->filename)); + spprintf(error, 0, "phar error: unable to open zip-based phar archive \"%s\" to verify local file header for file \"%s\"", + idata->phar->fname, ZSTR_VAL(entry->filename)); return FAILURE; } php_stream_seek(phar_get_entrypfp(idata->internal_file), entry->header_offset, SEEK_SET); if (sizeof(local) != php_stream_read(phar_get_entrypfp(idata->internal_file), (char *) &local, sizeof(local))) { - - spprintf(error, 0, "phar error: internal corruption of zip-based phar \"%s\" (cannot read local file header for file \"%s\")", idata->phar->fname, ZSTR_VAL(entry->filename)); + spprintf(error, 0, "phar error: internal corruption of zip-based phar \"%s\" (cannot read local file header for file \"%s\")", + idata->phar->fname, ZSTR_VAL(entry->filename)); return FAILURE; } @@ -2416,7 +2378,8 @@ zend_result phar_postprocess_file(phar_entry_data *idata, uint32_t crc32, char * entry->compressed_filesize, SEEK_SET); if (sizeof(desc) != php_stream_read(phar_get_entrypfp(idata->internal_file), (char *) &desc, sizeof(desc))) { - spprintf(error, 0, "phar error: internal corruption of zip-based phar \"%s\" (cannot read local data descriptor for file \"%s\")", idata->phar->fname, ZSTR_VAL(entry->filename)); + spprintf(error, 0, "phar error: internal corruption of zip-based phar \"%s\" (cannot read local data descriptor for file \"%s\")", + idata->phar->fname, ZSTR_VAL(entry->filename)); return FAILURE; } if (desc.signature[0] == 'P' && desc.signature[1] == 'K') { @@ -2428,7 +2391,8 @@ zend_result phar_postprocess_file(phar_entry_data *idata, uint32_t crc32, char * } /* verify local header */ if (ZSTR_LEN(entry->filename) != PHAR_ZIP_16(local.filename_len) || entry->crc32 != PHAR_ZIP_32(local.crc32) || entry->uncompressed_filesize != PHAR_ZIP_32(local.uncompsize) || entry->compressed_filesize != PHAR_ZIP_32(local.compsize)) { - spprintf(error, 0, "phar error: internal corruption of zip-based phar \"%s\" (local header of file \"%s\" does not match central directory)", idata->phar->fname, ZSTR_VAL(entry->filename)); + spprintf(error, 0, "phar error: internal corruption of zip-based phar \"%s\" (local header of file \"%s\" does not match central directory)", + idata->phar->fname, ZSTR_VAL(entry->filename)); return FAILURE; } @@ -2456,7 +2420,8 @@ zend_result phar_postprocess_file(phar_entry_data *idata, uint32_t crc32, char * entry->is_crc_checked = 1; return SUCCESS; } else { - spprintf(error, 0, "phar error: internal corruption of phar \"%s\" (crc32 mismatch on file \"%s\")", idata->phar->fname, ZSTR_VAL(entry->filename)); + spprintf(error, 0, "phar error: internal corruption of phar \"%s\" (crc32 mismatch on file \"%s\")", + idata->phar->fname, ZSTR_VAL(entry->filename)); return FAILURE; } } @@ -2527,7 +2492,7 @@ zend_string *phar_create_default_stub(const char *index_php, const char *web_ind } /* }}} */ -void phar_flush(phar_archive_data *phar, char **error) { +ZEND_ATTRIBUTE_NONNULL void phar_flush(phar_archive_data *phar, char **error) { phar_flush_ex(phar, NULL, false, error); } @@ -2536,7 +2501,7 @@ void phar_flush(phar_archive_data *phar, char **error) { * * if user_stub is NULL the default or existing stub should be used */ -void phar_flush_ex(phar_archive_data *phar, zend_string *user_stub, bool is_default_stub, char **error) /* {{{ */ +ZEND_ATTRIBUTE_NONNULL_ARGS(1, 4) void phar_flush_ex(phar_archive_data *phar, zend_string *user_stub, bool is_default_stub, char **error) /* {{{ */ { static const char halt_stub[] = "__HALT_COMPILER();"; @@ -2562,15 +2527,11 @@ void phar_flush_ex(phar_archive_data *phar, zend_string *user_stub, bool is_defa php_stream *shared_cfp = NULL; if (phar->is_persistent) { - if (error) { - spprintf(error, 0, "internal error: attempt to flush cached zip-based phar \"%s\"", phar->fname); - } + spprintf(error, 0, "internal error: attempt to flush cached zip-based phar \"%s\"", phar->fname); return; } - if (error) { - *error = NULL; - } + *error = NULL; if (!zend_hash_num_elements(&phar->manifest) && !user_stub) { return; @@ -2602,9 +2563,7 @@ void phar_flush_ex(phar_archive_data *phar, zend_string *user_stub, bool is_defa } newfile = php_stream_fopen_tmpfile(); if (!newfile) { - if (error) { - spprintf(error, 0, "unable to create temporary file"); - } + *error = estrdup("unable to create temporary file"); if (must_close_old_file) { php_stream_close(oldfile); } @@ -2619,9 +2578,7 @@ void phar_flush_ex(phar_archive_data *phar, zend_string *user_stub, bool is_defa php_stream_close(oldfile); } php_stream_close(newfile); - if (error) { - spprintf(error, 0, "illegal stub for phar \"%s\" (__HALT_COMPILER(); is missing)", phar->fname); - } + spprintf(error, 0, "illegal stub for phar \"%s\" (__HALT_COMPILER(); is missing)", phar->fname); return; } @@ -2637,9 +2594,7 @@ void phar_flush_ex(phar_archive_data *phar, zend_string *user_stub, bool is_defa php_stream_close(oldfile); } php_stream_close(newfile); - if (error) { - spprintf(error, 0, "unable to create stub from string in new phar \"%s\"", phar->fname); - } + spprintf(error, 0, "unable to create stub from string in new phar \"%s\"", phar->fname); return; } phar->halt_offset = len + end_sequence_len; @@ -2660,12 +2615,10 @@ void phar_flush_ex(phar_archive_data *phar, zend_string *user_stub, bool is_defa php_stream_close(oldfile); } php_stream_close(newfile); - if (error) { - if (new_stub) { - spprintf(error, 0, "unable to create stub in new phar \"%s\"", phar->fname); - } else { - spprintf(error, 0, "unable to copy stub of old phar to new phar \"%s\"", phar->fname); - } + if (new_stub) { + spprintf(error, 0, "unable to create stub in new phar \"%s\"", phar->fname); + } else { + spprintf(error, 0, "unable to copy stub of old phar to new phar \"%s\"", phar->fname); } if (new_stub) { zend_string_free(new_stub); @@ -2763,9 +2716,7 @@ void phar_flush_ex(phar_archive_data *phar, zend_string *user_stub, bool is_defa php_stream_close(oldfile); } php_stream_close(newfile); - if (error) { - spprintf(error, 0, "unable to seek to start of file \"%s\" while creating new phar \"%s\"", ZSTR_VAL(entry->filename), phar->fname); - } + spprintf(error, 0, "unable to seek to start of file \"%s\" while creating new phar \"%s\"", ZSTR_VAL(entry->filename), phar->fname); return; } newcrc32 = php_crc32_bulk_init(); @@ -2783,15 +2734,10 @@ void phar_flush_ex(phar_archive_data *phar, zend_string *user_stub, bool is_defa php_stream_close(oldfile); } php_stream_close(newfile); - if (entry->flags & PHAR_ENT_COMPRESSED_GZ) { - if (error) { - spprintf(error, 0, "unable to gzip compress file \"%s\" to new phar \"%s\"", ZSTR_VAL(entry->filename), phar->fname); - } - } else { - if (error) { - spprintf(error, 0, "unable to bzip2 compress file \"%s\" to new phar \"%s\"", ZSTR_VAL(entry->filename), phar->fname); - } - } + spprintf(error, 0, "unable to %s compress file \"%s\" to new phar \"%s\"", + entry->flags & PHAR_ENT_COMPRESSED_GZ ? "gzip" : "bzip2", + ZSTR_VAL(entry->filename), + phar->fname); return; } @@ -2804,9 +2750,7 @@ void phar_flush_ex(phar_archive_data *phar, zend_string *user_stub, bool is_defa entry->cfp = shared_cfp; if (!entry->cfp) { php_stream_filter_free(filter); - if (error) { - spprintf(error, 0, "unable to create temporary file"); - } + *error = estrdup("unable to create temporary file"); if (must_close_old_file) { php_stream_close(oldfile); } @@ -2823,9 +2767,8 @@ void phar_flush_ex(phar_archive_data *phar, zend_string *user_stub, bool is_defa php_stream_close(oldfile); } php_stream_close(newfile); - if (error) { - spprintf(error, 0, "unable to seek to start of file \"%s\" while creating new phar \"%s\"", ZSTR_VAL(entry->filename), phar->fname); - } + spprintf(error, 0, "unable to seek to start of file \"%s\" while creating new phar \"%s\"", + ZSTR_VAL(entry->filename), phar->fname); goto cleanup; } php_stream_filter_append((&entry->cfp->writefilters), filter); @@ -2835,9 +2778,8 @@ void phar_flush_ex(phar_archive_data *phar, zend_string *user_stub, bool is_defa php_stream_close(oldfile); } php_stream_close(newfile); - if (error) { - spprintf(error, 0, "unable to copy compressed file contents of file \"%s\" while creating new phar \"%s\"", ZSTR_VAL(entry->filename), phar->fname); - } + spprintf(error, 0, "unable to copy compressed file contents of file \"%s\" while creating new phar \"%s\"", + ZSTR_VAL(entry->filename), phar->fname); goto cleanup; } php_stream_filter_flush(filter, 1); @@ -2897,9 +2839,7 @@ void phar_flush_ex(phar_archive_data *phar, zend_string *user_stub, bool is_defa php_stream_close(newfile); phar->alias_len = restore_alias_len; - if (error) { - spprintf(error, 0, "unable to write manifest header of new phar \"%s\"", phar->fname); - } + spprintf(error, 0, "unable to write manifest header of new phar \"%s\"", phar->fname); goto cleanup; } @@ -2918,9 +2858,7 @@ void phar_flush_ex(phar_archive_data *phar, zend_string *user_stub, bool is_defa php_stream_close(newfile); phar->alias_len = restore_alias_len; - if (error) { - spprintf(error, 0, "unable to write manifest meta-data of new phar \"%s\"", phar->fname); - } + spprintf(error, 0, "unable to write manifest meta-data of new phar \"%s\"", phar->fname); goto cleanup; } @@ -2951,12 +2889,10 @@ void phar_flush_ex(phar_archive_data *phar, zend_string *user_stub, bool is_defa php_stream_close(oldfile); } php_stream_close(newfile); - if (error) { - if (entry->is_dir) { - spprintf(error, 0, "unable to write filename of directory \"%s\" to manifest of new phar \"%s\"", ZSTR_VAL(entry->filename), phar->fname); - } else { - spprintf(error, 0, "unable to write filename of file \"%s\" to manifest of new phar \"%s\"", ZSTR_VAL(entry->filename), phar->fname); - } + if (entry->is_dir) { + spprintf(error, 0, "unable to write filename of directory \"%s\" to manifest of new phar \"%s\"", ZSTR_VAL(entry->filename), phar->fname); + } else { + spprintf(error, 0, "unable to write filename of file \"%s\" to manifest of new phar \"%s\"", ZSTR_VAL(entry->filename), phar->fname); } goto cleanup; } @@ -2988,9 +2924,7 @@ void phar_flush_ex(phar_archive_data *phar, zend_string *user_stub, bool is_defa php_stream_close(newfile); - if (error) { - spprintf(error, 0, "unable to write temporary manifest of file \"%s\" to manifest of new phar \"%s\"", ZSTR_VAL(entry->filename), phar->fname); - } + spprintf(error, 0, "unable to write temporary manifest of file \"%s\" to manifest of new phar \"%s\"", ZSTR_VAL(entry->filename), phar->fname); goto cleanup; } @@ -3004,9 +2938,7 @@ void phar_flush_ex(phar_archive_data *phar, zend_string *user_stub, bool is_defa php_stream_close(newfile); - if (error) { - spprintf(error, 0, "unable to write manifest padding byte"); - } + *error = estrdup("unable to write manifest padding byte"); goto cleanup; } @@ -3029,9 +2961,7 @@ void phar_flush_ex(phar_archive_data *phar, zend_string *user_stub, bool is_defa php_stream_close(oldfile); } php_stream_close(newfile); - if (error) { - spprintf(error, 0, "unable to seek to start of file \"%s\" while creating new phar \"%s\"", ZSTR_VAL(entry->filename), phar->fname); - } + spprintf(error, 0, "unable to seek to start of file \"%s\" while creating new phar \"%s\"", ZSTR_VAL(entry->filename), phar->fname); goto cleanup; } } @@ -3041,9 +2971,7 @@ void phar_flush_ex(phar_archive_data *phar, zend_string *user_stub, bool is_defa php_stream_close(oldfile); } php_stream_close(newfile); - if (error) { - spprintf(error, 0, "unable to seek to start of file \"%s\" while creating new phar \"%s\"", ZSTR_VAL(entry->filename), phar->fname); - } + spprintf(error, 0, "unable to seek to start of file \"%s\" while creating new phar \"%s\"", ZSTR_VAL(entry->filename), phar->fname); goto cleanup; } @@ -3057,9 +2985,7 @@ void phar_flush_ex(phar_archive_data *phar, zend_string *user_stub, bool is_defa php_stream_close(newfile); - if (error) { - spprintf(error, 0, "unable to write contents of file \"%s\" to new phar \"%s\"", ZSTR_VAL(entry->filename), phar->fname); - } + spprintf(error, 0, "unable to write contents of file \"%s\" to new phar \"%s\"", ZSTR_VAL(entry->filename), phar->fname); goto cleanup; } @@ -3105,12 +3031,11 @@ void phar_flush_ex(phar_archive_data *phar, zend_string *user_stub, bool is_defa char *digest = NULL; size_t digest_len; - if (FAILURE == phar_create_signature(phar, newfile, &digest, &digest_len, error)) { - if (error) { - char *save = *error; - spprintf(error, 0, "phar error: unable to write signature: %s", save); - efree(save); - } + char *signature_error = NULL; + if (FAILURE == phar_create_signature(phar, newfile, &digest, &digest_len, &signature_error)) { + spprintf(error, 0, "phar error: unable to write signature: %s", signature_error); + efree(signature_error); + if (digest) { efree(digest); } @@ -3167,9 +3092,7 @@ void phar_flush_ex(phar_archive_data *phar, zend_string *user_stub, bool is_defa phar->fp = php_stream_open_wrapper(phar->fname, "w+b", IGNORE_URL|STREAM_MUST_SEEK|REPORT_ERRORS, NULL); if (!phar->fp) { phar->fp = newfile; - if (error) { - spprintf(error, 4096, "unable to open new phar \"%s\" for writing", phar->fname); - } + spprintf(error, 4096, "unable to open new phar \"%s\" for writing", phar->fname); return; } @@ -3183,9 +3106,7 @@ void phar_flush_ex(phar_archive_data *phar, zend_string *user_stub, bool is_defa zend_array_destroy(Z_ARR(filterparams)); if (!filter) { - if (error) { - spprintf(error, 4096, "unable to compress all contents of phar \"%s\" using zlib, PHP versions older than 5.2.6 have a buggy zlib", phar->fname); - } + spprintf(error, 4096, "unable to compress all contents of phar \"%s\" using zlib, PHP versions older than 5.2.6 have a buggy zlib", phar->fname); return; } @@ -3213,9 +3134,7 @@ void phar_flush_ex(phar_archive_data *phar, zend_string *user_stub, bool is_defa } if (-1 == php_stream_seek(phar->fp, phar->halt_offset, SEEK_SET)) { - if (error) { - spprintf(error, 0, "unable to seek to __HALT_COMPILER(); in new phar \"%s\"", phar->fname); - } + spprintf(error, 0, "unable to seek to __HALT_COMPILER(); in new phar \"%s\"", phar->fname); } return; diff --git a/ext/phar/phar_internal.h b/ext/phar/phar_internal.h index fe63e075c1b51..232ba579d7f0b 100644 --- a/ext/phar/phar_internal.h +++ b/ext/phar/phar_internal.h @@ -404,15 +404,15 @@ void phar_request_initialize(void); void phar_object_init(void); void phar_destroy_phar_data(phar_archive_data *phar); -zend_result phar_postprocess_file(phar_entry_data *idata, uint32_t crc32, char **error, int process_zip); +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_result phar_open_or_create_filename(char *fname, size_t fname_len, char *alias, size_t alias_len, bool is_data, uint32_t options, phar_archive_data** pphar, char **error); -zend_result phar_create_or_parse_filename(char *fname, size_t fname_len, char *alias, size_t alias_len, bool is_data, uint32_t options, phar_archive_data** pphar, char **error); -zend_result phar_open_executed_filename(char *alias, size_t alias_len, char **error); +ZEND_ATTRIBUTE_NONNULL_ARGS(1, 7, 8) zend_result phar_open_or_create_filename(char *fname, size_t fname_len, char *alias, size_t alias_len, bool is_data, uint32_t options, phar_archive_data** pphar, char **error); +ZEND_ATTRIBUTE_NONNULL_ARGS(1, 7, 8) zend_result phar_create_or_parse_filename(char *fname, size_t fname_len, 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_free_alias(phar_archive_data *phar, char *alias, size_t alias_len); zend_result phar_get_archive(phar_archive_data **archive, char *fname, size_t fname_len, 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, char *fname, char **signature, size_t *signature_len, char **error); -zend_result phar_create_signature(phar_archive_data *phar, php_stream *fp, char **signature, size_t *signature_length, char **error); +ZEND_ATTRIBUTE_NONNULL zend_result phar_create_signature(phar_archive_data *phar, php_stream *fp, char **signature, size_t *signature_length, char **error); /* utility functions */ zend_string *phar_create_default_stub(const char *index_php, const char *web_index, char **error); @@ -424,7 +424,7 @@ void phar_add_virtual_dirs(phar_archive_data *phar, char *filename, size_t filen 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); -phar_entry_info * phar_open_jit(phar_archive_data *phar, phar_entry_info *entry, char **error); +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); /* If this has data, free it and set all values to undefined. */ @@ -436,8 +436,8 @@ zend_result phar_metadata_tracker_unserialize_or_copy(phar_metadata_tracker* tra void destroy_phar_manifest_entry(zval *zv); int phar_seek_efp(phar_entry_info *entry, zend_off_t offset, int whence, zend_off_t position, bool follow_links); php_stream *phar_get_efp(phar_entry_info *entry, bool follow_links); -zend_result phar_copy_entry_fp(phar_entry_info *source, phar_entry_info *dest, char **error); -zend_result phar_open_entry_fp(phar_entry_info *entry, char **error, bool follow_links); +ZEND_ATTRIBUTE_NONNULL zend_result phar_copy_entry_fp(phar_entry_info *source, phar_entry_info *dest, char **error); +ZEND_ATTRIBUTE_NONNULL zend_result phar_open_entry_fp(phar_entry_info *entry, char **error, bool follow_links); phar_entry_info *phar_get_link_source(phar_entry_info *entry); zend_result phar_open_archive_fp(phar_archive_data *phar); zend_result phar_copy_on_write(phar_archive_data **pphar); @@ -445,13 +445,13 @@ zend_result phar_copy_on_write(phar_archive_data **pphar); /* tar functions in tar.c */ bool phar_is_tar(char *buf, char *fname); zend_result phar_parse_tarfile(php_stream* fp, char *fname, size_t fname_len, char *alias, size_t alias_len, phar_archive_data** pphar, uint32_t compression, char **error); -zend_result phar_open_or_create_tar(char *fname, size_t fname_len, char *alias, size_t alias_len, bool is_data, uint32_t options, phar_archive_data** pphar, char **error); -void phar_tar_flush(phar_archive_data *phar, zend_string *user_stub, bool is_default_stub, char **error); +ZEND_ATTRIBUTE_NONNULL_ARGS(1, 7, 8) zend_result phar_open_or_create_tar(char *fname, size_t fname_len, char *alias, size_t alias_len, bool is_data, uint32_t options, phar_archive_data** pphar, char **error); +ZEND_ATTRIBUTE_NONNULL_ARGS(1, 4) void 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, char *fname, size_t fname_len, char *alias, size_t alias_len, phar_archive_data** pphar, char **error); -zend_result phar_open_or_create_zip(char *fname, size_t fname_len, char *alias, size_t alias_len, bool is_data, uint32_t options, phar_archive_data** pphar, char **error); -void phar_zip_flush(phar_archive_data *archive, zend_string *user_stub, bool is_default_stub, char **error); +ZEND_ATTRIBUTE_NONNULL_ARGS(1, 7, 8) zend_result phar_open_or_create_zip(char *fname, size_t fname_len, char *alias, size_t alias_len, bool is_data, uint32_t options, phar_archive_data** pphar, char **error); +ZEND_ATTRIBUTE_NONNULL_ARGS(1, 4) void phar_zip_flush(phar_archive_data *archive, zend_string *user_stub, bool is_default_stub, char **error); #ifdef PHAR_MAIN extern const php_stream_wrapper php_stream_phar_wrapper; @@ -465,10 +465,10 @@ void phar_entry_delref(phar_entry_data *idata); phar_entry_info *phar_get_entry_info(phar_archive_data *phar, char *path, size_t path_len, char **error, bool security); phar_entry_info *phar_get_entry_info_dir(phar_archive_data *phar, char *path, size_t path_len, char dir, char **error, bool security); -phar_entry_data *phar_get_or_create_entry_data(char *fname, size_t fname_len, char *path, size_t path_len, const char *mode, char allow_dir, char **error, bool security); -zend_result phar_get_entry_data(phar_entry_data **ret, char *fname, size_t fname_len, char *path, size_t path_len, const char *mode, char allow_dir, char **error, bool security); -void phar_flush_ex(phar_archive_data *archive, zend_string *user_stub, bool is_default_stub, char **error); -void phar_flush(phar_archive_data *archive, char **error); +ZEND_ATTRIBUTE_NONNULL phar_entry_data *phar_get_or_create_entry_data(char *fname, size_t fname_len, char *path, size_t path_len, const char *mode, char allow_dir, char **error, bool security); +ZEND_ATTRIBUTE_NONNULL zend_result phar_get_entry_data(phar_entry_data **ret, char *fname, size_t fname_len, char *path, size_t path_len, const char *mode, char allow_dir, char **error, bool security); +ZEND_ATTRIBUTE_NONNULL_ARGS(1, 4) void phar_flush_ex(phar_archive_data *archive, zend_string *user_stub, bool is_default_stub, char **error); +ZEND_ATTRIBUTE_NONNULL void phar_flush(phar_archive_data *archive, char **error); zend_result phar_detect_phar_fname_ext(const char *filename, size_t filename_len, const char **ext_str, size_t *ext_len, int executable, int for_create, bool is_complete); zend_result phar_split_fname(const char *filename, size_t filename_len, char **arch, size_t *arch_len, char **entry, size_t *entry_len, int executable, int for_create); @@ -484,6 +484,6 @@ typedef enum { pcr_err_empty_entry } phar_path_check_result; -phar_path_check_result phar_path_check(char **p, size_t *len, const char **error); +ZEND_ATTRIBUTE_NONNULL phar_path_check_result phar_path_check(char **p, size_t *len, const char **error); END_EXTERN_C() diff --git a/ext/phar/phar_object.c b/ext/phar/phar_object.c index 0b7e55c5e9afa..8a7cf236b0973 100644 --- a/ext/phar/phar_object.c +++ b/ext/phar/phar_object.c @@ -4108,7 +4108,7 @@ PHP_METHOD(Phar, delMetadata) } /* }}} */ -static zend_result phar_extract_file(bool overwrite, phar_entry_info *entry, const zend_string *path, char **error) /* {{{ */ +ZEND_ATTRIBUTE_NONNULL static zend_result phar_extract_file(bool overwrite, phar_entry_info *entry, const zend_string *path, char **error) /* {{{ */ { php_stream_statbuf ssb; size_t len; @@ -4245,9 +4245,10 @@ static zend_result phar_extract_file(bool overwrite, phar_entry_info *entry, con } if ((phar_get_fp_type(entry) == PHAR_FP && (entry->flags & PHAR_ENT_COMPRESSION_MASK)) || !phar_get_efp(entry, false)) { - if (FAILURE == phar_open_entry_fp(entry, error, true)) { - if (error) { - spprintf(error, 4096, "Cannot extract \"%s\" to \"%s\", unable to open internal file pointer: %s", ZSTR_VAL(entry->filename), fullpath, *error); + char *open_entry_error = NULL; + if (FAILURE == phar_open_entry_fp(entry, &open_entry_error, true)) { + if (open_entry_error) { + spprintf(error, 4096, "Cannot extract \"%s\" to \"%s\", unable to open internal file pointer: %s", ZSTR_VAL(entry->filename), fullpath, open_entry_error); } else { spprintf(error, 4096, "Cannot extract \"%s\" to \"%s\", unable to open internal file pointer", ZSTR_VAL(entry->filename), fullpath); } @@ -4285,7 +4286,7 @@ static zend_result phar_extract_file(bool overwrite, phar_entry_info *entry, con } /* }}} */ -static int extract_helper(const phar_archive_data *archive, zend_string *search, const zend_string *path_to, bool overwrite, char **error) { /* {{{ */ +ZEND_ATTRIBUTE_NONNULL_ARGS(1, 3, 5) static int extract_helper(const phar_archive_data *archive, zend_string *search, const zend_string *path_to, bool overwrite, char **error) { /* {{{ */ int extracted = 0; phar_entry_info *entry; diff --git a/ext/phar/phar_path_check.re b/ext/phar/phar_path_check.re index 77aa0b1953d3c..689ffaa512442 100644 --- a/ext/phar/phar_path_check.re +++ b/ext/phar/phar_path_check.re @@ -18,7 +18,7 @@ #include "phar_internal.h" -phar_path_check_result phar_path_check(char **s, size_t *len, const char **error) +ZEND_ATTRIBUTE_NONNULL phar_path_check_result phar_path_check(char **s, size_t *len, const char **error) { const unsigned char *p = (const unsigned char*)*s; const unsigned char *m; diff --git a/ext/phar/stream.h b/ext/phar/stream.h index ce75b70dcba00..83b395b4cfca3 100644 --- a/ext/phar/stream.h +++ b/ext/phar/stream.h @@ -21,7 +21,7 @@ BEGIN_EXTERN_C() #include "ext/standard/url.h" php_url* phar_parse_url(php_stream_wrapper *wrapper, const char *filename, const char *mode, int options); -void phar_entry_remove(phar_entry_data *idata, char **error); +ZEND_ATTRIBUTE_NONNULL void phar_entry_remove(phar_entry_data *idata, char **error); static php_stream* phar_wrapper_open_url(php_stream_wrapper *wrapper, const char *path, const char *mode, int options, zend_string **opened_path, php_stream_context *context STREAMS_DC); static int phar_wrapper_rename(php_stream_wrapper *wrapper, const char *url_from, const char *url_to, int options, php_stream_context *context); diff --git a/ext/phar/tar.c b/ext/phar/tar.c index 540f265892299..550183746a2c8 100644 --- a/ext/phar/tar.c +++ b/ext/phar/tar.c @@ -127,7 +127,7 @@ bool phar_is_tar(char *buf, char *fname) /* {{{ */ } /* }}} */ -zend_result phar_open_or_create_tar(char *fname, size_t fname_len, char *alias, size_t alias_len, bool is_data, uint32_t options, phar_archive_data** pphar, char **error) /* {{{ */ +ZEND_ATTRIBUTE_NONNULL_ARGS(1, 7, 8) zend_result phar_open_or_create_tar(char *fname, size_t fname_len, 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, fname_len, alias, alias_len, is_data, options, &phar, error); @@ -136,9 +136,7 @@ zend_result phar_open_or_create_tar(char *fname, size_t fname_len, char *alias, return FAILURE; } - if (pphar) { - *pphar = phar; - } + *pphar = phar; phar->is_data = is_data; @@ -153,9 +151,7 @@ zend_result phar_open_or_create_tar(char *fname, size_t fname_len, char *alias, } /* we've reached here - the phar exists and is a regular phar */ - if (error) { - spprintf(error, 4096, "phar tar error: \"%s\" already exists as a regular phar and must be deleted from disk prior to creating as a tar-based phar", fname); - } + spprintf(error, 4096, "phar tar error: \"%s\" already exists as a regular phar and must be deleted from disk prior to creating as a tar-based phar", fname); return FAILURE; } /* }}} */ @@ -877,7 +873,7 @@ static int phar_tar_writeheaders(zval *zv, void *argument) /* {{{ */ } /* }}} */ -static int phar_tar_setmetadata(const phar_metadata_tracker *tracker, phar_entry_info *entry, char **error) /* {{{ */ +ZEND_ATTRIBUTE_NONNULL static int phar_tar_setmetadata(const phar_metadata_tracker *tracker, phar_entry_info *entry, char **error) /* {{{ */ { /* Copy the metadata from tracker to the new entry being written out to temporary files */ const zend_string *serialized_str; @@ -897,7 +893,7 @@ static int phar_tar_setmetadata(const phar_metadata_tracker *tracker, phar_entry entry->fp = php_stream_fopen_tmpfile(); entry->offset = entry->offset_abs = 0; if (entry->fp == NULL) { - spprintf(error, 0, "phar error: unable to create temporary file"); + *error = estrdup("phar error: unable to create temporary file"); return -1; } if (serialized_str && ZSTR_LEN(serialized_str) != php_stream_write(entry->fp, ZSTR_VAL(serialized_str), ZSTR_LEN(serialized_str))) { @@ -910,7 +906,7 @@ static int phar_tar_setmetadata(const phar_metadata_tracker *tracker, phar_entry } /* }}} */ -static int phar_tar_setupmetadata(zval *zv, void *argument) /* {{{ */ +ZEND_ATTRIBUTE_NONNULL static int phar_tar_setupmetadata(zval *zv, void *argument) /* {{{ */ { struct _phar_pass_tar_info *i = (struct _phar_pass_tar_info *)argument; char **error = i->error; @@ -964,7 +960,7 @@ static int phar_tar_setupmetadata(zval *zv, void *argument) /* {{{ */ } /* }}} */ -void phar_tar_flush(phar_archive_data *phar, zend_string *user_stub, bool is_default_stub, char **error) /* {{{ */ +ZEND_ATTRIBUTE_NONNULL_ARGS(1, 4) void phar_tar_flush(phar_archive_data *phar, zend_string *user_stub, bool is_default_stub, char **error) /* {{{ */ { static const char newstub[] = "is_persistent) { - if (error) { - spprintf(error, 0, "internal error: attempt to flush cached tar-based phar \"%s\"", phar->fname); - } + spprintf(error, 0, "internal error: attempt to flush cached tar-based phar \"%s\"", phar->fname); return; } @@ -1002,13 +996,11 @@ void phar_tar_flush(phar_archive_data *phar, zend_string *user_stub, bool is_def if (!phar->is_temporary_alias && phar->alias_len) { entry.fp = php_stream_fopen_tmpfile(); if (entry.fp == NULL) { - spprintf(error, 0, "phar error: unable to create temporary file"); + *error = estrdup("phar error: unable to create temporary file"); return; } if (phar->alias_len != php_stream_write(entry.fp, phar->alias, phar->alias_len)) { - if (error) { - spprintf(error, 0, "unable to set alias in tar-based phar \"%s\"", phar->fname); - } + spprintf(error, 0, "unable to set alias in tar-based phar \"%s\"", phar->fname); php_stream_close(entry.fp); return; } @@ -1028,9 +1020,7 @@ void phar_tar_flush(phar_archive_data *phar, zend_string *user_stub, bool is_def char *pos = php_stristr(ZSTR_VAL(user_stub), halt_stub, ZSTR_LEN(user_stub), sizeof(halt_stub) - 1); if (pos == NULL) { - if (error) { - spprintf(error, 0, "illegal stub for tar-based phar \"%s\"", phar->fname); - } + spprintf(error, 0, "illegal stub for tar-based phar \"%s\"", phar->fname); return; } @@ -1040,7 +1030,7 @@ void phar_tar_flush(phar_archive_data *phar, zend_string *user_stub, bool is_def entry.fp = php_stream_fopen_tmpfile(); if (entry.fp == NULL) { - spprintf(error, 0, "phar error: unable to create temporary file"); + *error = estrdup("phar error: unable to create temporary file"); return; } entry.uncompressed_filesize = len + end_sequence_len; @@ -1049,9 +1039,7 @@ void phar_tar_flush(phar_archive_data *phar, zend_string *user_stub, bool is_def len != php_stream_write(entry.fp, ZSTR_VAL(user_stub), len) || end_sequence_len != php_stream_write(entry.fp, end_sequence, end_sequence_len) ) { - if (error) { - spprintf(error, 0, "unable to create stub from string in new tar-based phar \"%s\"", phar->fname); - } + spprintf(error, 0, "unable to create stub from string in new tar-based phar \"%s\"", phar->fname); php_stream_close(entry.fp); return; } @@ -1062,14 +1050,13 @@ void phar_tar_flush(phar_archive_data *phar, zend_string *user_stub, bool is_def /* Either this is a brand new phar (add the stub), or the default stub is required (overwrite the stub) */ entry.fp = php_stream_fopen_tmpfile(); if (entry.fp == NULL) { - spprintf(error, 0, "phar error: unable to create temporary file"); + *error = estrdup("phar error: unable to create temporary file"); return; } if (sizeof(newstub)-1 != php_stream_write(entry.fp, newstub, sizeof(newstub)-1)) { php_stream_close(entry.fp); - if (error) { - spprintf(error, 0, "unable to %s stub in%star-based phar \"%s\", failed", user_stub ? "overwrite" : "create", user_stub ? " " : " new ", phar->fname); - } + spprintf(error, 0, "unable to %s stub in%star-based phar \"%s\", failed", + user_stub ? "overwrite" : "create", user_stub ? " " : " new ", phar->fname); return; } @@ -1081,9 +1068,7 @@ void phar_tar_flush(phar_archive_data *phar, zend_string *user_stub, bool is_def if (NULL == zend_hash_add_mem(&phar->manifest, entry.filename, &entry, sizeof(phar_entry_info))) { php_stream_close(entry.fp); zend_string_efree(entry.filename); - if (error) { - spprintf(error, 0, "unable to create stub in tar-based phar \"%s\"", phar->fname); - } + spprintf(error, 0, "unable to create stub in tar-based phar \"%s\"", phar->fname); return; } } else { @@ -1106,9 +1091,7 @@ void phar_tar_flush(phar_archive_data *phar, zend_string *user_stub, bool is_def newfile = php_stream_fopen_tmpfile(); if (!newfile) { - if (error) { - spprintf(error, 0, "unable to create temporary file"); - } + *error = estrdup("unable to create temporary file"); if (must_close_old_file) { php_stream_close(oldfile); } @@ -1159,7 +1142,7 @@ void phar_tar_flush(phar_archive_data *phar, zend_string *user_stub, bool is_def zend_hash_apply_with_argument(&phar->manifest, phar_tar_setupmetadata, (void *) &pass); - if (error && *error) { + if (*error) { if (must_close_old_file) { php_stream_close(oldfile); } @@ -1171,7 +1154,7 @@ void phar_tar_flush(phar_archive_data *phar, zend_string *user_stub, bool is_def zend_hash_apply_with_argument(&phar->manifest, phar_tar_writeheaders, (void *) &pass); - if (error && *error) { + if (*error) { if (must_close_old_file) { php_stream_close(oldfile); } @@ -1183,12 +1166,10 @@ void phar_tar_flush(phar_archive_data *phar, zend_string *user_stub, bool is_def /* add signature for executable tars or tars explicitly set with setSignatureAlgorithm */ if (!phar->is_data || phar->sig_flags) { - if (FAILURE == phar_create_signature(phar, newfile, &signature, &signature_length, error)) { - if (error) { - char *save = *error; - spprintf(error, 0, "phar error: unable to write signature to tar-based phar: %s", save); - efree(save); - } + char *signature_error = NULL; + if (FAILURE == phar_create_signature(phar, newfile, &signature, &signature_length, &signature_error)) { + spprintf(error, 0, "phar error: unable to write signature to tar-based phar: %s", signature_error); + efree(signature_error); if (must_close_old_file) { php_stream_close(oldfile); @@ -1200,7 +1181,7 @@ void phar_tar_flush(phar_archive_data *phar, zend_string *user_stub, bool is_def entry.fp = php_stream_fopen_tmpfile(); if (entry.fp == NULL) { - spprintf(error, 0, "phar error: unable to create temporary file"); + *error = estrdup("phar error: unable to create temporary file"); efree(signature); if (must_close_old_file) { @@ -1225,9 +1206,7 @@ void phar_tar_flush(phar_archive_data *phar, zend_string *user_stub, bool is_def if (8 != php_stream_write(entry.fp, sigbuf, 8) || signature_length != php_stream_write(entry.fp, signature, signature_length)) { efree(signature); - if (error) { - spprintf(error, 0, "phar error: unable to write signature to tar-based phar %s", phar->fname); - } + spprintf(error, 0, "phar error: unable to write signature to tar-based phar %s", phar->fname); if (must_close_old_file) { php_stream_close(oldfile); @@ -1244,7 +1223,7 @@ void phar_tar_flush(phar_archive_data *phar, zend_string *user_stub, bool is_def phar_tar_writeheaders_int(&entry, &pass); ZSTR_ALLOCA_FREE(entry.filename, use_heap); - if (error && *error) { + if (*error) { if (must_close_old_file) { php_stream_close(oldfile); } @@ -1264,7 +1243,7 @@ void phar_tar_flush(phar_archive_data *phar, zend_string *user_stub, bool is_def } /* on error in the hash iterator above, error is set */ - if (error && *error) { + if (*error) { php_stream_close(newfile); return; } @@ -1290,9 +1269,7 @@ void phar_tar_flush(phar_archive_data *phar, zend_string *user_stub, bool is_def phar->fp = php_stream_open_wrapper(phar->fname, "w+b", IGNORE_URL|STREAM_MUST_SEEK|REPORT_ERRORS, NULL); if (!phar->fp) { phar->fp = newfile; - if (error) { - spprintf(error, 0, "unable to open new phar \"%s\" for writing", phar->fname); - } + spprintf(error, 0, "unable to open new phar \"%s\" for writing", phar->fname); return; } @@ -1314,9 +1291,7 @@ void phar_tar_flush(phar_archive_data *phar, zend_string *user_stub, bool is_def /* copy contents uncompressed rather than lose them */ php_stream_copy_to_stream_ex(newfile, phar->fp, PHP_STREAM_COPY_ALL, NULL); php_stream_close(newfile); - if (error) { - spprintf(error, 4096, "unable to compress all contents of phar \"%s\" using zlib, PHP versions older than 5.2.6 have a buggy zlib", phar->fname); - } + spprintf(error, 4096, "unable to compress all contents of phar \"%s\" using zlib, PHP versions older than 5.2.6 have a buggy zlib", phar->fname); return; } diff --git a/ext/phar/util.c b/ext/phar/util.c index 51ebfb36275d7..884e96fb979a6 100644 --- a/ext/phar/util.c +++ b/ext/phar/util.c @@ -362,8 +362,10 @@ zend_string *phar_find_in_include_path(zend_string *filename, phar_archive_data } /* }}} */ -static zend_result phar_create_writeable_entry(phar_archive_data *phar, phar_entry_info *entry, char **error) /* {{{ */ +static ZEND_ATTRIBUTE_NONNULL zend_result phar_create_writeable_entry(phar_archive_data *phar, phar_entry_info *entry, char **error) /* {{{ */ { + *error = NULL; + if (entry->fp_type == PHAR_MOD) { /* already newly created, truncate */ php_stream_truncate_set_size(entry->fp, 0); @@ -381,10 +383,6 @@ static zend_result phar_create_writeable_entry(phar_archive_data *phar, phar_ent return SUCCESS; } - if (error) { - *error = NULL; - } - /* open a new temp file for writing */ if (entry->link) { efree(entry->link); @@ -395,9 +393,7 @@ static zend_result phar_create_writeable_entry(phar_archive_data *phar, phar_ent entry->fp = php_stream_fopen_tmpfile(); if (!entry->fp) { - if (error) { - spprintf(error, 0, "phar error: unable to create temporary file"); - } + *error = estrdup("phar error: unable to create temporary file"); return FAILURE; } @@ -415,7 +411,7 @@ static zend_result phar_create_writeable_entry(phar_archive_data *phar, phar_ent } /* }}} */ -static zend_result phar_separate_entry_fp(phar_entry_info *entry, char **error) /* {{{ */ +ZEND_ATTRIBUTE_NONNULL static zend_result phar_separate_entry_fp(phar_entry_info *entry, char **error) /* {{{ */ { php_stream *fp; phar_entry_info *link; @@ -430,7 +426,7 @@ static zend_result phar_separate_entry_fp(phar_entry_info *entry, char **error) fp = php_stream_fopen_tmpfile(); if (fp == NULL) { - spprintf(error, 0, "phar error: unable to create temporary file"); + *error = estrdup("phar error: unable to create temporary file"); return FAILURE; } phar_seek_efp(entry, 0, SEEK_SET, 0, true); @@ -441,9 +437,7 @@ static zend_result phar_separate_entry_fp(phar_entry_info *entry, char **error) } if (SUCCESS != php_stream_copy_to_stream_ex(phar_get_efp(link, false), fp, link->uncompressed_filesize, NULL)) { - if (error) { - spprintf(error, 4096, "phar error: cannot separate entry file \"%s\" contents in phar archive \"%s\" for write access", ZSTR_VAL(entry->filename), entry->phar->fname); - } + spprintf(error, 4096, "phar error: cannot separate entry file \"%s\" contents in phar archive \"%s\" for write access", ZSTR_VAL(entry->filename), entry->phar->fname); return FAILURE; } @@ -469,7 +463,7 @@ static zend_result phar_separate_entry_fp(phar_entry_info *entry, char **error) * appended, truncated, or read. For read, if the entry is marked unmodified, it is * assumed that the file pointer, if present, is opened for reading */ -zend_result phar_get_entry_data(phar_entry_data **ret, char *fname, size_t fname_len, char *path, size_t path_len, const char *mode, char allow_dir, char **error, bool security) /* {{{ */ +ZEND_ATTRIBUTE_NONNULL zend_result phar_get_entry_data(phar_entry_data **ret, char *fname, size_t fname_len, char *path, size_t path_len, const char *mode, char allow_dir, char **error, bool security) /* {{{ */ { phar_archive_data *phar; phar_entry_info *entry; @@ -478,31 +472,20 @@ zend_result phar_get_entry_data(phar_entry_data **ret, char *fname, size_t fname bool for_create = mode[0] != 'r'; bool for_trunc = mode[0] == 'w'; - if (!ret) { - return FAILURE; - } - *ret = NULL; - - if (error) { - *error = NULL; - } + *error = NULL; if (FAILURE == phar_get_archive(&phar, fname, fname_len, NULL, 0, error)) { return FAILURE; } if (for_write && PHAR_G(readonly) && !phar->is_data) { - if (error) { - spprintf(error, 4096, "phar error: file \"%s\" in phar \"%s\" cannot be opened for writing, disabled by ini setting", path, fname); - } + spprintf(error, 4096, "phar error: file \"%s\" in phar \"%s\" cannot be opened for writing, disabled by ini setting", path, fname); return FAILURE; } if (!path_len) { - if (error) { - spprintf(error, 4096, "phar error: file \"\" in phar \"%s\" must not be empty", fname); - } + spprintf(error, 4096, "phar error: file \"\" in phar \"%s\" must not be empty", fname); return FAILURE; } really_get_entry: @@ -524,9 +507,7 @@ zend_result phar_get_entry_data(phar_entry_data **ret, char *fname, size_t fname if (for_write && phar->is_persistent) { if (FAILURE == phar_copy_on_write(&phar)) { - if (error) { - spprintf(error, 4096, "phar error: file \"%s\" in phar \"%s\" cannot be opened for writing, could not make cached phar writeable", path, fname); - } + spprintf(error, 4096, "phar error: file \"%s\" in phar \"%s\" cannot be opened for writing, could not make cached phar writeable", path, fname); return FAILURE; } else { goto really_get_entry; @@ -534,16 +515,12 @@ zend_result phar_get_entry_data(phar_entry_data **ret, char *fname, size_t fname } if (entry->is_modified && !for_write) { - if (error) { - spprintf(error, 4096, "phar error: file \"%s\" in phar \"%s\" cannot be opened for reading, writable file pointers are open", path, fname); - } + spprintf(error, 4096, "phar error: file \"%s\" in phar \"%s\" cannot be opened for reading, writable file pointers are open", path, fname); return FAILURE; } if (entry->fp_refcount && for_write) { - if (error) { - spprintf(error, 4096, "phar error: file \"%s\" in phar \"%s\" cannot be opened for writing, readable file pointers are open", path, fname); - } + spprintf(error, 4096, "phar error: file \"%s\" in phar \"%s\" cannot be opened for writing, readable file pointers are open", path, fname); return FAILURE; } @@ -629,7 +606,7 @@ zend_result phar_get_entry_data(phar_entry_data **ret, char *fname, size_t fname /** * Create a new dummy file slot within a writeable phar for a newly created file */ -phar_entry_data *phar_get_or_create_entry_data(char *fname, size_t fname_len, char *path, size_t path_len, const char *mode, char allow_dir, char **error, bool security) /* {{{ */ +ZEND_ATTRIBUTE_NONNULL phar_entry_data *phar_get_or_create_entry_data(char *fname, size_t fname_len, char *path, size_t path_len, const char *mode, char allow_dir, char **error, bool security) /* {{{ */ { phar_archive_data *phar; phar_entry_info *entry, etemp; @@ -654,16 +631,12 @@ phar_entry_data *phar_get_or_create_entry_data(char *fname, size_t fname_len, ch } if (phar_path_check(&path, &path_len, &pcr_error) > pcr_is_ok) { - if (error) { - spprintf(error, 0, "phar error: invalid path \"%s\" contains %s", path, pcr_error); - } + spprintf(error, 0, "phar error: invalid path \"%s\" contains %s", path, pcr_error); return NULL; } if (phar->is_persistent && FAILURE == phar_copy_on_write(&phar)) { - if (error) { - spprintf(error, 4096, "phar error: file \"%s\" in phar \"%s\" cannot be created, could not make cached phar writeable", path, fname); - } + spprintf(error, 4096, "phar error: file \"%s\" in phar \"%s\" cannot be created, could not make cached phar writeable", path, fname); return NULL; } @@ -676,9 +649,7 @@ phar_entry_data *phar_get_or_create_entry_data(char *fname, size_t fname_len, ch etemp.fp = php_stream_fopen_tmpfile(); if (!etemp.fp) { - if (error) { - spprintf(error, 0, "phar error: unable to create temporary file"); - } + *error = estrdup("phar error: unable to create temporary file"); efree(ret); return NULL; } @@ -710,9 +681,8 @@ phar_entry_data *phar_get_or_create_entry_data(char *fname, size_t fname_len, ch if (NULL == (entry = zend_hash_add_mem(&phar->manifest, etemp.filename, &etemp, sizeof(phar_entry_info)))) { php_stream_close(etemp.fp); - if (error) { - spprintf(error, 0, "phar error: unable to add new entry \"%s\" to phar \"%s\"", ZSTR_VAL(etemp.filename), phar->fname); - } + spprintf(error, 0, "phar error: unable to add new entry \"%s\" to phar \"%s\"", + ZSTR_VAL(etemp.filename), phar->fname); efree(ret); zend_string_efree(etemp.filename); return NULL; @@ -760,7 +730,7 @@ zend_result phar_open_archive_fp(phar_archive_data *phar) /* {{{ */ /* }}} */ /* copy file data from an existing to a new phar_entry_info that is not in the manifest */ -zend_result phar_copy_entry_fp(phar_entry_info *source, phar_entry_info *dest, char **error) /* {{{ */ +ZEND_ATTRIBUTE_NONNULL zend_result phar_copy_entry_fp(phar_entry_info *source, phar_entry_info *dest, char **error) /* {{{ */ { phar_entry_info *link; @@ -779,7 +749,7 @@ zend_result phar_copy_entry_fp(phar_entry_info *source, phar_entry_info *dest, c dest->is_modified = 1; dest->fp = php_stream_fopen_tmpfile(); if (dest->fp == NULL) { - spprintf(error, 0, "phar error: unable to create temporary file"); + *error = estrdup("phar error: unable to create temporary file"); return EOF; } phar_seek_efp(source, 0, SEEK_SET, 0, true); @@ -792,9 +762,8 @@ zend_result phar_copy_entry_fp(phar_entry_info *source, phar_entry_info *dest, c if (SUCCESS != php_stream_copy_to_stream_ex(phar_get_efp(link, false), dest->fp, link->uncompressed_filesize, NULL)) { php_stream_close(dest->fp); dest->fp_type = PHAR_FP; - if (error) { - spprintf(error, 4096, "phar error: unable to copy contents of file \"%s\" to \"%s\" in phar archive \"%s\"", ZSTR_VAL(source->filename), ZSTR_VAL(dest->filename), source->phar->fname); - } + spprintf(error, 4096, "phar error: unable to copy contents of file \"%s\" to \"%s\" in phar archive \"%s\"", + ZSTR_VAL(source->filename), ZSTR_VAL(dest->filename), source->phar->fname); return FAILURE; } @@ -828,7 +797,7 @@ static void phar_set_fp_type(phar_entry_info *entry, enum phar_fp_type type, zen /* open and decompress a compressed phar entry */ -zend_result phar_open_entry_fp(phar_entry_info *entry, char **error, bool follow_links) /* {{{ */ +ZEND_ATTRIBUTE_NONNULL zend_result phar_open_entry_fp(phar_entry_info *entry, char **error, bool follow_links) /* {{{ */ { php_stream_filter *filter; phar_archive_data *phar = entry->phar; @@ -947,11 +916,9 @@ zend_result phar_open_entry_fp(phar_entry_info *entry, char **error, bool follow /** * helper function to open an internal file's fp just-in-time */ -phar_entry_info * phar_open_jit(phar_archive_data *phar, phar_entry_info *entry, char **error) /* {{{ */ +ZEND_ATTRIBUTE_NONNULL phar_entry_info * phar_open_jit(const phar_archive_data *phar, phar_entry_info *entry, char **error) /* {{{ */ { - if (error) { - *error = NULL; - } + *error = NULL; /* seek to start of internal file and read it */ if (FAILURE == phar_open_entry_fp(entry, error, true)) { return NULL; @@ -1540,7 +1507,7 @@ zend_result phar_verify_signature(php_stream *fp, size_t end_of_phar, uint32_t s #ifndef PHAR_HAVE_OPENSSL if (!zend_hash_str_exists(&module_registry, "openssl", sizeof("openssl")-1)) { if (error) { - spprintf(error, 0, "openssl not loaded"); + *error = estrdup("openssl not loaded"); } return FAILURE; } @@ -1555,7 +1522,7 @@ zend_result phar_verify_signature(php_stream *fp, size_t end_of_phar, uint32_t s php_stream_close(pfp); } if (error) { - spprintf(error, 0, "openssl public key could not be read"); + *error = estrdup("openssl public key could not be read"); } return FAILURE; } @@ -1568,7 +1535,7 @@ zend_result phar_verify_signature(php_stream *fp, size_t end_of_phar, uint32_t s zend_string_release_ex(pubkey, 0); if (error) { - spprintf(error, 0, "openssl signature could not be verified"); + *error = estrdup("openssl signature could not be verified"); } return FAILURE; @@ -1583,7 +1550,7 @@ zend_result phar_verify_signature(php_stream *fp, size_t end_of_phar, uint32_t s if (NULL == in) { zend_string_release_ex(pubkey, 0); if (error) { - spprintf(error, 0, "openssl signature could not be processed"); + *error = estrdup("openssl signature could not be processed"); } return FAILURE; } @@ -1594,7 +1561,7 @@ zend_result phar_verify_signature(php_stream *fp, size_t end_of_phar, uint32_t s if (NULL == key) { if (error) { - spprintf(error, 0, "openssl signature could not be processed"); + *error = estrdup("openssl signature could not be processed"); } return FAILURE; } @@ -1605,7 +1572,7 @@ zend_result phar_verify_signature(php_stream *fp, size_t end_of_phar, uint32_t s EVP_MD_CTX_destroy(md_ctx); } if (error) { - spprintf(error, 0, "openssl signature could not be verified"); + *error = estrdup("openssl signature could not be verified"); } return FAILURE; } @@ -1637,7 +1604,7 @@ zend_result phar_verify_signature(php_stream *fp, size_t end_of_phar, uint32_t s EVP_MD_CTX_destroy(md_ctx); if (error) { - spprintf(error, 0, "broken openssl signature"); + *error = estrdup("broken openssl signature"); } return FAILURE; @@ -1656,7 +1623,7 @@ zend_result phar_verify_signature(php_stream *fp, size_t end_of_phar, uint32_t s if (sig_len < sizeof(digest)) { if (error) { - spprintf(error, 0, "broken signature"); + *error = estrdup("broken openssl signature"); } return FAILURE; } @@ -1682,7 +1649,7 @@ zend_result phar_verify_signature(php_stream *fp, size_t end_of_phar, uint32_t s if (memcmp(digest, sig, sizeof(digest))) { if (error) { - spprintf(error, 0, "broken signature"); + *error = estrdup("broken openssl signature"); } return FAILURE; } @@ -1696,7 +1663,7 @@ zend_result phar_verify_signature(php_stream *fp, size_t end_of_phar, uint32_t s if (sig_len < sizeof(digest)) { if (error) { - spprintf(error, 0, "broken signature"); + *error = estrdup("broken openssl signature"); } return FAILURE; } @@ -1722,7 +1689,7 @@ zend_result phar_verify_signature(php_stream *fp, size_t end_of_phar, uint32_t s if (memcmp(digest, sig, sizeof(digest))) { if (error) { - spprintf(error, 0, "broken signature"); + *error = estrdup("broken signature"); } return FAILURE; } @@ -1736,7 +1703,7 @@ zend_result phar_verify_signature(php_stream *fp, size_t end_of_phar, uint32_t s if (sig_len < sizeof(digest)) { if (error) { - spprintf(error, 0, "broken signature"); + *error = estrdup("broken signature"); } return FAILURE; } @@ -1762,7 +1729,7 @@ zend_result phar_verify_signature(php_stream *fp, size_t end_of_phar, uint32_t s if (memcmp(digest, sig, sizeof(digest))) { if (error) { - spprintf(error, 0, "broken signature"); + *error = estrdup("broken signature"); } return FAILURE; } @@ -1776,7 +1743,7 @@ zend_result phar_verify_signature(php_stream *fp, size_t end_of_phar, uint32_t s if (sig_len < sizeof(digest)) { if (error) { - spprintf(error, 0, "broken signature"); + *error = estrdup("broken signature"); } return FAILURE; } @@ -1802,7 +1769,7 @@ zend_result phar_verify_signature(php_stream *fp, size_t end_of_phar, uint32_t s if (memcmp(digest, sig, sizeof(digest))) { if (error) { - spprintf(error, 0, "broken signature"); + *error = estrdup("broken signature"); } return FAILURE; } @@ -1812,7 +1779,7 @@ zend_result phar_verify_signature(php_stream *fp, size_t end_of_phar, uint32_t s } default: if (error) { - spprintf(error, 0, "broken or unsupported signature"); + *error = estrdup("broken or unsupported signature"); } return FAILURE; } @@ -1820,7 +1787,7 @@ zend_result phar_verify_signature(php_stream *fp, size_t end_of_phar, uint32_t s } /* }}} */ -zend_result phar_create_signature(phar_archive_data *phar, php_stream *fp, char **signature, size_t *signature_length, char **error) /* {{{ */ +ZEND_ATTRIBUTE_NONNULL zend_result phar_create_signature(phar_archive_data *phar, php_stream *fp, char **signature, size_t *signature_length, char **error) /* {{{ */ { unsigned char buf[1024]; size_t sig_len; @@ -1888,9 +1855,7 @@ zend_result phar_create_signature(phar_archive_data *phar, php_stream *fp, char in = BIO_new_mem_buf(PHAR_G(openssl_privatekey), PHAR_G(openssl_privatekey_len)); if (in == NULL) { - if (error) { - spprintf(error, 0, "unable to write to phar \"%s\" with requested openssl signature", phar->fname); - } + spprintf(error, 0, "unable to write to phar \"%s\" with requested openssl signature", phar->fname); return FAILURE; } @@ -1898,18 +1863,14 @@ zend_result phar_create_signature(phar_archive_data *phar, php_stream *fp, char BIO_free(in); if (!key) { - if (error) { - spprintf(error, 0, "unable to process private key"); - } + *error = estrdup("unable to process private key"); return FAILURE; } md_ctx = EVP_MD_CTX_create(); if (md_ctx == NULL) { EVP_PKEY_free(key); - if (error) { - spprintf(error, 0, "unable to initialize openssl signature for phar \"%s\"", phar->fname); - } + spprintf(error, 0, "unable to initialize openssl signature for phar \"%s\"", phar->fname); return FAILURE; } @@ -1920,9 +1881,7 @@ zend_result phar_create_signature(phar_archive_data *phar, php_stream *fp, char EVP_PKEY_free(key); EVP_MD_CTX_free(md_ctx); efree(sigbuf); - if (error) { - spprintf(error, 0, "unable to initialize openssl signature for phar \"%s\"", phar->fname); - } + spprintf(error, 0, "unable to initialize openssl signature for phar \"%s\"", phar->fname); return FAILURE; } @@ -1931,9 +1890,7 @@ zend_result phar_create_signature(phar_archive_data *phar, php_stream *fp, char EVP_PKEY_free(key); EVP_MD_CTX_free(md_ctx); efree(sigbuf); - if (error) { - spprintf(error, 0, "unable to update the openssl signature for phar \"%s\"", phar->fname); - } + spprintf(error, 0, "unable to update the openssl signature for phar \"%s\"", phar->fname); return FAILURE; } } @@ -1942,9 +1899,7 @@ zend_result phar_create_signature(phar_archive_data *phar, php_stream *fp, char EVP_PKEY_free(key); EVP_MD_CTX_free(md_ctx); efree(sigbuf); - if (error) { - spprintf(error, 0, "unable to write phar \"%s\" with requested openssl signature", phar->fname); - } + spprintf(error, 0, "unable to write phar \"%s\" with requested openssl signature", phar->fname); return FAILURE; } @@ -1958,9 +1913,7 @@ zend_result phar_create_signature(phar_archive_data *phar, php_stream *fp, char 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 (error) { - spprintf(error, 0, "unable to write phar \"%s\" with requested openssl signature", phar->fname); - } + spprintf(error, 0, "unable to write phar \"%s\" with requested openssl signature", phar->fname); return FAILURE; } #endif diff --git a/ext/phar/zip.c b/ext/phar/zip.c index 4949750e28706..e8ffecec57147 100644 --- a/ext/phar/zip.c +++ b/ext/phar/zip.c @@ -798,7 +798,7 @@ zend_result phar_parse_zipfile(php_stream *fp, char *fname, size_t fname_len, ch /** * Create or open a zip-based phar for writing */ -zend_result phar_open_or_create_zip(char *fname, size_t fname_len, char *alias, size_t alias_len, bool is_data, uint32_t options, phar_archive_data** pphar, char **error) /* {{{ */ +ZEND_ATTRIBUTE_NONNULL_ARGS(1, 7, 8) zend_result phar_open_or_create_zip(char *fname, size_t fname_len, 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, fname_len, alias, alias_len, is_data, options, &phar, error); @@ -807,9 +807,7 @@ zend_result phar_open_or_create_zip(char *fname, size_t fname_len, char *alias, return FAILURE; } - if (pphar) { - *pphar = phar; - } + *pphar = phar; phar->is_data = is_data; @@ -824,9 +822,7 @@ zend_result phar_open_or_create_zip(char *fname, size_t fname_len, char *alias, } /* we've reached here - the phar exists and is a regular phar */ - if (error) { - spprintf(error, 4096, "phar zip error: phar \"%s\" already exists as a regular phar and must be deleted from disk prior to creating as a zip-based phar", fname); - } + spprintf(error, 4096, "phar zip error: phar \"%s\" already exists as a regular phar and must be deleted from disk prior to creating as a zip-based phar", fname); return FAILURE; } @@ -1178,11 +1174,11 @@ static zend_result phar_zip_applysignature(phar_archive_data *phar, struct _phar php_stream_write(newfile, ZSTR_VAL(phar->metadata_tracker.str), ZSTR_LEN(phar->metadata_tracker.str)); } - if (FAILURE == phar_create_signature(phar, newfile, &signature, &signature_length, pass->error)) { - if (pass->error) { - char *save = *(pass->error); - spprintf(pass->error, 0, "phar error: unable to write signature to zip-based phar: %s", save); - efree(save); + char *signature_error = NULL; + if (FAILURE == phar_create_signature(phar, newfile, &signature, &signature_length, &signature_error)) { + if (signature_error) { + spprintf(pass->error, 0, "phar error: unable to write signature to zip-based phar: %s", signature_error); + efree(signature_error); } php_stream_close(newfile); @@ -1231,7 +1227,7 @@ static zend_result phar_zip_applysignature(phar_archive_data *phar, struct _phar } /* }}} */ -void phar_zip_flush(phar_archive_data *phar, zend_string *user_stub, bool is_default_stub, char **error) /* {{{ */ +ZEND_ATTRIBUTE_NONNULL_ARGS(1, 4) void phar_zip_flush(phar_archive_data *phar, zend_string *user_stub, bool is_default_stub, char **error) /* {{{ */ { static const char newstub[] = "is_persistent) { - if (error) { - spprintf(error, 0, "internal error: attempt to flush cached zip-based phar \"%s\"", phar->fname); - } + spprintf(error, 0, "internal error: attempt to flush cached zip-based phar \"%s\"", phar->fname); return; } @@ -1267,13 +1258,11 @@ void phar_zip_flush(phar_archive_data *phar, zend_string *user_stub, bool is_def if (!phar->is_temporary_alias && phar->alias_len) { entry.fp = php_stream_fopen_tmpfile(); if (entry.fp == NULL) { - spprintf(error, 0, "phar error: unable to create temporary file"); + *error = estrdup("phar error: unable to create temporary file"); return; } if (phar->alias_len != php_stream_write(entry.fp, phar->alias, phar->alias_len)) { - if (error) { - spprintf(error, 0, "unable to set alias in zip-based phar \"%s\"", phar->fname); - } + spprintf(error, 0, "unable to set alias in zip-based phar \"%s\"", phar->fname); return; } @@ -1297,9 +1286,7 @@ void phar_zip_flush(phar_archive_data *phar, zend_string *user_stub, bool is_def char *pos = php_stristr(ZSTR_VAL(user_stub), halt_stub, ZSTR_LEN(user_stub), strlen(halt_stub)); if (pos == NULL) { - if (error) { - spprintf(error, 0, "illegal stub for zip-based phar \"%s\"", phar->fname); - } + spprintf(error, 0, "illegal stub for zip-based phar \"%s\"", phar->fname); return; } @@ -1309,7 +1296,7 @@ void phar_zip_flush(phar_archive_data *phar, zend_string *user_stub, bool is_def entry.fp = php_stream_fopen_tmpfile(); if (entry.fp == NULL) { - spprintf(error, 0, "phar error: unable to create temporary file"); + *error = estrdup("phar error: unable to create temporary file"); return; } entry.uncompressed_filesize = len + end_sequence_len; @@ -1318,9 +1305,7 @@ void phar_zip_flush(phar_archive_data *phar, zend_string *user_stub, bool is_def len != php_stream_write(entry.fp, ZSTR_VAL(user_stub), len) || end_sequence_len != php_stream_write(entry.fp, end_sequence, end_sequence_len) ) { - if (error) { - spprintf(error, 0, "unable to create stub from string in new zip-based phar \"%s\"", phar->fname); - } + spprintf(error, 0, "unable to create stub from string in new zip-based phar \"%s\"", phar->fname); php_stream_close(entry.fp); return; } @@ -1332,14 +1317,12 @@ void phar_zip_flush(phar_archive_data *phar, zend_string *user_stub, bool is_def /* Either this is a brand new phar (add the stub), or the default stub is required (overwrite the stub) */ entry.fp = php_stream_fopen_tmpfile(); if (entry.fp == NULL) { - spprintf(error, 0, "phar error: unable to create temporary file"); + *error = estrdup("phar error: unable to create temporary file"); return; } if (sizeof(newstub)-1 != php_stream_write(entry.fp, newstub, sizeof(newstub)-1)) { php_stream_close(entry.fp); - if (error) { - spprintf(error, 0, "unable to %s stub in%szip-based phar \"%s\", failed", user_stub ? "overwrite" : "create", user_stub ? " " : " new ", phar->fname); - } + spprintf(error, 0, "unable to %s stub in%szip-based phar \"%s\", failed", user_stub ? "overwrite" : "create", user_stub ? " " : " new ", phar->fname); return; } @@ -1351,9 +1334,7 @@ void phar_zip_flush(phar_archive_data *phar, zend_string *user_stub, bool is_def if (NULL == zend_hash_add_mem(&phar->manifest, entry.filename, &entry, sizeof(phar_entry_info))) { php_stream_close(entry.fp); zend_string_efree(entry.filename); - if (error) { - spprintf(error, 0, "unable to create stub in zip-based phar \"%s\"", phar->fname); - } + spprintf(error, 0, "unable to create stub in zip-based phar \"%s\"", phar->fname); return; } } else { @@ -1375,6 +1356,9 @@ void phar_zip_flush(phar_archive_data *phar, zend_string *user_stub, bool is_def } /* save modified files to the zip */ + char *pass_error = NULL; + struct _phar_zip_pass pass; + pass.error = &pass_error; pass.old = oldfile; pass.filefp = php_stream_fopen_tmpfile(); @@ -1383,9 +1367,7 @@ void phar_zip_flush(phar_archive_data *phar, zend_string *user_stub, bool is_def if (must_close_old_file) { php_stream_close(oldfile); } - if (error) { - spprintf(error, 4096, "phar zip flush of \"%s\" failed: unable to open temporary file", phar->fname); - } + spprintf(error, 4096, "phar zip flush of \"%s\" failed: unable to open temporary file", phar->fname); return; } @@ -1413,13 +1395,11 @@ void phar_zip_flush(phar_archive_data *phar, zend_string *user_stub, bool is_def zend_hash_apply_with_argument(&phar->manifest, phar_zip_changed_apply, (void *) &pass); phar_metadata_tracker_try_ensure_has_serialized_data(&phar->metadata_tracker, phar->is_persistent); - if (temperr) { -temperror: - if (error) { - spprintf(error, 4096, "phar zip flush of \"%s\" failed: %s", phar->fname, temperr); - } - efree(temperr); -notemperror: + if (pass_error) { +has_pass_error: + spprintf(error, 4096, "phar zip flush of \"%s\" failed: %s", phar->fname, pass_error); + efree(pass_error); +nopasserror: php_stream_close(pass.centralfp); nocentralerror: php_stream_close(pass.filefp); @@ -1430,7 +1410,8 @@ void phar_zip_flush(phar_archive_data *phar, zend_string *user_stub, bool is_def } if (FAILURE == phar_zip_applysignature(phar, &pass)) { - goto temperror; + ZEND_ASSERT(pass_error != NULL); + goto has_pass_error; } /* save zip */ @@ -1444,10 +1425,8 @@ void phar_zip_flush(phar_archive_data *phar, zend_string *user_stub, bool is_def size_t clen; zend_result ret = php_stream_copy_to_stream_ex(pass.centralfp, pass.filefp, PHP_STREAM_COPY_ALL, &clen); if (SUCCESS != ret || clen != cdir_size) { - if (error) { - spprintf(error, 4096, "phar zip flush of \"%s\" failed: unable to write central-directory", phar->fname); - } - goto notemperror; + spprintf(error, 4096, "phar zip flush of \"%s\" failed: unable to write central-directory", phar->fname); + goto nopasserror; } } @@ -1459,23 +1438,17 @@ void phar_zip_flush(phar_archive_data *phar, zend_string *user_stub, bool is_def PHAR_SET_16(eocd.comment_len, ZSTR_LEN(phar->metadata_tracker.str)); if (sizeof(eocd) != php_stream_write(pass.filefp, (char *)&eocd, sizeof(eocd))) { - if (error) { - spprintf(error, 4096, "phar zip flush of \"%s\" failed: unable to write end of central-directory", phar->fname); - } + spprintf(error, 4096, "phar zip flush of \"%s\" failed: unable to write end of central-directory", phar->fname); goto nocentralerror; } if (ZSTR_LEN(phar->metadata_tracker.str) != php_stream_write(pass.filefp, ZSTR_VAL(phar->metadata_tracker.str), ZSTR_LEN(phar->metadata_tracker.str))) { - if (error) { - spprintf(error, 4096, "phar zip flush of \"%s\" failed: unable to write metadata to zip comment", phar->fname); - } + spprintf(error, 4096, "phar zip flush of \"%s\" failed: unable to write metadata to zip comment", phar->fname); goto nocentralerror; } } else { if (sizeof(eocd) != php_stream_write(pass.filefp, (char *)&eocd, sizeof(eocd))) { - if (error) { - spprintf(error, 4096, "phar zip flush of \"%s\" failed: unable to write end of central-directory", phar->fname); - } + spprintf(error, 4096, "phar zip flush of \"%s\" failed: unable to write end of central-directory", phar->fname); goto nocentralerror; } } @@ -1504,9 +1477,7 @@ void phar_zip_flush(phar_archive_data *phar, zend_string *user_stub, bool is_def php_stream_close(oldfile); } phar->fp = pass.filefp; - if (error) { - spprintf(error, 4096, "unable to open new phar \"%s\" for writing", phar->fname); - } + spprintf(error, 4096, "unable to open new phar \"%s\" for writing", phar->fname); return; } php_stream_rewind(pass.filefp); From 6ac29ec0742bdae3f864301db318a89553fa6ed0 Mon Sep 17 00:00:00 2001 From: Gina Peter Banyard Date: Thu, 16 Oct 2025 00:40:42 +0100 Subject: [PATCH 03/14] ext/phar: remove unused parameters for phar_do_403() --- ext/phar/phar_object.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ext/phar/phar_object.c b/ext/phar/phar_object.c index 8a7cf236b0973..3dc8b40a32c6a 100644 --- a/ext/phar/phar_object.c +++ b/ext/phar/phar_object.c @@ -311,7 +311,7 @@ static int phar_file_action(phar_archive_data *phar, phar_entry_info *info, char } /* }}} */ -static void phar_do_403(char *entry, size_t entry_len) /* {{{ */ +static void phar_do_403(void) /* {{{ */ { sapi_header_line ctr = {0}; @@ -723,7 +723,7 @@ PHP_METHOD(Phar, webPhar) break; case IS_TRUE: case IS_FALSE: - phar_do_403(entry, entry_len); + phar_do_403(); if (free_pathinfo) { efree(path_info); From c0856bc729ffef65a437eef4149465d0e795f662 Mon Sep 17 00:00:00 2001 From: Gina Peter Banyard Date: Wed, 15 Oct 2025 23:31:27 +0100 Subject: [PATCH 04/14] ext/phar: remove unused parameters for phar_do_404() --- ext/phar/phar_object.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/ext/phar/phar_object.c b/ext/phar/phar_object.c index 3dc8b40a32c6a..73e0daf1ccae8 100644 --- a/ext/phar/phar_object.c +++ b/ext/phar/phar_object.c @@ -325,7 +325,7 @@ static void phar_do_403(void) /* {{{ */ } /* }}} */ -static void phar_do_404(phar_archive_data *phar, char *fname, size_t fname_len, char *f404, size_t f404_len, char *entry, size_t entry_len) /* {{{ */ +static void phar_do_404(phar_archive_data *phar, char *fname, size_t fname_len, char *f404, size_t f404_len) /* {{{ */ { sapi_header_line ctr = {0}; phar_entry_info *info; @@ -769,7 +769,7 @@ PHP_METHOD(Phar, webPhar) 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_do_404(phar, fname, fname_len, f404, f404_len, entry, entry_len); + phar_do_404(phar, fname, fname_len, f404, f404_len); if (free_pathinfo) { efree(path_info); @@ -815,7 +815,7 @@ PHP_METHOD(Phar, webPhar) 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_do_404(phar, fname, fname_len, f404, f404_len, entry, entry_len); + phar_do_404(phar, fname, fname_len, f404, f404_len); zend_bailout(); } From d7eef8c4305219f7e2a23dea0bd7ca1702609ff2 Mon Sep 17 00:00:00 2001 From: Gina Peter Banyard Date: Thu, 16 Oct 2025 00:42:35 +0100 Subject: [PATCH 05/14] ext/phar: use zend_string for f404 param of phar_do_404() --- ext/phar/phar_object.c | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/ext/phar/phar_object.c b/ext/phar/phar_object.c index 73e0daf1ccae8..e4edfee5a68b7 100644 --- a/ext/phar/phar_object.c +++ b/ext/phar/phar_object.c @@ -325,16 +325,16 @@ static void phar_do_403(void) /* {{{ */ } /* }}} */ -static void phar_do_404(phar_archive_data *phar, char *fname, size_t fname_len, char *f404, size_t f404_len) /* {{{ */ +static void phar_do_404(phar_archive_data *phar, char *fname, size_t fname_len, zend_string *f404) /* {{{ */ { sapi_header_line ctr = {0}; phar_entry_info *info; - if (phar && f404_len) { - info = phar_get_entry_info(phar, f404, f404_len, NULL, true); + if (phar && f404 && ZSTR_LEN(f404)) { + info = phar_get_entry_info(phar, ZSTR_VAL(f404), ZSTR_LEN(f404), NULL, true); if (info) { - phar_file_action(phar, info, "text/html", PHAR_MIME_PHP, f404, f404_len, fname, NULL, NULL, 0); + phar_file_action(phar, info, "text/html", PHAR_MIME_PHP, ZSTR_VAL(f404), ZSTR_LEN(f404), fname, NULL, NULL, 0); return; } } @@ -559,8 +559,9 @@ PHP_METHOD(Phar, webPhar) zval *mimeoverride = NULL; zend_fcall_info rewrite_fci = {0}; zend_fcall_info_cache rewrite_fcc; - char *alias = NULL, *error, *index_php = NULL, *f404 = NULL, *ru = NULL; - size_t alias_len = 0, f404_len = 0, free_pathinfo = 0; + char *alias = NULL, *error, *index_php = NULL, *ru = NULL; + size_t alias_len = 0, free_pathinfo = 0; + zend_string *f404 = NULL; size_t ru_len = 0; char *fname, *path_info, *mime_type = NULL, *entry, *pt; const char *basename; @@ -571,7 +572,7 @@ PHP_METHOD(Phar, webPhar) phar_entry_info *info = NULL; size_t sapi_mod_name_len = strlen(sapi_module.name); - if (zend_parse_parameters(ZEND_NUM_ARGS(), "|s!s!s!af!", &alias, &alias_len, &index_php, &index_php_len, &f404, &f404_len, &mimeoverride, &rewrite_fci, &rewrite_fcc) == FAILURE) { + if (zend_parse_parameters(ZEND_NUM_ARGS(), "|s!s!S!af!", &alias, &alias_len, &index_php, &index_php_len, &f404, &mimeoverride, &rewrite_fci, &rewrite_fcc) == FAILURE) { RETURN_THROWS(); } @@ -769,7 +770,7 @@ PHP_METHOD(Phar, webPhar) 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_do_404(phar, fname, fname_len, f404, f404_len); + phar_do_404(phar, fname, fname_len, f404); if (free_pathinfo) { efree(path_info); @@ -815,7 +816,7 @@ PHP_METHOD(Phar, webPhar) 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_do_404(phar, fname, fname_len, f404, f404_len); + phar_do_404(phar, fname, fname_len, f404); zend_bailout(); } From 8fa09cd252cfe63f045c0876fd63e8c4b0d023cd Mon Sep 17 00:00:00 2001 From: Gina Peter Banyard Date: Wed, 15 Oct 2025 23:37:41 +0100 Subject: [PATCH 06/14] ext/phar: Use RETURN_BOOL() when possible --- ext/phar/phar_object.c | 44 ++++++++++++------------------------------ 1 file changed, 12 insertions(+), 32 deletions(-) diff --git a/ext/phar/phar_object.c b/ext/phar/phar_object.c index e4edfee5a68b7..171015582796d 100644 --- a/ext/phar/phar_object.c +++ b/ext/phar/phar_object.c @@ -1030,23 +1030,11 @@ PHP_METHOD(Phar, canCompress) phar_request_initialize(); switch (method) { case PHAR_ENT_COMPRESSED_GZ: - if (PHAR_G(has_zlib)) { - RETURN_TRUE; - } else { - RETURN_FALSE; - } + RETURN_BOOL(PHAR_G(has_zlib)); case PHAR_ENT_COMPRESSED_BZ2: - if (PHAR_G(has_bz2)) { - RETURN_TRUE; - } else { - RETURN_FALSE; - } + RETURN_BOOL(PHAR_G(has_bz2)); default: - if (PHAR_G(has_zlib) || PHAR_G(has_bz2)) { - RETURN_TRUE; - } else { - RETURN_FALSE; - } + RETURN_BOOL(PHAR_G(has_zlib) || PHAR_G(has_bz2)); } } /* }}} */ @@ -2577,11 +2565,8 @@ PHP_METHOD(Phar, isWritable) } if (SUCCESS != php_stream_stat_path(phar_obj->archive->fname, &ssb)) { - if (phar_obj->archive->is_brandnew) { - /* assume it works if the file doesn't exist yet */ - RETURN_TRUE; - } - RETURN_FALSE; + /* assume it works if the file doesn't exist yet */ + RETURN_BOOL(phar_obj->archive->is_brandnew); } RETURN_BOOL((ssb.sb.st_mode & (S_IWOTH | S_IWGRP | S_IWUSR)) != 0); @@ -3503,7 +3488,6 @@ PHP_METHOD(Phar, copy) PHP_METHOD(Phar, offsetExists) { zend_string *file_name; - phar_entry_info *entry; if (zend_parse_parameters(ZEND_NUM_ARGS(), "P", &file_name) == FAILURE) { RETURN_THROWS(); @@ -3511,19 +3495,15 @@ PHP_METHOD(Phar, offsetExists) PHAR_ARCHIVE_OBJECT(); - if (zend_hash_exists(&phar_obj->archive->manifest, file_name)) { - if (NULL != (entry = zend_hash_find_ptr(&phar_obj->archive->manifest, file_name))) { - if (entry->is_deleted) { - /* entry is deleted, but has not been flushed to disk yet */ - RETURN_FALSE; - } - } - - if (zend_string_starts_with_literal(file_name, ".phar")) { - /* none of these are real files, so they don't exist */ + const phar_entry_info *entry = zend_hash_find_ptr(&phar_obj->archive->manifest, file_name); + if (entry != NULL) { + if (entry->is_deleted) { + /* entry is deleted, but has not been flushed to disk yet */ RETURN_FALSE; } - RETURN_TRUE; + + /* none of these are real files, so they don't exist */ + RETURN_BOOL(!zend_string_starts_with_literal(file_name, ".phar")); } else { /* If the info class is not based on PharFileInfo, directories are not directly instantiable */ if (UNEXPECTED(!instanceof_function(phar_obj->spl.info_class, phar_ce_entry))) { From 44a863a805819c4bf2f9fbd0b17051f5b11f4789 Mon Sep 17 00:00:00 2001 From: Gina Peter Banyard Date: Thu, 16 Oct 2025 00:03:28 +0100 Subject: [PATCH 07/14] ext/phar: Do not aquire lifetime of basename parameter in phar_file_action() This is incredibly confusing. --- ext/phar/phar_object.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/ext/phar/phar_object.c b/ext/phar/phar_object.c index 171015582796d..6741ca40f5667 100644 --- a/ext/phar/phar_object.c +++ b/ext/phar/phar_object.c @@ -168,7 +168,6 @@ static int phar_file_action(phar_archive_data *phar, phar_entry_info *info, char switch (code) { case PHAR_MIME_PHPS: - efree(basename); /* highlight source */ if (entry[0] == '/') { spprintf(&name, 4096, "phar://%s%s", arch, entry); @@ -186,7 +185,6 @@ static int phar_file_action(phar_archive_data *phar, phar_entry_info *info, char zend_bailout(); case PHAR_MIME_OTHER: /* send headers, output file contents */ - efree(basename); ctr.line_len = spprintf((char **) &(ctr.line), 0, "Content-type: %s", mime_type); sapi_header_op(SAPI_HEADER_REPLACE, &ctr); efree((void *) ctr.line); @@ -230,7 +228,6 @@ static int phar_file_action(phar_archive_data *phar, phar_entry_info *info, char case PHAR_MIME_PHP: if (basename) { phar_mung_server_vars(arch, entry, entry_len, basename, ru_len); - efree(basename); } if (entry[0] == '/') { @@ -870,6 +867,7 @@ PHP_METHOD(Phar, webPhar) code = phar_file_type(&PHAR_G(mime_types), entry, &mime_type); } phar_file_action(phar, info, mime_type, code, entry, entry_len, fname, pt, ru, ru_len); + efree(pt); finish: ; #ifdef PHP_WIN32 From 0b37777592f20f42522e94335d2ef778005ec07a Mon Sep 17 00:00:00 2001 From: Gina Peter Banyard Date: Thu, 16 Oct 2025 00:10:57 +0100 Subject: [PATCH 08/14] ext/phar/phar_object.c: add some const qualifiers --- ext/phar/phar_object.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/ext/phar/phar_object.c b/ext/phar/phar_object.c index 6741ca40f5667..e1c18cd4bac63 100644 --- a/ext/phar/phar_object.c +++ b/ext/phar/phar_object.c @@ -45,7 +45,7 @@ static zend_class_entry *phar_ce_entry; RETURN_THROWS(); \ } -static int phar_file_type(HashTable *mimes, char *file, char **mime_type) /* {{{ */ +static int phar_file_type(const HashTable *mimes, const char *file, char **mime_type) /* {{{ */ { char *ext; phar_mime_type *mime; @@ -65,7 +65,7 @@ static int phar_file_type(HashTable *mimes, char *file, char **mime_type) /* {{{ } /* }}} */ -static void phar_mung_server_vars(char *fname, char *entry, size_t entry_len, char *basename, size_t request_uri_len) /* {{{ */ +static void phar_mung_server_vars(char *fname, char *entry, size_t entry_len, const char *basename, size_t request_uri_len) /* {{{ */ { HashTable *_SERVER; zval *stuff; @@ -151,7 +151,7 @@ static void phar_mung_server_vars(char *fname, char *entry, size_t entry_len, ch } /* }}} */ -static int phar_file_action(phar_archive_data *phar, phar_entry_info *info, char *mime_type, int code, char *entry, size_t entry_len, char *arch, char *basename, char *ru, size_t ru_len) /* {{{ */ +static int phar_file_action(phar_archive_data *phar, phar_entry_info *info, char *mime_type, int code, char *entry, size_t entry_len, char *arch, const char *basename, char *ru, size_t ru_len) /* {{{ */ { char *name = NULL, buf[8192]; const char *cwd; @@ -349,7 +349,7 @@ 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(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, char **entry, size_t *entry_len, char **ru, size_t *ru_len) /* {{{ */ { char *e = *entry + 1, *u = NULL, *u1 = NULL, *saveu = NULL; size_t e_len = *entry_len - 1, u_len = 0; @@ -627,7 +627,7 @@ PHP_METHOD(Phar, webPhar) || (sapi_mod_name_len == sizeof("litespeed") - 1 && !strncmp(sapi_module.name, "litespeed", sizeof("litespeed") - 1))) { if (Z_TYPE(PG(http_globals)[TRACK_VARS_SERVER]) != IS_UNDEF) { - HashTable *_server = Z_ARRVAL(PG(http_globals)[TRACK_VARS_SERVER]); + const HashTable *_server = Z_ARRVAL(PG(http_globals)[TRACK_VARS_SERVER]); zval *z_script_name, *z_path_info; if (NULL == (z_script_name = zend_hash_str_find(_server, "SCRIPT_NAME", sizeof("SCRIPT_NAME")-1)) || @@ -3114,7 +3114,7 @@ static int phar_set_compression(zval *zv, void *argument) /* {{{ */ static int phar_test_compression(zval *zv, void *argument) /* {{{ */ { - phar_entry_info *entry = (phar_entry_info *)Z_PTR_P(zv); + const phar_entry_info *entry = Z_PTR_P(zv); if (entry->is_deleted) { return ZEND_HASH_APPLY_KEEP; From 3828b2426be742f5cc80512af26b5c15806f4122 Mon Sep 17 00:00:00 2001 From: Gina Peter Banyard Date: Thu, 16 Oct 2025 00:56:10 +0100 Subject: [PATCH 09/14] ext/phar: Refactor phar_create_default_stub() --- ext/phar/phar.c | 50 ++++++++++++++++++++++------------------ ext/phar/phar_internal.h | 2 +- ext/phar/phar_object.c | 12 +++++----- 3 files changed, 35 insertions(+), 29 deletions(-) diff --git a/ext/phar/phar.c b/ext/phar/phar.c index cec38aa33533e..f31a4f841225f 100644 --- a/ext/phar/phar.c +++ b/ext/phar/phar.c @@ -2453,42 +2453,48 @@ static int phar_flush_clean_deleted_apply(zval *zv) /* {{{ */ #include "stub.h" /* Generated phar_get_stub() function from makestub.php script */ -zend_string *phar_create_default_stub(const char *index_php, const char *web_index, char **error) /* {{{ */ +zend_string *phar_create_default_stub(const zend_string *php_index_str, const zend_string *web_index_str, char **error) /* {{{ */ { - size_t index_len, web_len; + const char *php_index; + const char *web_index; + size_t php_len, web_len; if (error) { *error = NULL; } - if (!index_php) { - index_php = "index.php"; - } - - if (!web_index) { - web_index = "index.php"; - } - - index_len = strlen(index_php); - web_len = strlen(web_index); - - if (index_len > 400) { - /* ridiculous size not allowed for index.php startup filename */ - if (error) { - spprintf(error, 0, "Illegal filename passed in for stub creation, was %zd characters long, and only 400 or less is allowed", index_len); + if (!php_index_str) { + php_index = "index.php"; + php_len = strlen("index.php"); + } else { + php_index = ZSTR_VAL(php_index_str); + php_len = ZSTR_LEN(php_index_str); + if (php_len > 400) { + /* ridiculous size not allowed for index.php startup filename */ + if (error) { + spprintf(error, 0, "Illegal filename passed in for stub creation, was %zd characters long, and only 400 or less is allowed", php_len); + } return NULL; } } - if (web_len > 400) { - /* ridiculous size not allowed for index.php startup filename */ - if (error) { - spprintf(error, 0, "Illegal web filename passed in for stub creation, was %zd characters long, and only 400 or less is allowed", web_len); + if (!web_index_str) { + web_index = "index.php"; + web_len = strlen("index.php"); + } else { + web_index = ZSTR_VAL(web_index_str); + web_len = ZSTR_LEN(web_index_str); + + if (web_len > 400) { + /* ridiculous size not allowed for index.php startup filename */ + if (error) { + spprintf(error, 0, "Illegal web filename passed in for stub creation, was %zd characters long, and only 400 or less is allowed", web_len); + } return NULL; } } - return phar_get_stub(index_php, web_index, index_len+1, web_len+1); + return phar_get_stub(php_index, web_index, php_len+1, web_len+1); } /* }}} */ diff --git a/ext/phar/phar_internal.h b/ext/phar/phar_internal.h index 232ba579d7f0b..bd3d7158c8e82 100644 --- a/ext/phar/phar_internal.h +++ b/ext/phar/phar_internal.h @@ -415,7 +415,7 @@ zend_result phar_verify_signature(php_stream *fp, size_t end_of_phar, uint32_t s ZEND_ATTRIBUTE_NONNULL zend_result phar_create_signature(phar_archive_data *phar, php_stream *fp, char **signature, size_t *signature_length, char **error); /* utility functions */ -zend_string *phar_create_default_stub(const char *index_php, const char *web_index, char **error); +zend_string *phar_create_default_stub(const zend_string *php_index_str, const zend_string *web_index_str, char **error); const char *phar_decompress_filter(const phar_entry_info *entry, bool return_unknown); const char *phar_compress_filter(const phar_entry_info *entry, bool return_unknown); diff --git a/ext/phar/phar_object.c b/ext/phar/phar_object.c index e1c18cd4bac63..58c6140451880 100644 --- a/ext/phar/phar_object.c +++ b/ext/phar/phar_object.c @@ -946,11 +946,11 @@ PHP_METHOD(Phar, interceptFileFuncs) */ PHP_METHOD(Phar, createDefaultStub) { - char *index = NULL, *webindex = NULL, *error; + zend_string *index = NULL, *webindex = NULL; + char *error; zend_string *stub; - size_t index_len = 0, webindex_len = 0; - if (zend_parse_parameters(ZEND_NUM_ARGS(), "|p!p!", &index, &index_len, &webindex, &webindex_len) == FAILURE) { + if (zend_parse_parameters(ZEND_NUM_ARGS(), "|P!P!", &index, &webindex) == FAILURE) { RETURN_THROWS(); } @@ -2914,12 +2914,11 @@ PHP_METHOD(Phar, setStub) */ PHP_METHOD(Phar, setDefaultStub) { - char *index = NULL, *webindex = NULL, *error = NULL; + zend_string *index = NULL, *webindex = NULL; zend_string *stub = NULL; - size_t index_len = 0, webindex_len = 0; bool created_stub = false; - if (zend_parse_parameters(ZEND_NUM_ARGS(), "|s!s!", &index, &index_len, &webindex, &webindex_len) == FAILURE) { + if (zend_parse_parameters(ZEND_NUM_ARGS(), "|P!P!", &index, &webindex) == FAILURE) { RETURN_THROWS(); } @@ -2947,6 +2946,7 @@ PHP_METHOD(Phar, setDefaultStub) RETURN_THROWS(); } + char *error = NULL; if (!phar_obj->archive->is_tar && !phar_obj->archive->is_zip) { stub = phar_create_default_stub(index, webindex, &error); From ad9c60f995c3f9ff088398d73971c39a926022f8 Mon Sep 17 00:00:00 2001 From: Gina Peter Banyard Date: Thu, 16 Oct 2025 01:33:09 +0100 Subject: [PATCH 10/14] ext/phar: start refactoring phar_postprocess_ru_web() --- ext/phar/phar_object.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/ext/phar/phar_object.c b/ext/phar/phar_object.c index 58c6140451880..6981d7c026d13 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, *u = NULL, *u1 = NULL, *saveu = NULL; + const char *e = entry + 1; + char *u = NULL, *u1 = NULL, *saveu = NULL; size_t e_len = *entry_len - 1, u_len = 0; phar_archive_data *pphar; @@ -746,7 +747,7 @@ PHP_METHOD(Phar, webPhar) } if (entry_len) { - phar_postprocess_ru_web(fname, fname_len, &entry, &entry_len, &ru, &ru_len); + phar_postprocess_ru_web(fname, fname_len, entry, &entry_len, &ru, &ru_len); } if (!entry_len || (entry_len == 1 && entry[0] == '/')) { From 94284df7b23dcc8663828c269de23c28ca03fcae Mon Sep 17 00:00:00 2001 From: Niels Dossche <7771979+nielsdos@users.noreply.github.com> Date: Sun, 12 Oct 2025 00:40:28 +0200 Subject: [PATCH 11/14] Fix GH-20122: getColumnMeta() for JSON-column in MySQL While at it, also add VECTOR. Closes GH-20143. --- NEWS | 1 + .../tests/mysqli_fetch_field_types.phpt | 1 + ext/pdo_mysql/mysql_statement.c | 6 ++++ ext/pdo_mysql/tests/gh20122.phpt | 33 +++++++++++++++++++ 4 files changed, 41 insertions(+) create mode 100644 ext/pdo_mysql/tests/gh20122.phpt diff --git a/NEWS b/NEWS index 265cbcea11403..057d26c7d52e3 100644 --- a/NEWS +++ b/NEWS @@ -29,6 +29,7 @@ PHP NEWS - MySQLnd: . Fixed bug GH-8978 (SSL certificate verification fails (port doubled)). (nielsdos) + . Fixed bug GH-20122 (getColumnMeta() for JSON-column in MySQL). (nielsdos) - Opcache: . Fixed bug GH-20081 (access to uninitialized vars in preload_load()). diff --git a/ext/mysqli/tests/mysqli_fetch_field_types.phpt b/ext/mysqli/tests/mysqli_fetch_field_types.phpt index 041eb16694a7c..3f58987b3d95a 100644 --- a/ext/mysqli/tests/mysqli_fetch_field_types.phpt +++ b/ext/mysqli/tests/mysqli_fetch_field_types.phpt @@ -94,6 +94,7 @@ require_once 'skipifconnectfailure.inc'; MYSQLI_TYPE_NEWDATE => 'MYSQLI_TYPE_NEWDATE - TODO add testing', MYSQLI_TYPE_INTERVAL => 'MYSQLI_TYPE_INTERVAL - TODO add testing', MYSQLI_TYPE_GEOMETRY => 'MYSQLI_TYPE_GEOMETRY - TODO add testing', + MYSQLI_TYPE_JSON => array('JSON', '[]'), ); $datatypes[MYSQLI_TYPE_NEWDECIMAL] = array('DECIMAL', '1.1'); diff --git a/ext/pdo_mysql/mysql_statement.c b/ext/pdo_mysql/mysql_statement.c index c4f86b0e7d320..b3dc527b10919 100644 --- a/ext/pdo_mysql/mysql_statement.c +++ b/ext/pdo_mysql/mysql_statement.c @@ -748,6 +748,12 @@ static char *type_to_name_native(int type) /* {{{ */ PDO_MYSQL_NATIVE_TYPE_NAME(DATE) #ifdef FIELD_TYPE_NEWDATE PDO_MYSQL_NATIVE_TYPE_NAME(NEWDATE) +#endif +#ifdef FIELD_TYPE_VECTOR + PDO_MYSQL_NATIVE_TYPE_NAME(VECTOR) +#endif +#ifdef FIELD_TYPE_JSON + PDO_MYSQL_NATIVE_TYPE_NAME(JSON) #endif PDO_MYSQL_NATIVE_TYPE_NAME(TIME) PDO_MYSQL_NATIVE_TYPE_NAME(DATETIME) diff --git a/ext/pdo_mysql/tests/gh20122.phpt b/ext/pdo_mysql/tests/gh20122.phpt new file mode 100644 index 0000000000000..28369fefaf63a --- /dev/null +++ b/ext/pdo_mysql/tests/gh20122.phpt @@ -0,0 +1,33 @@ +--TEST-- +GH-20122 (getColumnMeta() for JSON-column in MySQL) +--EXTENSIONS-- +pdo +pdo_mysql +--SKIPIF-- + +--FILE-- +exec('CREATE TABLE test (bar JSON)'); +$db->exec('INSERT INTO test VALUES("[]")'); + +$stmt = $db->query('SELECT * from test'); +$meta = $stmt->getColumnMeta(0); + +// Note: JSON is an alias for LONGTEXT on MariaDB! +echo $meta['native_type'], "\n"; +?> +--CLEAN-- + +--EXPECTF-- +%r(JSON|LONGTEXT)%r From fbac7a366fc9607e715b53b37bf9287278d79612 Mon Sep 17 00:00:00 2001 From: Niels Dossche <7771979+nielsdos@users.noreply.github.com> Date: Thu, 16 Oct 2025 23:01:41 +0200 Subject: [PATCH 12/14] phar: Get rid of bailouts in Phar::webPhar() (#20190) Bailouts are bad because they stop the GC etc. They also hide leaks. This makes the behaviour equivalent to exit(), as it's meant to stop the request (which is why bailout was used). We also have to fix some leaks that pop up then. --- ext/phar/phar_object.c | 45 +++++++++++++++++++++++++++--------------- 1 file changed, 29 insertions(+), 16 deletions(-) diff --git a/ext/phar/phar_object.c b/ext/phar/phar_object.c index 6981d7c026d13..6238e51c7d5cb 100644 --- a/ext/phar/phar_object.c +++ b/ext/phar/phar_object.c @@ -699,6 +699,7 @@ PHP_METHOD(Phar, webPhar) zval params, retval; ZVAL_STRINGL(¶ms, entry, entry_len); + efree(entry); rewrite_fci.param_count = 1; rewrite_fci.params = ¶ms; @@ -716,9 +717,10 @@ PHP_METHOD(Phar, webPhar) switch (Z_TYPE(retval)) { case IS_STRING: - efree(entry); + /* TODO: avoid relocation??? */ entry = estrndup(Z_STRVAL_P(rewrite_fci.retval), Z_STRLEN_P(rewrite_fci.retval)); entry_len = Z_STRLEN_P(rewrite_fci.retval); + zval_ptr_dtor_str(&retval); break; case IS_TRUE: case IS_FALSE: @@ -729,15 +731,16 @@ PHP_METHOD(Phar, webPhar) } efree(pt); - zend_bailout(); + zend_throw_unwind_exit(); + return; default: + zval_ptr_dtor(&retval); zend_throw_exception_ex(phar_ce_PharException, 0, "phar error: rewrite callback must return a string or false"); cleanup_fail: if (free_pathinfo) { efree(path_info); } - efree(entry); efree(pt); #ifdef PHP_WIN32 efree(fname); @@ -752,6 +755,10 @@ PHP_METHOD(Phar, webPhar) if (!entry_len || (entry_len == 1 && entry[0] == '/')) { efree(entry); + efree(pt); + + bool is_entry_allocated = false; + /* direct request */ if (index_php_len) { entry = index_php; @@ -759,22 +766,17 @@ PHP_METHOD(Phar, webPhar) if (entry[0] != '/') { spprintf(&entry, 0, "/%s", index_php); ++entry_len; + is_entry_allocated = true; } } else { /* assume "index.php" is starting point */ - entry = estrndup("/index.php", sizeof("/index.php")); + entry = "/index.php"; 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_do_404(phar, fname, fname_len, f404); - - if (free_pathinfo) { - efree(path_info); - } - - zend_bailout(); } else { char *tmp = NULL, sa = '\0'; sapi_header_line ctr = {0}; @@ -801,21 +803,32 @@ PHP_METHOD(Phar, webPhar) *tmp = sa; } - if (free_pathinfo) { - efree(path_info); - } - sapi_header_op(SAPI_HEADER_REPLACE, &ctr); sapi_send_headers(); efree((void *) ctr.line); - zend_bailout(); } + + if (is_entry_allocated) { + efree(entry); + } + if (free_pathinfo) { + efree(path_info); + } + + zend_throw_unwind_exit(); + return; } if (FAILURE == phar_get_archive(&phar, fname, fname_len, NULL, 0, NULL) || (info = phar_get_entry_info(phar, entry, entry_len, NULL, false)) == NULL) { + efree(entry); + efree(pt); + if (free_pathinfo) { + efree(path_info); + } phar_do_404(phar, fname, fname_len, f404); - zend_bailout(); + zend_throw_unwind_exit(); + return; } if (mimeoverride && zend_hash_num_elements(Z_ARRVAL_P(mimeoverride))) { From 1570f6a6b22b19910c3544fa37ef5f9773238ad4 Mon Sep 17 00:00:00 2001 From: Niels Dossche <7771979+nielsdos@users.noreply.github.com> Date: Thu, 16 Oct 2025 23:54:02 +0200 Subject: [PATCH 13/14] Fix test on 8.4+ --- ext/pdo_mysql/tests/gh20122.phpt | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/ext/pdo_mysql/tests/gh20122.phpt b/ext/pdo_mysql/tests/gh20122.phpt index 28369fefaf63a..925c94e907a00 100644 --- a/ext/pdo_mysql/tests/gh20122.phpt +++ b/ext/pdo_mysql/tests/gh20122.phpt @@ -5,15 +5,13 @@ pdo pdo_mysql --SKIPIF-- --FILE-- exec('CREATE TABLE test (bar JSON)'); $db->exec('INSERT INTO test VALUES("[]")'); From 6980d51f52fdaaf926cec5ae8bc17da317f20fbb Mon Sep 17 00:00:00 2001 From: Niels Dossche <7771979+nielsdos@users.noreply.github.com> Date: Fri, 17 Oct 2025 00:10:02 +0200 Subject: [PATCH 14/14] [ci skip] Fail test temporarily --- ext/pdo_mysql/tests/gh20122.phpt | 1 + 1 file changed, 1 insertion(+) diff --git a/ext/pdo_mysql/tests/gh20122.phpt b/ext/pdo_mysql/tests/gh20122.phpt index 925c94e907a00..fb3bd70a7e7f5 100644 --- a/ext/pdo_mysql/tests/gh20122.phpt +++ b/ext/pdo_mysql/tests/gh20122.phpt @@ -8,6 +8,7 @@ pdo_mysql require_once __DIR__ . '/inc/mysql_pdo_test.inc'; MySQLPDOTest::skip(); ?> +--XFAIL-- --FILE--