Skip to content

phpize: fix silently stale build files when the PHP install is read-only - #23570

Open
GromNaN wants to merge 2 commits into
php:masterfrom
GromNaN:phpize-cp-force
Open

phpize: fix silently stale build files when the PHP install is read-only#23570
GromNaN wants to merge 2 commits into
php:masterfrom
GromNaN:phpize-cp-force

Conversation

@GromNaN

@GromNaN GromNaN commented Sep 4, 2026

Copy link
Copy Markdown
Member

phpize_copy_files() copies build/* and run-tests.php from the PHP installation into the extension directory using plain cp.

Homebrew installs those files read-only, mode 444 and 555. On the first phpize run the destination is created with the source's mode, so it is read-only too. On every subsequent run in the same extension directory, cp cannot open the destination for writing and fails with "Permission denied". Any installation that makes these files read-only will hit the same thing.

The failure is not detected. Both cp calls run in subshells whose exit status is discarded, phpize_copy_files is called unconditionally, and phpize exits 0. So phpize reports success while leaving the previous run's files in place.

That is the real hazard. The visible error lines are only a symptom; the consequence is that the extension is then configured and built against stale php.m4, Makefile.global and run-tests.php. After upgrading PHP in place, an extension can be configured with the previous PHP's build system without any signal that something went wrong.

Two changes, split so they can be judged separately:

  1. Use cp -f. It unlinks and recreates the destination, so it needs write permission on the directory only, not on the target file. This alone fixes the failure. -f is POSIX.
  2. Append || exit 1 to both subshells so a copy failure aborts phpize instead of continuing with stale files. This matches the style already used by phpize_autotools() just below.

Verified on macOS with Homebrew PHP 8.5.10: the substituted script still passes sh -n, and cp fails while cp -f succeeds against a mode 444 destination.

Many PHP installations, for example Homebrew, Nix and distribution
packages, install lib/php/build/* and run-tests.php read-only. Plain cp
creates the destination with the source mode on the first phpize run. On
later runs in the same project, cp cannot open the read-only destination
for writing and fails with "Permission denied".

cp -f unlinks and recreates the destination, so it only needs write
permission on the directory, not on the target file.
Both cp calls run in subshells with no status check, and
phpize_copy_files is called unconditionally, so phpize exits 0 even when
the copy fails. The extension is then configured with stale files left
over from a previous run. After a PHP upgrade in place, this silently
builds against the previous PHP's php.m4, Makefile.global and
run-tests.php.

Propagate the failure with "|| exit 1", matching the style already used
in phpize_autotools().
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant