From 70e1851a22a2789e99d111b48ceb3710d707419e Mon Sep 17 00:00:00 2001 From: Ilia Alshanetsky Date: Sat, 18 Apr 2026 08:10:44 -0400 Subject: [PATCH 1/3] phar: restore is_link handler in phar_intercept_functions_shutdown phar_intercept_functions_init hooks 22 built-in functions via PHAR_INTERCEPT. phar_intercept_functions_shutdown restores all of them via PHAR_RELEASE except is_link, which was simply missing from the list. On MSHUTDOWN the is_link entry in CG(function_table) retains the phar intercept handler. In a persistent SAPI, if the module is reloaded, the second MINIT saves PHP_FN(phar_is_link) as orig_is_link, and any subsequent is_link() call recurses infinitely. --- ext/phar/func_interceptors.c | 1 + ext/phar/tests/phar-is-link-intercept.phpt | 30 ++++++++++++++++++++++ 2 files changed, 31 insertions(+) create mode 100644 ext/phar/tests/phar-is-link-intercept.phpt diff --git a/ext/phar/func_interceptors.c b/ext/phar/func_interceptors.c index f1b2b0eba1e6..9d83f740d501 100644 --- a/ext/phar/func_interceptors.c +++ b/ext/phar/func_interceptors.c @@ -932,6 +932,7 @@ void phar_intercept_functions_shutdown(void) PHAR_RELEASE(fopen); PHAR_RELEASE(file_get_contents); PHAR_RELEASE(is_file); + PHAR_RELEASE(is_link); PHAR_RELEASE(is_dir); PHAR_RELEASE(opendir); PHAR_RELEASE(file_exists); diff --git a/ext/phar/tests/phar-is-link-intercept.phpt b/ext/phar/tests/phar-is-link-intercept.phpt new file mode 100644 index 000000000000..378e9ef375d1 --- /dev/null +++ b/ext/phar/tests/phar-is-link-intercept.phpt @@ -0,0 +1,30 @@ +--TEST-- +phar: is_link() intercept correctly delegates for non-symlink phar entries +--EXTENSIONS-- +phar +--SKIPIF-- + +--INI-- +phar.readonly=0 +phar.require_hash=0 +--FILE-- +addFromString('file.txt', 'hello'); +$phar->setStub(''); +include $fname; +?> +--CLEAN-- + +--EXPECT-- +bool(false) +bool(false) +bool(false) From 174d77cb4b72de9308c1954c816d98aadcf883ed Mon Sep 17 00:00:00 2001 From: Ilia Alshanetsky Date: Sat, 18 Apr 2026 10:59:39 -0400 Subject: [PATCH 2/3] phar: drop unnecessary SKIPIF from is_link intercept test The test is platform-agnostic: all three assertions expect bool(false) and is_link() on a non-symlink behaves identically on Windows. --- ext/phar/tests/phar-is-link-intercept.phpt | 2 -- 1 file changed, 2 deletions(-) diff --git a/ext/phar/tests/phar-is-link-intercept.phpt b/ext/phar/tests/phar-is-link-intercept.phpt index 378e9ef375d1..480d16bf01c6 100644 --- a/ext/phar/tests/phar-is-link-intercept.phpt +++ b/ext/phar/tests/phar-is-link-intercept.phpt @@ -2,8 +2,6 @@ phar: is_link() intercept correctly delegates for non-symlink phar entries --EXTENSIONS-- phar ---SKIPIF-- - --INI-- phar.readonly=0 phar.require_hash=0 From cb1d62ee2b6b693aa973b235e18dc596d7ac5047 Mon Sep 17 00:00:00 2001 From: Ilia Alshanetsky Date: Sat, 18 Apr 2026 11:30:25 -0400 Subject: [PATCH 3/3] phar: label is_link intercept test assertions in output Replace inline comments with echo prefixes so each var_dump line in the expected output identifies which case it covers -- regular entry, missing entry, absolute phar:// path. --- ext/phar/tests/phar-is-link-intercept.phpt | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/ext/phar/tests/phar-is-link-intercept.phpt b/ext/phar/tests/phar-is-link-intercept.phpt index 480d16bf01c6..f81f1ae425d7 100644 --- a/ext/phar/tests/phar-is-link-intercept.phpt +++ b/ext/phar/tests/phar-is-link-intercept.phpt @@ -12,17 +12,18 @@ $phar = new Phar($fname); $phar->addFromString('file.txt', 'hello'); $phar->setStub(''); include $fname; ?> --CLEAN-- --EXPECT-- -bool(false) -bool(false) -bool(false) +regular entry (not a symlink): bool(false) +missing entry: bool(false) +absolute phar:// path (bypasses intercept): bool(false)