From ade8e2d8cde8ffa6637aebc506d5523606613aaa Mon Sep 17 00:00:00 2001 From: Niels Dossche <7771979+nielsdos@users.noreply.github.com> Date: Fri, 17 Oct 2025 08:09:42 +0200 Subject: [PATCH 1/3] phar: Drop buggy redundant Windows-only check (#20195) If the path contains '\' the path is duplicated and unixified. In practice this is always true. And if it were not, we'd get a heap corruption as the cleanup code assumes it is. --- ext/phar/phar_object.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/ext/phar/phar_object.c b/ext/phar/phar_object.c index 6238e51c7d5c..adec61126697 100644 --- a/ext/phar/phar_object.c +++ b/ext/phar/phar_object.c @@ -609,10 +609,8 @@ PHP_METHOD(Phar, webPhar) fname_len = ZSTR_LEN(zend_file_name); #ifdef PHP_WIN32 - if (memchr(fname, '\\', fname_len)) { - fname = estrndup(fname, fname_len); - phar_unixify_path_separators(fname, fname_len); - } + fname = estrndup(fname, fname_len); + phar_unixify_path_separators(fname, fname_len); #endif basename = zend_memrchr(fname, '/', fname_len); From 3ee2f442d2052d2bba226ce93632daa950cc0955 Mon Sep 17 00:00:00 2001 From: Niels Dossche <7771979+nielsdos@users.noreply.github.com> Date: Fri, 17 Oct 2025 08:12:25 +0200 Subject: [PATCH 2/3] phar: Get rid of last bailouts in phar_file_action() (#20193) * phar: Get rid of last bailouts in phar_file_action() Follow-up on GH-20190. * [ci skip] Drop wrong comment --- ext/phar/phar_object.c | 102 ++++++++++++++++------------------------- 1 file changed, 39 insertions(+), 63 deletions(-) diff --git a/ext/phar/phar_object.c b/ext/phar/phar_object.c index adec61126697..31b9261ba137 100644 --- a/ext/phar/phar_object.c +++ b/ext/phar/phar_object.c @@ -151,7 +151,12 @@ static void phar_mung_server_vars(char *fname, char *entry, size_t entry_len, co } /* }}} */ -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) /* {{{ */ +typedef enum { + PHAR_ACT_DO_EXIT, + PHAR_ACT_GRACEFULLY_RETURN, +} phar_action_status; + +static phar_action_status 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; @@ -182,7 +187,7 @@ static int phar_file_action(phar_archive_data *phar, phar_entry_info *info, char #ifdef PHP_WIN32 efree(arch); #endif - zend_bailout(); + return PHAR_ACT_DO_EXIT; case PHAR_MIME_OTHER: /* send headers, output file contents */ ctr.line_len = spprintf((char **) &(ctr.line), 0, "Content-type: %s", mime_type); @@ -193,7 +198,7 @@ static int phar_file_action(phar_archive_data *phar, phar_entry_info *info, char efree((void *) ctr.line); if (FAILURE == sapi_send_headers()) { - zend_bailout(); + return PHAR_ACT_DO_EXIT; } /* prepare to output */ @@ -206,7 +211,7 @@ static int phar_file_action(phar_archive_data *phar, phar_entry_info *info, char zend_throw_exception_ex(phar_ce_PharException, 0, "%s", error); efree(error); } - return -1; + return PHAR_ACT_GRACEFULLY_RETURN; } fp = phar_get_efp(info, true); } @@ -224,7 +229,7 @@ static int phar_file_action(phar_archive_data *phar, phar_entry_info *info, char } } while (1); - zend_bailout(); + return PHAR_ACT_DO_EXIT; case PHAR_MIME_PHP: if (basename) { phar_mung_server_vars(arch, entry, entry_len, basename, ru_len); @@ -299,12 +304,11 @@ static int phar_file_action(phar_archive_data *phar, phar_entry_info *info, char efree(name); } zend_end_try(); - zend_bailout(); + return PHAR_ACT_DO_EXIT; } - - return PHAR_MIME_PHP; } - return -1; + + return PHAR_ACT_GRACEFULLY_RETURN; } /* }}} */ @@ -331,6 +335,7 @@ static void phar_do_404(phar_archive_data *phar, char *fname, size_t fname_len, info = phar_get_entry_info(phar, ZSTR_VAL(f404), ZSTR_LEN(f404), NULL, true); if (info) { + /* Status doesn't matter, we're exiting anyway. */ phar_file_action(phar, info, "text/html", PHAR_MIME_PHP, ZSTR_VAL(f404), ZSTR_LEN(f404), fname, NULL, NULL, 0); return; } @@ -569,6 +574,7 @@ PHP_METHOD(Phar, webPhar) phar_archive_data *phar = NULL; phar_entry_info *info = NULL; size_t sapi_mod_name_len = strlen(sapi_module.name); + phar_action_status status = PHAR_ACT_DO_EXIT; 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(); @@ -652,9 +658,7 @@ PHP_METHOD(Phar, webPhar) pt = estrndup(Z_STRVAL_P(z_script_name), Z_STRLEN_P(z_script_name)); } else { - char *testit; - - testit = sapi_getenv("SCRIPT_NAME", sizeof("SCRIPT_NAME")-1); + char *testit = sapi_getenv("SCRIPT_NAME", sizeof("SCRIPT_NAME")-1); if (!(pt = strstr(testit, basename))) { efree(testit); goto finish; @@ -675,6 +679,7 @@ PHP_METHOD(Phar, webPhar) } pt = estrndup(testit, (pt - testit) + (fname_len - (basename - fname))); + efree(testit); } not_cgi = 0; } else { @@ -708,7 +713,7 @@ PHP_METHOD(Phar, webPhar) if (!EG(exception)) { zend_throw_exception_ex(phar_ce_PharException, 0, "phar error: failed to call rewrite callback"); } - goto cleanup_fail; + goto cleanup_skip_entry; } zval_ptr_dtor_str(¶ms); @@ -723,27 +728,11 @@ PHP_METHOD(Phar, webPhar) case IS_TRUE: case IS_FALSE: phar_do_403(); - - if (free_pathinfo) { - efree(path_info); - } - efree(pt); - - zend_throw_unwind_exit(); - return; + goto cleanup_skip_entry; 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(pt); -#ifdef PHP_WIN32 - efree(fname); -#endif - RETURN_THROWS(); + goto cleanup_skip_entry; } } @@ -753,7 +742,6 @@ PHP_METHOD(Phar, webPhar) if (!entry_len || (entry_len == 1 && entry[0] == '/')) { efree(entry); - efree(pt); bool is_entry_allocated = false; @@ -809,24 +797,14 @@ PHP_METHOD(Phar, webPhar) if (is_entry_allocated) { efree(entry); } - if (free_pathinfo) { - efree(path_info); - } - zend_throw_unwind_exit(); - return; + goto cleanup_skip_entry; } if (FAILURE == phar_get_archive(&phar, fname, fname_len, NULL, 0, NULL) || (info = phar_get_entry_info(phar, entry, entry_len, NULL, false)) == NULL) { - efree(entry); - efree(pt); - if (free_pathinfo) { - efree(path_info); - } phar_do_404(phar, fname, fname_len, f404); - zend_throw_unwind_exit(); - return; + goto cleanup; } if (mimeoverride && zend_hash_num_elements(Z_ARRVAL_P(mimeoverride))) { @@ -844,15 +822,7 @@ PHP_METHOD(Phar, webPhar) code = Z_LVAL_P(val); } else { zend_throw_exception_ex(phar_ce_PharException, 0, "Unknown mime type specifier used, only Phar::PHP, Phar::PHPS and a mime type string are allowed"); - if (free_pathinfo) { - efree(path_info); - } - efree(pt); - efree(entry); -#ifdef PHP_WIN32 - efree(fname); -#endif - RETURN_THROWS(); + goto cleanup; } break; case IS_STRING: @@ -861,15 +831,7 @@ PHP_METHOD(Phar, webPhar) break; default: zend_throw_exception_ex(phar_ce_PharException, 0, "Unknown mime type specifier used (not a string or int), only Phar::PHP, Phar::PHPS and a mime type string are allowed"); - if (free_pathinfo) { - efree(path_info); - } - efree(pt); - efree(entry); -#ifdef PHP_WIN32 - efree(fname); -#endif - RETURN_THROWS(); + goto cleanup; } } } @@ -878,8 +840,22 @@ PHP_METHOD(Phar, webPhar) if (!mime_type) { 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); + status = phar_file_action(phar, info, mime_type, code, entry, entry_len, fname, pt, ru, ru_len); + +cleanup: + efree(entry); +cleanup_skip_entry: + if (free_pathinfo) { + efree(path_info); + } efree(pt); + efree(ru); + + if (status == PHAR_ACT_DO_EXIT) { + if (!EG(exception)) { + zend_throw_unwind_exit(); + } + } finish: ; #ifdef PHP_WIN32 From a576a3d5d422a6f9b71f95c299a3a575e107a5a4 Mon Sep 17 00:00:00 2001 From: Niels Dossche <7771979+nielsdos@users.noreply.github.com> Date: Fri, 17 Oct 2025 09:12:10 +0200 Subject: [PATCH 3/3] Fix test on 8.4+ (#20196) * Fix test on 8.4+ * more fixes * Fix include path --- ext/pdo_mysql/tests/gh20122.phpt | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/ext/pdo_mysql/tests/gh20122.phpt b/ext/pdo_mysql/tests/gh20122.phpt index fb3bd70a7e7f..f4abc266335a 100644 --- a/ext/pdo_mysql/tests/gh20122.phpt +++ b/ext/pdo_mysql/tests/gh20122.phpt @@ -8,16 +8,15 @@ pdo_mysql require_once __DIR__ . '/inc/mysql_pdo_test.inc'; MySQLPDOTest::skip(); ?> ---XFAIL-- --FILE-- exec('CREATE TABLE test (bar JSON)'); -$db->exec('INSERT INTO test VALUES("[]")'); +$db->exec('CREATE TABLE test_gh20122 (bar JSON)'); +$db->exec('INSERT INTO test_gh20122 VALUES("[]")'); -$stmt = $db->query('SELECT * from test'); +$stmt = $db->query('SELECT * from test_gh20122'); $meta = $stmt->getColumnMeta(0); // Note: JSON is an alias for LONGTEXT on MariaDB! @@ -25,8 +24,9 @@ echo $meta['native_type'], "\n"; ?> --CLEAN-- query('DROP TABLE IF EXISTS test_gh20122'); ?> --EXPECTF-- %r(JSON|LONGTEXT)%r