From 4be0d5ecef38789e3e1a5a781505b9d8908d13d7 Mon Sep 17 00:00:00 2001 From: Ilija Tovilo Date: Tue, 17 Feb 2026 17:33:44 +0100 Subject: [PATCH 01/12] [skip ci] Sync nightly.yml with master --- .github/workflows/nightly.yml | 37 +++++++++++------------------------ 1 file changed, 11 insertions(+), 26 deletions(-) diff --git a/.github/workflows/nightly.yml b/.github/workflows/nightly.yml index 20b7e8be56f5..97064ad3972d 100644 --- a/.github/workflows/nightly.yml +++ b/.github/workflows/nightly.yml @@ -11,6 +11,9 @@ on: community_verify_type_inference: required: true type: boolean + macos_arm64_version: + required: true + type: string run_alpine: required: true type: boolean @@ -129,7 +132,6 @@ jobs: jitType: tracing runTestsParameters: >- --asan -x - -d zend_extension=opcache.so -d opcache.enable_cli=1 - name: Extra tests uses: ./.github/actions/extra-tests @@ -240,14 +242,12 @@ jobs: jitType: tracing runTestsParameters: >- ${{ matrix.run_tests_parameters }} - -d zend_extension=opcache.so -d opcache.enable_cli=1 - name: Test OpCache uses: ./.github/actions/test-linux with: runTestsParameters: >- ${{ matrix.run_tests_parameters }} - -d zend_extension=opcache.so -d opcache.enable_cli=1 - name: Test Function JIT # ASAN frequently timeouts. Each test run takes ~90 minutes, we can @@ -258,7 +258,6 @@ jobs: jitType: function runTestsParameters: >- ${{ matrix.run_tests_parameters }} - -d zend_extension=opcache.so -d opcache.enable_cli=1 - name: Extra tests uses: ./.github/actions/extra-tests @@ -329,14 +328,12 @@ jobs: jitType: tracing runTestsParameters: >- ${{ matrix.run_tests_parameters }} - -d zend_extension=opcache.so -d opcache.enable_cli=1 - name: Test OpCache uses: ./.github/actions/test-linux with: runTestsParameters: >- ${{ matrix.run_tests_parameters }} - -d zend_extension=opcache.so -d opcache.enable_cli=1 - name: Test Function JIT uses: ./.github/actions/test-linux @@ -344,7 +341,6 @@ jobs: jitType: function runTestsParameters: >- ${{ matrix.run_tests_parameters }} - -d zend_extension=opcache.so -d opcache.enable_cli=1 - name: Extra tests uses: ./.github/actions/extra-tests @@ -354,11 +350,11 @@ jobs: matrix: debug: [true, false] zts: [true, false] - os: ['13', '14'] + arch: ['X64', 'ARM64'] exclude: - - os: ${{ !inputs.run_macos_arm64 && '14' || '*never*' }} - name: "MACOS_${{ matrix.os == '13' && 'X64' || 'ARM64' }}_${{ matrix.debug && 'DEBUG' || 'RELEASE' }}_${{ matrix.zts && 'ZTS' || 'NTS' }}" - runs-on: macos-${{ matrix.os }} + - arch: ${{ !inputs.run_macos_arm64 && 'ARM64' || '*never*' }} + name: "MACOS_${{ matrix.arch }}_${{ matrix.debug && 'DEBUG' || 'RELEASE' }}_${{ matrix.zts && 'ZTS' || 'NTS' }}" + runs-on: macos-${{ matrix.arch == 'X64' && '15-intel' || inputs.macos_arm64_version }} steps: - name: git checkout uses: actions/checkout@v6 @@ -384,26 +380,23 @@ jobs: - name: Test uses: ./.github/actions/test-macos - name: Test Tracing JIT - if: matrix.os != '14' || !matrix.zts + if: matrix.arch == 'X64' || !matrix.zts uses: ./.github/actions/test-macos with: jitType: tracing runTestsParameters: >- - -d zend_extension=opcache.so -d opcache.enable_cli=1 - name: Test OpCache uses: ./.github/actions/test-macos with: runTestsParameters: >- - -d zend_extension=opcache.so -d opcache.enable_cli=1 - name: Test Function JIT - if: matrix.os != '14' || !matrix.zts + if: matrix.arch == 'X64' || !matrix.zts uses: ./.github/actions/test-macos with: jitType: function runTestsParameters: >- - -d zend_extension=opcache.so -d opcache.enable_cli=1 - name: Extra tests uses: ./.github/actions/extra-tests @@ -462,9 +455,8 @@ jobs: with: jitType: tracing runTestsParameters: >- - -d zend_extension=opcache.so -d opcache.enable_cli=1 - - uses: codecov/codecov-action@v4 + - uses: codecov/codecov-action@v5 if: ${{ !cancelled() }} with: fail_ci_if_error: true @@ -511,7 +503,6 @@ jobs: - name: Enable Opcache run: | echo memory_limit=-1 >> /etc/php.d/opcache.ini - echo zend_extension=opcache.so > /etc/php.d/opcache.ini echo opcache.enable_cli=1 >> /etc/php.d/opcache.ini echo opcache.enable=1 >> /etc/php.d/opcache.ini echo opcache.protect_memory=1 >> /etc/php.d/opcache.ini @@ -708,21 +699,18 @@ jobs: uses: ./.github/actions/test-linux with: runTestsParameters: >- - -d zend_extension=opcache.so -d opcache.enable_cli=1 --file-cache-prime - name: Test File Cache (prime shm, use shm) uses: ./.github/actions/test-linux with: runTestsParameters: >- - -d zend_extension=opcache.so -d opcache.enable_cli=1 --file-cache-use - name: Test File Cache (prime shm, use file) uses: ./.github/actions/test-linux with: runTestsParameters: >- - -d zend_extension=opcache.so -d opcache.enable_cli=1 --file-cache-use -d opcache.file_cache_only=1 @@ -730,7 +718,6 @@ jobs: uses: ./.github/actions/test-linux with: runTestsParameters: >- - -d zend_extension=opcache.so -d opcache.enable_cli=1 --file-cache-prime -d opcache.file_cache_only=1 @@ -738,7 +725,6 @@ jobs: uses: ./.github/actions/test-linux with: runTestsParameters: >- - -d zend_extension=opcache.so -d opcache.enable_cli=1 --file-cache-use -d opcache.file_cache_only=1 @@ -827,7 +813,6 @@ jobs: with: runTestsParameters: >- --msan - -d zend_extension=opcache.so -d opcache.enable_cli=1 - name: Verify generated files are up to date uses: ./.github/actions/verify-generated-files @@ -999,7 +984,7 @@ jobs: PHP_BUILD_CACHE_BASE_DIR: C:\build-cache PHP_BUILD_OBJ_DIR: C:\obj PHP_BUILD_CACHE_SDK_DIR: C:\build-cache\sdk - PHP_BUILD_SDK_BRANCH: php-sdk-2.3.0 + PHP_BUILD_SDK_BRANCH: php-sdk-2.5.0 PHP_BUILD_CRT: ${{ inputs.vs_crt_version }} PLATFORM: ${{ matrix.x64 && 'x64' || 'x86' }} THREAD_SAFE: "${{ matrix.zts && '1' || '0' }}" From f7b58d3938ce0ecd7de2282599ff5771a35a9423 Mon Sep 17 00:00:00 2001 From: Ilija Tovilo Date: Thu, 5 Feb 2026 16:13:50 +0100 Subject: [PATCH 02/12] Unify push & nightly workflows Also introduce label-based opt-in and opt-out mechanism for jobs. Closes GH-21172 --- .github/actions/ccache/action.yml | 13 ++ .github/nightly_matrix.php | 120 +++++++++++- .github/workflows/nightly.yml | 263 ++++++++++---------------- .github/workflows/push.yml | 303 ++++++++++++------------------ .github/workflows/root.yml | 23 +-- 5 files changed, 351 insertions(+), 371 deletions(-) create mode 100644 .github/actions/ccache/action.yml diff --git a/.github/actions/ccache/action.yml b/.github/actions/ccache/action.yml new file mode 100644 index 000000000000..fbd8691c927e --- /dev/null +++ b/.github/actions/ccache/action.yml @@ -0,0 +1,13 @@ +name: ccache +inputs: + name: + required: true +runs: + using: composite + steps: + - name: ccache + uses: hendrikmuhs/ccache-action@v1.2 + with: + key: "${{ inputs.name }}-${{ hashFiles('main/php_version.h') }}" + append-timestamp: false + save: ${{ github.event_name != 'pull_request' }} diff --git a/.github/nightly_matrix.php b/.github/nightly_matrix.php index 0032da7dbcea..8e4e9e7606e2 100644 --- a/.github/nightly_matrix.php +++ b/.github/nightly_matrix.php @@ -46,6 +46,101 @@ function get_current_version(): array { return [$major, $minor]; } +function select_jobs($trigger, $labels, $php_version, $ref, $all_variations) { + $no_jobs = in_array('CI: No jobs', $labels, true); + $all_jobs = in_array('CI: All jobs', $labels, true); + $test_alpine = in_array('CI: Alpine', $labels, true); + $test_community = in_array('CI: Community', $labels, true); + $test_freebsd = in_array('CI: FreeBSD', $labels, true); + $test_libmysqlclient = in_array('CI: libmysqlclient', $labels, true); + $test_linux_ppc64 = in_array('CI: Linux PPC64', $labels, true); + $test_linux_x32 = in_array('CI: Linux X32', $labels, true); + $test_linux_x64 = in_array('CI: Linux X64', $labels, true); + $test_macos = in_array('CI: macOS', $labels, true); + $test_msan = in_array('CI: MSAN', $labels, true); + $test_opcache_variation = in_array('CI: Opcache Variation', $labels, true); + $test_windows = in_array('CI: Windows', $labels, true); + + $jobs = []; + if (version_compare($php_version, '8.4', '>=') && ($all_jobs || !$no_jobs || $test_alpine)) { + $jobs['ALPINE'] = true; + } + if ($all_jobs || $test_community) { + $jobs['COMMUNITY']['matrix'] = version_compare($php_version, '8.4', '>=') + ? ['type' => ['asan', 'verify_type_inference']] + : ['type' => ['asan']]; + $jobs['COMMUNITY']['config']['symfony_version'] = version_compare($php_version, '8.4', '>=') ? '8.1' : '7.4'; + } + if ($trigger === 'schedule' && $ref === 'master') { + $jobs['COVERAGE'] = true; + } + if ($all_jobs || $test_libmysqlclient) { + $jobs['LIBMYSQLCLIENT'] = true; + } + if (version_compare($php_version, '8.4', '>=') && ($all_jobs || $test_linux_ppc64)) { + $jobs['LINUX_PPC64'] = true; + } + if ($all_jobs || !$no_jobs || $test_linux_x64) { + $jobs['LINUX_X64']['matrix'] = $all_variations + ? [ + 'name' => [''], + 'asan' => [false], + 'debug' => [true, false], + 'repeat' => [false], + 'variation' => [false], + 'zts' => [true, false], + 'include' => [ + ['name' => '_ASAN', 'asan' => true, 'debug' => true, 'repeat' => false, 'variation' => false, 'zts' => true], + ['name' => '_REPEAT', 'asan' => false, 'debug' => true, 'repeat' => true, 'variation' => false, 'zts' => false], + ['name' => '_VARIATION', 'asan' => false, 'debug' => true, 'repeat' => false, 'variation' => true, 'zts' => true], + ], + ] + : ['include' => [ + ['name' => '', 'asan' => false, 'debug' => false, 'repeat' => false, 'variation' => false, 'zts' => false], + ['name' => '_ASAN', 'asan' => true, 'debug' => true, 'repeat' => false, 'variation' => false, 'zts' => true], + ]]; + $jobs['LINUX_X64']['config']['variation_enable_zend_max_execution_timers'] = version_compare($php_version, '8.3', '>='); + } + if ($all_jobs || !$no_jobs || $test_linux_x32) { + $jobs['LINUX_X32']['matrix'] = $all_variations + ? ['debug' => [true, false], 'zts' => [true, false]] + : ['debug' => [true], 'zts' => [true]]; + } + if ($all_jobs || !$no_jobs || $test_macos) { + $test_arm = version_compare($php_version, '8.4', '>='); + $jobs['MACOS']['matrix'] = $all_variations + ? ['arch' => $test_arm ? ['X64', 'ARM64'] : ['X64'], 'debug' => [true, false], 'zts' => [true, false]] + : ['include' => [['arch' => $test_arm ? 'ARM64' : 'X64', 'debug' => true, 'zts' => false]]]; + $jobs['MACOS']['config']['arm64_version'] = version_compare($php_version, '8.4', '>=') ? '15' : '14'; + } + if ($all_jobs || $test_msan) { + $jobs['MSAN'] = true; + } + if ($all_jobs || $test_opcache_variation) { + $jobs['OPCACHE_VARIATION'] = true; + } + if ($trigger === 'schedule' && $ref === 'master') { + $jobs['PECL'] = true; + } + if ($all_jobs || !$no_jobs || $test_windows) { + $jobs['WINDOWS']['matrix'] = $all_variations + ? ['include' => [ + ['asan' => true, 'opcache' => true, 'x64' => true, 'zts' => true], + ['asan' => false, 'opcache' => false, 'x64' => false, 'zts' => false], + ]] + : ['include' => [['asan' => false, 'opcache' => true, 'x64' => true, 'zts' => true]]]; + $jobs['WINDOWS']['config'] = version_compare($php_version, '8.4', '>=') + ? ['vs_crt_version' => 'vs17'] + : ['vs_crt_version' => 'vs16']; + } + if ($all_jobs || !$no_jobs || $test_freebsd) { + $jobs['FREEBSD']['matrix'] = $all_variations && version_compare($php_version, '8.3', '>=') + ? ['zts' => [true, false]] + : ['zts' => [false]]; + } + return $jobs; +} + $trigger = $argv[1] ?? 'schedule'; $attempt = (int) ($argv[2] ?? 1); $sunday = date('w', time()) === '0'; @@ -60,6 +155,25 @@ function get_current_version(): array { ? get_branches() : [['ref' => $branch, 'version' => get_current_version()]]; -$f = fopen(getenv('GITHUB_OUTPUT'), 'a'); -fwrite($f, 'branches=' . json_encode($branches, JSON_UNESCAPED_SLASHES) . "\n"); -fclose($f); +$labels = json_decode($argv[4] ?? '[]', true); +$labels = array_column($labels, 'name'); +$all_variations = $trigger === 'schedule' || $trigger === 'workflow_dispatch' || in_array('CI: All variations', $labels, true); + +foreach ($branches as &$branch) { + $php_version = $branch['version'][0] . '.' . $branch['version'][1]; + $branch['jobs'] = select_jobs($trigger, $labels, $php_version, $branch['ref'], $all_variations); + $branch['config']['ubuntu_version'] = version_compare($php_version, '8.5', '>=') ? '24.04' : '22.04'; +} + +echo "All variations:"; +echo json_encode($all_variations, JSON_UNESCAPED_SLASHES|JSON_PRETTY_PRINT); +echo "\n\nBranches:\n"; +echo json_encode($branches, JSON_UNESCAPED_SLASHES|JSON_PRETTY_PRINT); +echo "\n"; + +if (false !== ($github_output = getenv('GITHUB_OUTPUT'))) { + $f = fopen($github_output, 'a'); + fwrite($f, 'branches=' . json_encode($branches, JSON_UNESCAPED_SLASHES) . "\n"); + fwrite($f, 'all_variations=' . json_encode($all_variations, JSON_UNESCAPED_SLASHES) . "\n"); + fclose($f); +} diff --git a/.github/workflows/nightly.yml b/.github/workflows/nightly.yml index 97064ad3972d..f0f93b5a40a1 100644 --- a/.github/workflows/nightly.yml +++ b/.github/workflows/nightly.yml @@ -2,64 +2,25 @@ name: Test suite on: workflow_call: inputs: - asan_ubuntu_version: - required: true - type: string - branch: - required: true - type: string - community_verify_type_inference: - required: true - type: boolean - macos_arm64_version: - required: true - type: string - run_alpine: - required: true - type: boolean - run_linux_ppc64: - required: true - type: boolean - run_macos_arm64: - required: true - type: boolean - run_freebsd_zts: - required: true - type: boolean - ubuntu_version: - required: true - type: string - windows_version: - required: true - type: string - vs_crt_version: - required: true - type: string - skip_laravel: + all_variations: required: true type: boolean - symfony_version: + branch: required: true type: string - skip_wordpress: - required: true - type: boolean - variation_enable_zend_max_execution_timers: - required: true - type: boolean permissions: contents: read jobs: LINUX_PPC64: - if: inputs.run_linux_ppc64 - name: LINUX_PPC64_ASAN_UBSAN_DEBUG_ZTS + if: ${{ fromJson(inputs.branch).jobs.LINUX_PPC64 }} + name: LINUX_PPC64_ASAN_DEBUG_ZTS # This runs on a self-hosted runner; see https://wiki.php.net/systems/ci runs-on: [self-hosted, gentoo, ppc64] steps: - name: git checkout uses: actions/checkout@v6 with: - ref: ${{ inputs.branch }} + ref: ${{ fromJson(inputs.branch).ref }} - name: System info run: | echo "::group::Show host CPU info" @@ -91,8 +52,8 @@ jobs: - name: Extra tests uses: ./.github/actions/extra-tests ALPINE: - if: inputs.run_alpine - name: ALPINE_X64_ASAN_UBSAN_DEBUG_ZTS + if: ${{ fromJson(inputs.branch).jobs.ALPINE }} + name: ALPINE_X64_ASAN_DEBUG_ZTS runs-on: ubuntu-24.04 container: image: 'alpine:3.22' @@ -100,7 +61,7 @@ jobs: - name: git checkout uses: actions/checkout@v6 with: - ref: ${{ inputs.branch }} + ref: ${{ fromJson(inputs.branch).ref }} - name: apk uses: ./.github/actions/apk - name: System info @@ -136,6 +97,7 @@ jobs: - name: Extra tests uses: ./.github/actions/extra-tests LINUX_X64: + if: ${{ fromJson(inputs.branch).jobs.LINUX_X64 }} services: mysql: image: mysql:8.4 @@ -161,47 +123,14 @@ jobs: FIREBIRD_PASSWORD: test strategy: fail-fast: false - matrix: - configuration_parameters: [''] - debug: [true, false] - name: [''] - run_tests_parameters: [''] - test_function_jit: [true] - zts: [true, false] - include: - - name: _ASAN_UBSAN - debug: true - zts: true - configuration_parameters: >- - CFLAGS="-fsanitize=undefined,address -DZEND_TRACK_ARENA_ALLOC" - LDFLAGS="-fsanitize=undefined,address" - run_tests_parameters: '--asan' - test_function_jit: false - asan: true - - name: _REPEAT - debug: true - zts: false - run_tests_parameters: --repeat 2 - timeout_minutes: 360 - test_function_jit: true - asan: false - - name: _VARIATION - debug: true - zts: true - configuration_parameters: >- - CFLAGS="-DZEND_RC_DEBUG=1 -DPROFITABILITY_CHECKS=0 -DZEND_VERIFY_FUNC_INFO=1 -DZEND_VERIFY_TYPE_INFERENCE" - ${{ inputs.variation_enable_zend_max_execution_timers && '--enable-zend-max-execution-timers' || '' }} - run_tests_parameters: -d zend_test.observer.enabled=1 -d zend_test.observer.show_output=0 - timeout_minutes: 360 - test_function_jit: true - asan: false + matrix: ${{ fromJson(inputs.branch).jobs.LINUX_X64.matrix }} name: "LINUX_X64${{ matrix.name }}_${{ matrix.debug && 'DEBUG' || 'RELEASE' }}_${{ matrix.zts && 'ZTS' || 'NTS' }}" - runs-on: ubuntu-${{ matrix.asan && inputs.asan_ubuntu_version || inputs.ubuntu_version }} + runs-on: ubuntu-${{ fromJson(inputs.branch).config.ubuntu_version }} steps: - name: git checkout uses: actions/checkout@v6 with: - ref: ${{ inputs.branch }} + ref: ${{ fromJson(inputs.branch).ref }} - name: Create MSSQL container uses: ./.github/actions/setup-mssql - name: apt @@ -216,64 +145,90 @@ jobs: echo "::group::Show installed package versions" dpkg -l echo "::endgroup::" + - name: Setup Caddy server + uses: ./.github/actions/setup-caddy + - name: ccache + uses: ./.github/actions/ccache + with: + # This duplicates the "job.name" expression above because + # GitHub has no way to query the job name (github.job is the + # job id, not the job name) + name: "LINUX_X64${{ matrix.name }}_${{ matrix.debug && 'DEBUG' || 'RELEASE' }}_${{ matrix.zts && 'ZTS' || 'NTS' }}" - name: ./configure uses: ./.github/actions/configure-x64 with: configurationParameters: >- - ${{ matrix.configuration_parameters }} + ${{ matrix.asan && 'CFLAGS="-fsanitize=undefined,address -DZEND_TRACK_ARENA_ALLOC" LDFLAGS="-fsanitize=undefined,address"' || '' }} + ${{ matrix.variation && 'CFLAGS="-DZEND_RC_DEBUG=1 -DPROFITABILITY_CHECKS=0 -DZEND_VERIFY_FUNC_INFO=1 -DZEND_VERIFY_TYPE_INFERENCE"' || '' }} + ${{ (matrix.variation && fromJson(inputs.branch).jobs.LINUX_X64.config.variation_enable_zend_max_execution_timers) && '--enable-zend-max-execution-timers' || '' }} --${{ matrix.debug && 'enable' || 'disable' }}-debug + ${{ matrix.debug && 'CXXFLAGS="-D_GLIBCXX_ASSERTIONS"' || '' }} --${{ matrix.zts && 'enable' || 'disable' }}-zts asan: ${{ matrix.asan && 'true' || 'false' }} + skipSlow: ${{ (matrix.asan && !inputs.all_variations) && 'true' || 'false' }} - name: make run: make -j$(/usr/bin/nproc) >/dev/null - name: make install uses: ./.github/actions/install-linux - name: Setup + if: ${{ !matrix.asan || inputs.all_variations }} uses: ./.github/actions/setup-x64 - name: Test + if: ${{ inputs.all_variations || !matrix.asan }} uses: ./.github/actions/test-linux with: runTestsParameters: >- - ${{ matrix.run_tests_parameters }} + ${{ matrix.asan && '--asan' || '' }} + ${{ matrix.repeat && '--repeat 2' || '' }} + ${{ matrix.variation && '-d zend_test.observer.enabled=1 -d zend_test.observer.show_output=0' || '' }} idleCpu: ${{ matrix.asan && 'true' || 'false' }} - name: Test Tracing JIT uses: ./.github/actions/test-linux with: jitType: tracing runTestsParameters: >- - ${{ matrix.run_tests_parameters }} + ${{ matrix.asan && '--asan' || '' }} + ${{ (matrix.asan && !inputs.all_variations) && '-x' || '' }} + ${{ matrix.repeat && '--repeat 2' || '' }} + ${{ matrix.variation && '-d zend_test.observer.enabled=1 -d zend_test.observer.show_output=0' || '' }} -d opcache.enable_cli=1 - name: Test OpCache + if: ${{ inputs.all_variations }} uses: ./.github/actions/test-linux with: runTestsParameters: >- - ${{ matrix.run_tests_parameters }} + ${{ matrix.asan && '--asan' || '' }} + ${{ matrix.repeat && '--repeat 2' || '' }} + ${{ matrix.variation && '-d zend_test.observer.enabled=1 -d zend_test.observer.show_output=0' || '' }} -d opcache.enable_cli=1 - name: Test Function JIT # ASAN frequently timeouts. Each test run takes ~90 minutes, we can # avoid running into the 6 hour timeout by skipping the function JIT. - if: matrix.test_function_jit + if: ${{ inputs.all_variations && !matrix.asan }} uses: ./.github/actions/test-linux with: jitType: function runTestsParameters: >- - ${{ matrix.run_tests_parameters }} + ${{ matrix.repeat && '--repeat 2' || '' }} + ${{ matrix.variation && '-d zend_test.observer.enabled=1 -d zend_test.observer.show_output=0' || '' }} -d opcache.enable_cli=1 - name: Extra tests uses: ./.github/actions/extra-tests - name: Verify generated files are up to date uses: ./.github/actions/verify-generated-files LINUX_X32: + if: ${{ fromJson(inputs.branch).jobs.LINUX_X32 }} strategy: fail-fast: false - matrix: - debug: [true, false] - zts: [true, false] + matrix: ${{ fromJson(inputs.branch).jobs.LINUX_X32.matrix }} name: "LINUX_X32_${{ matrix.debug && 'DEBUG' || 'RELEASE' }}_${{ matrix.zts && 'ZTS' || 'NTS' }}" runs-on: ubuntu-latest container: - image: ubuntu:${{ inputs.ubuntu_version }} + image: ubuntu:${{ fromJson(inputs.branch).config.ubuntu_version }} env: + MYSQL_TEST_HOST: mysql + PDO_MYSQL_TEST_DSN: mysql:host=mysql;dbname=test + PDO_MYSQL_TEST_HOST: mysql PDO_FIREBIRD_TEST_DSN: firebird:dbname=firebird:test.fdb services: mysql: @@ -296,9 +251,13 @@ jobs: - name: git checkout uses: actions/checkout@v6 with: - ref: ${{ inputs.branch }} + ref: ${{ fromJson(inputs.branch).ref }} - name: apt uses: ./.github/actions/apt-x32 + - name: ccache + uses: ./.github/actions/ccache + with: + name: "LINUX_X32_${{ matrix.debug && 'DEBUG' || 'RELEASE' }}_${{ matrix.zts && 'ZTS' || 'NTS' }}" - name: System info run: | echo "::group::Show host CPU info" @@ -318,53 +277,50 @@ jobs: - name: make install uses: ./.github/actions/install-linux-x32 - name: Test + if: ${{ inputs.all_variations }} uses: ./.github/actions/test-linux - with: - runTestsParameters: >- - ${{ matrix.run_tests_parameters }} - name: Test Tracing JIT uses: ./.github/actions/test-linux with: jitType: tracing runTestsParameters: >- - ${{ matrix.run_tests_parameters }} -d opcache.enable_cli=1 - name: Test OpCache + if: ${{ inputs.all_variations }} uses: ./.github/actions/test-linux with: runTestsParameters: >- - ${{ matrix.run_tests_parameters }} -d opcache.enable_cli=1 - name: Test Function JIT + if: ${{ inputs.all_variations }} uses: ./.github/actions/test-linux with: jitType: function runTestsParameters: >- - ${{ matrix.run_tests_parameters }} -d opcache.enable_cli=1 - name: Extra tests uses: ./.github/actions/extra-tests MACOS: + if: ${{ fromJson(inputs.branch).jobs.MACOS }} strategy: fail-fast: false - matrix: - debug: [true, false] - zts: [true, false] - arch: ['X64', 'ARM64'] - exclude: - - arch: ${{ !inputs.run_macos_arm64 && 'ARM64' || '*never*' }} + matrix: ${{ fromJson(inputs.branch).jobs.MACOS.matrix }} name: "MACOS_${{ matrix.arch }}_${{ matrix.debug && 'DEBUG' || 'RELEASE' }}_${{ matrix.zts && 'ZTS' || 'NTS' }}" - runs-on: macos-${{ matrix.arch == 'X64' && '15-intel' || inputs.macos_arm64_version }} + runs-on: macos-${{ matrix.arch == 'X64' && '15-intel' || fromJson(inputs.branch).jobs.MACOS.config.arm64_version }} steps: - name: git checkout uses: actions/checkout@v6 with: - ref: ${{ inputs.branch }} + ref: ${{ fromJson(inputs.branch).ref }} - name: Update clang uses: ./.github/actions/macos-update-clang - name: brew timeout-minutes: 10 uses: ./.github/actions/brew + - name: ccache + uses: ./.github/actions/ccache + with: + name: "MACOS_${{ matrix.arch }}_${{ matrix.debug && 'DEBUG' || 'RELEASE' }}_${{ matrix.zts && 'ZTS' || 'NTS' }}" - name: ./configure uses: ./.github/actions/configure-macos with: @@ -378,21 +334,23 @@ jobs: - name: make install run: sudo make install - name: Test + if: ${{ inputs.all_variations }} uses: ./.github/actions/test-macos - name: Test Tracing JIT - if: matrix.arch == 'X64' || !matrix.zts + if: ${{ matrix.arch == 'X64' || !matrix.zts }} uses: ./.github/actions/test-macos with: jitType: tracing runTestsParameters: >- -d opcache.enable_cli=1 - name: Test OpCache + if: ${{ inputs.all_variations || (matrix.arch == 'ARM64' && matrix.zts) }} uses: ./.github/actions/test-macos with: runTestsParameters: >- -d opcache.enable_cli=1 - name: Test Function JIT - if: matrix.arch == 'X64' || !matrix.zts + if: ${{ inputs.all_variations && (matrix.arch == 'X64' || !matrix.zts) }} uses: ./.github/actions/test-macos with: jitType: function @@ -402,8 +360,8 @@ jobs: uses: ./.github/actions/extra-tests - name: Verify generated files are up to date uses: ./.github/actions/verify-generated-files - COVERAGE_DEBUG_NTS: - if: inputs.branch == 'master' + COVERAGE: + if: ${{ fromJson(inputs.branch).jobs.COVERAGE }} services: mysql: image: mysql:8.4 @@ -432,7 +390,7 @@ jobs: - name: git checkout uses: actions/checkout@v6 with: - ref: ${{ inputs.branch }} + ref: ${{ fromJson(inputs.branch).ref }} - name: Create MSSQL container uses: ./.github/actions/setup-mssql - name: apt @@ -463,14 +421,12 @@ jobs: token: ${{ secrets.CODECOV_TOKEN }} verbose: true COMMUNITY: + if: ${{ fromJson(inputs.branch).jobs.COMMUNITY }} strategy: fail-fast: false - matrix: - type: ['asan', 'verify_type_inference'] - exclude: - - type: ${{ !inputs.community_verify_type_inference && 'verify_type_inference' || '*never*' }} + matrix: ${{ fromJson(inputs.branch).jobs.COMMUNITY.matrix }} name: "COMMUNITY_${{ matrix.type }}" - runs-on: ubuntu-${{ inputs.ubuntu_version }} + runs-on: ubuntu-${{ fromJson(inputs.branch).config.ubuntu_version }} env: ASAN_OPTIONS: exitcode=139 UBSAN_OPTIONS: print_stacktrace=1 @@ -480,7 +436,7 @@ jobs: - name: git checkout uses: actions/checkout@v6 with: - ref: ${{ inputs.branch }} + ref: ${{ fromJson(inputs.branch).ref }} - name: apt uses: ./.github/actions/apt-x64 - name: ./configure @@ -511,7 +467,7 @@ jobs: echo opcache.interned_strings_buffer=64 >> /etc/php.d/opcache.ini echo opcache.max_accelerated_files=100000 >> /etc/php.d/opcache.ini - name: Enable JIT - if: matrix.type != 'verify_type_inference' + if: ${{ matrix.type != 'verify_type_inference' }} run: | echo opcache.jit=tracing >> /etc/php.d/opcache.ini echo opcache.jit_buffer_size=1G >> /etc/php.d/opcache.ini @@ -545,7 +501,7 @@ jobs: done exit $X - name: Test Laravel - if: ${{ !cancelled() && !inputs.skip_laravel }} + if: ${{ !cancelled() }} run: | git clone https://github.com/laravel/framework.git --depth=1 cd framework @@ -590,9 +546,9 @@ jobs: exit 1 fi - name: Test Symfony - if: ${{ !cancelled() && inputs.symfony_version != '' }} + if: ${{ !cancelled() }} run: | - git clone https://github.com/symfony/symfony.git --depth=1 --branch="${{ inputs.symfony_version }}" + git clone https://github.com/symfony/symfony.git --depth=1 --branch="${{ fromJson(inputs.branch).jobs.COMMUNITY.config.symfony_version }}" cd symfony git rev-parse HEAD php /usr/bin/composer install --no-progress --ignore-platform-req=php+ @@ -627,7 +583,7 @@ jobs: fi - name: 'Symfony Preloading' # composer create-project will automatically pick the right Symfony version for us. - if: ${{ !cancelled() && inputs.symfony_version != '' }} + if: ${{ !cancelled() }} run: | php /usr/bin/composer create-project symfony/symfony-demo symfony_demo --no-progress --ignore-platform-req=php+ cd symfony_demo @@ -635,7 +591,7 @@ jobs: sed -i 's/PHP_SAPI/"cli-server"/g' var/cache/dev/App_KernelDevDebugContainer.preload.php php -d opcache.preload=var/cache/dev/App_KernelDevDebugContainer.preload.php public/index.php - name: Test Wordpress - if: ${{ !cancelled() && !inputs.skip_wordpress }} + if: ${{ !cancelled() }} run: | git clone https://github.com/WordPress/wordpress-develop.git wordpress --depth=1 cd wordpress @@ -650,6 +606,7 @@ jobs: exit 1 fi OPCACHE_VARIATION: + if: ${{ fromJson(inputs.branch).jobs.OPCACHE_VARIATION }} services: mysql: image: mysql:8.4 @@ -674,12 +631,12 @@ jobs: FIREBIRD_USER: test FIREBIRD_PASSWORD: test name: OPCACHE_VARIATION - runs-on: ubuntu-${{ inputs.ubuntu_version }} + runs-on: ubuntu-${{ fromJson(inputs.branch).config.ubuntu_version }} steps: - name: git checkout uses: actions/checkout@v6 with: - ref: ${{ inputs.branch }} + ref: ${{ fromJson(inputs.branch).ref }} - name: Create MSSQL container uses: ./.github/actions/setup-mssql - name: apt @@ -731,13 +688,14 @@ jobs: - name: Verify generated files are up to date uses: ./.github/actions/verify-generated-files MSAN: + if: ${{ fromJson(inputs.branch).jobs.MSAN }} name: MSAN - runs-on: ubuntu-${{ inputs.ubuntu_version }} + runs-on: ubuntu-${{ fromJson(inputs.branch).config.ubuntu_version }} steps: - name: git checkout uses: actions/checkout@v6 with: - ref: ${{ inputs.branch }} + ref: ${{ fromJson(inputs.branch).ref }} - name: apt uses: ./.github/actions/apt-x64 - name: ./configure @@ -817,13 +775,14 @@ jobs: - name: Verify generated files are up to date uses: ./.github/actions/verify-generated-files LIBMYSQLCLIENT: + if: ${{ fromJson(inputs.branch).jobs.LIBMYSQLCLIENT }} name: LIBMYSQLCLIENT - runs-on: ubuntu-${{ inputs.ubuntu_version }} + runs-on: ubuntu-${{ fromJson(inputs.branch).config.ubuntu_version }} steps: - name: git checkout uses: actions/checkout@v6 with: - ref: ${{ inputs.branch }} + ref: ${{ fromJson(inputs.branch).ref }} - name: apt run: | sudo apt-get update -y | true @@ -851,7 +810,7 @@ jobs: - name: Verify generated files are up to date uses: ./.github/actions/verify-generated-files PECL: - if: inputs.branch == 'master' + if: ${{ fromJson(inputs.branch).jobs.PECL }} runs-on: ubuntu-24.04 env: CC: ccache gcc @@ -861,7 +820,7 @@ jobs: uses: actions/checkout@v6 with: path: php - ref: ${{ inputs.branch }} + ref: ${{ fromJson(inputs.branch).ref }} - name: git checkout apcu uses: actions/checkout@v6 with: @@ -904,11 +863,9 @@ jobs: bison \ re2c - name: ccache - uses: hendrikmuhs/ccache-action@v1.2 + uses: ./.github/actions/ccache with: - key: "${{github.job}}-${{hashFiles('php/main/php_version.h')}}" - append-timestamp: false - save: ${{ github.event_name != 'pull_request' }} + name: "${{ github.job }}" - name: build PHP run: | cd php @@ -960,32 +917,18 @@ jobs: ./configure --prefix=/opt/php --with-php-config=/opt/php/bin/php-config make -j$(/usr/bin/nproc) WINDOWS: + if: ${{ fromJson(inputs.branch).jobs.WINDOWS }} strategy: fail-fast: false - matrix: - include: - - x64: true - zts: true - opcache: true - asan: false - - x64: false - zts: false - opcache: false - asan: false - - x64: true - zts: true - opcache: true - asan: true - branch: 'master' - timeout: 120 + matrix: ${{ fromJson(inputs.branch).jobs.WINDOWS.matrix }} name: "WINDOWS_${{ matrix.x64 && 'X64' || 'X86' }}_${{ matrix.zts && 'ZTS' || 'NTS' }}${{ matrix.asan && '_ASAN' || ''}}" - runs-on: windows-${{ inputs.windows_version }} + runs-on: windows-2022 env: PHP_BUILD_CACHE_BASE_DIR: C:\build-cache PHP_BUILD_OBJ_DIR: C:\obj PHP_BUILD_CACHE_SDK_DIR: C:\build-cache\sdk PHP_BUILD_SDK_BRANCH: php-sdk-2.5.0 - PHP_BUILD_CRT: ${{ inputs.vs_crt_version }} + PHP_BUILD_CRT: ${{ fromJson(inputs.branch).jobs.WINDOWS.config.vs_crt_version }} PLATFORM: ${{ matrix.x64 && 'x64' || 'x86' }} THREAD_SAFE: "${{ matrix.zts && '1' || '0' }}" INTRINSICS: "${{ matrix.zts && 'AVX2' || '' }}" @@ -998,7 +941,7 @@ jobs: - name: git checkout uses: actions/checkout@v6 with: - ref: ${{ inputs.branch }} + ref: ${{ fromJson(inputs.branch).ref }} - name: Setup uses: ./.github/actions/setup-windows - name: Build @@ -1006,12 +949,10 @@ jobs: - name: Test run: .github/scripts/windows/test.bat FREEBSD: + if: ${{ fromJson(inputs.branch).jobs.FREEBSD }} strategy: fail-fast: false - matrix: - zts: [true, false] - exclude: - - zts: ${{ !inputs.run_freebsd_zts && true || '*never*' }} + matrix: ${{ fromJson(inputs.branch).jobs.FREEBSD.matrix }} name: "FREEBSD_${{ matrix.zts && 'ZTS' || 'NTS' }}" runs-on: ubuntu-latest timeout-minutes: 50 @@ -1019,7 +960,7 @@ jobs: - name: git checkout uses: actions/checkout@v6 with: - ref: ${{ inputs.branch }} + ref: ${{ fromJson(inputs.branch).ref }} - name: FreeBSD uses: ./.github/actions/freebsd with: diff --git a/.github/workflows/push.yml b/.github/workflows/push.yml index 602716fbfed5..7f2bcf2ca9e5 100644 --- a/.github/workflows/push.yml +++ b/.github/workflows/push.yml @@ -1,7 +1,7 @@ name: Push on: push: - paths-ignore: + paths-ignore: &ignore_paths - docs/** - NEWS - UPGRADING @@ -10,31 +10,20 @@ on: - CONTRIBUTING.md - CODING_STANDARDS.md - .cirrus.yml - - .travis.yml - - travis/** - .circleci/** branches: - - PHP-7.4 - - PHP-8.0 - - PHP-8.1 - PHP-8.2 + - PHP-8.3 + - PHP-8.4 + - PHP-8.5 - master pull_request: - paths-ignore: - - docs/** - - NEWS - - UPGRADING - - UPGRADING.INTERNALS - - '**/README.*' - - CONTRIBUTING.md - - CODING_STANDARDS.md - - .cirrus.yml - - .travis.yml - - travis/** - - .circleci/** + paths-ignore: *ignore_paths branches: - '**' workflow_dispatch: ~ +permissions: + contents: read concurrency: group: ${{ github.workflow }}-${{ github.event.pull_request.url || github.run_id }} cancel-in-progress: true @@ -42,192 +31,130 @@ env: CC: ccache gcc CXX: ccache g++ jobs: - LINUX_X64: + GENERATE_MATRIX: + name: Generate Matrix if: github.repository == 'php/php-src' || github.event_name == 'pull_request' - services: - mysql: - image: mysql:8.4 - ports: - - 3306:3306 - env: - MYSQL_DATABASE: test - MYSQL_ROOT_PASSWORD: root - postgres: - image: postgres - ports: - - 5432:5432 - env: - POSTGRES_USER: postgres - POSTGRES_PASSWORD: postgres - POSTGRES_DB: test + runs-on: ubuntu-latest + outputs: + all_variations: ${{ steps.set-matrix.outputs.all_variations }} + branches: ${{ steps.set-matrix.outputs.branches }} + steps: + - uses: actions/checkout@v6 + - name: Generate Matrix + id: set-matrix + run: php .github/nightly_matrix.php "${{ github.event_name }}" "${{ github.run_attempt }}" "${{ github.ref }}" '${{ toJSON(github.event.pull_request.labels) }}' + PUSH: + needs: GENERATE_MATRIX + name: ${{ matrix.branch.ref }} + uses: ./.github/workflows/nightly.yml strategy: fail-fast: false matrix: - include: - - debug: true - zts: false - - debug: false - zts: true - name: "LINUX_X64_${{ matrix.debug && 'DEBUG' || 'RELEASE' }}_${{ matrix.zts && 'ZTS' || 'NTS' }}" - runs-on: ubuntu-22.04 + branch: ${{ fromJson(needs.GENERATE_MATRIX.outputs.branches) }} + with: + all_variations: ${{ needs.GENERATE_MATRIX.outputs.all_variations == 'true' }} + branch: ${{ toJSON(matrix.branch) }} + secrets: inherit + BENCHMARKING: + name: BENCHMARKING + if: github.repository == 'php/php-src' || github.event_name == 'pull_request' + runs-on: ubuntu-24.04 + timeout-minutes: 50 steps: - name: git checkout uses: actions/checkout@v6 - - name: Create MSSQL container - uses: ./.github/actions/setup-mssql - - name: Create Oracle container - uses: ./.github/actions/setup-oracle - - name: Setup Caddy server - uses: ./.github/actions/setup-caddy - - name: apt - uses: ./.github/actions/apt-x64 - - name: ccache - uses: hendrikmuhs/ccache-action@v1.2 - with: - # This duplicates the "job.name" expression above because - # GitHub has no way to query the job name (github.job is the - # job id, not the job name) - key: "LINUX_X64_${{ matrix.debug && 'DEBUG' || 'RELEASE' }}_${{ matrix.zts && 'ZTS' || 'NTS' }}-${{hashFiles('main/php_version.h')}}" - append-timestamp: false - save: ${{ github.event_name != 'pull_request' }} - - name: ./configure - uses: ./.github/actions/configure-x64 - with: - configurationParameters: >- - --${{ matrix.debug && 'enable' || 'disable' }}-debug - --${{ matrix.zts && 'enable' || 'disable' }}-zts - - name: make - run: make -j$(/usr/bin/nproc) >/dev/null - - name: make install - uses: ./.github/actions/install-linux - - name: Setup - uses: ./.github/actions/setup-x64 - - name: Test - uses: ./.github/actions/test-linux - - name: Test Tracing JIT - uses: ./.github/actions/test-linux with: - jitType: tracing - runTestsParameters: >- - -d zend_extension=opcache.so - -d opcache.enable_cli=1 - - name: Verify generated files are up to date - uses: ./.github/actions/verify-generated-files - LINUX_X32: - name: LINUX_X32_DEBUG_ZTS - runs-on: ubuntu-latest - container: - image: ubuntu:20.04 - env: - MYSQL_TEST_HOST: mysql - PDO_MYSQL_TEST_DSN: mysql:host=mysql;dbname=test - PDO_MYSQL_TEST_HOST: mysql - services: - mysql: - image: mysql:8.4 - ports: - - 3306:3306 - env: - MYSQL_DATABASE: test - MYSQL_ROOT_PASSWORD: root - steps: - - name: git checkout - uses: actions/checkout@v6 + fetch-depth: 0 + # ASLR can cause a lot of noise due to missed sse opportunities for memcpy + # and other operations, so we disable it during benchmarking. + - name: Disable ASLR + run: echo 0 | sudo tee /proc/sys/kernel/randomize_va_space - name: apt - uses: ./.github/actions/apt-x32 + run: | + set -x + sudo apt-get update + sudo apt-get install \ + bison \ + libgmp-dev \ + libonig-dev \ + libsqlite3-dev \ + openssl \ + re2c \ + valgrind - name: ccache - uses: hendrikmuhs/ccache-action@v1.2 + uses: ./.github/actions/ccache with: - key: "${{github.job}}-${{hashFiles('main/php_version.h')}}" - append-timestamp: false - save: ${{ github.event_name != 'pull_request' }} + name: "${{ github.job }}" - name: ./configure - uses: ./.github/actions/configure-x32 - with: - configurationParameters: >- - --enable-debug - --enable-zts + run: | + set -x + ./buildconf --force + ./configure \ + --disable-debug \ + --enable-mbstring \ + --enable-option-checking=fatal \ + --enable-sockets \ + --enable-werror \ + --prefix=/usr \ + --with-config-file-scan-dir=/etc/php.d \ + --with-gmp \ + --with-mysqli=mysqlnd \ + --with-openssl \ + --with-pdo-sqlite \ + --with-valgrind - name: make run: make -j$(/usr/bin/nproc) >/dev/null - name: make install - uses: ./.github/actions/install-linux-x32 - - name: Test Tracing JIT - uses: ./.github/actions/test-linux - with: - jitType: tracing - runTestsParameters: >- - -d zend_extension=opcache.so - -d opcache.enable_cli=1 - MACOS_DEBUG_NTS: - if: github.repository == 'php/php-src' || github.event_name == 'pull_request' - runs-on: macos-14 - steps: - - name: git checkout + run: | + set -x + sudo make install + sudo mkdir -p /etc/php.d + sudo chmod 777 /etc/php.d + echo mysqli.default_socket=/var/run/mysqld/mysqld.sock > /etc/php.d/mysqli.ini + echo opcache.enable=1 >> /etc/php.d/opcache.ini + echo opcache.enable_cli=1 >> /etc/php.d/opcache.ini + - name: Setup + run: | + git config --global user.name "Benchmark" + git config --global user.email "benchmark@php.net" + sudo service mysql start + mysql -uroot -proot -e "CREATE DATABASE IF NOT EXISTS wordpress" + mysql -uroot -proot -e "CREATE USER 'wordpress'@'localhost' IDENTIFIED BY 'wordpress'; FLUSH PRIVILEGES;" + mysql -uroot -proot -e "GRANT ALL PRIVILEGES ON *.* TO 'wordpress'@'localhost' WITH GRANT OPTION;" + - name: git checkout benchmarking-data uses: actions/checkout@v6 - - name: Update clang - uses: ./.github/actions/macos-update-clang - - name: brew - timeout-minutes: 10 - uses: ./.github/actions/brew - - name: ccache - uses: hendrikmuhs/ccache-action@v1.2 with: - key: "${{github.job}}-${{hashFiles('main/php_version.h')}}" - append-timestamp: false - save: ${{ github.event_name != 'pull_request' }} - - name: ./configure - uses: ./.github/actions/configure-macos - with: - configurationParameters: --enable-debug --disable-zts - - name: make + repository: php/benchmarking-data + ssh-key: ${{ secrets.BENCHMARKING_DATA_DEPLOY_KEY }} + path: benchmark/repos/data + - name: Benchmark + run: php benchmark/benchmark.php true + - name: Store result + if: github.event_name == 'push' + run: | + set -x + cd benchmark/repos/data + git pull --autostash + if [ -e ".git/MERGE_HEAD" ]; then + echo "Merging, can't proceed" + exit 1 + fi + git add . + if git diff --cached --quiet; then + exit 0 + fi + git commit -m "Add result for ${{ github.repository }}@${{ github.sha }}" + git push + - name: Show diff + if: github.event_name == 'pull_request' run: |- - export PATH="$(brew --prefix)/opt/bison/bin:$PATH" - make -j$(sysctl -n hw.logicalcpu) >/dev/null - - name: make install - run: sudo make install - - name: Test Tracing JIT - uses: ./.github/actions/test-macos + set -x + php benchmark/generate_diff.php \ + ${{ github.sha }} \ + $(git merge-base ${{ github.event.pull_request.base.sha }} ${{ github.sha }}) \ + > $GITHUB_STEP_SUMMARY + - uses: actions/upload-artifact@v6 with: - jitType: tracing - runTestsParameters: >- - -d zend_extension=opcache.so - -d opcache.enable_cli=1 - -d opcache.protect_memory=1 - - name: Verify generated files are up to date - uses: ./.github/actions/verify-generated-files - WINDOWS: - if: github.repository == 'php/php-src' || github.event_name == 'pull_request' - name: WINDOWS_X64_ZTS - runs-on: windows-2022 - env: - PHP_BUILD_CACHE_BASE_DIR: C:\build-cache - PHP_BUILD_OBJ_DIR: C:\obj - PHP_BUILD_CACHE_SDK_DIR: C:\build-cache\sdk - PHP_BUILD_SDK_BRANCH: php-sdk-2.3.0 - PHP_BUILD_CRT: vs16 - PLATFORM: x64 - THREAD_SAFE: "1" - INTRINSICS: AVX2 - PARALLEL: -j2 - OPCACHE: "1" - steps: - - name: git config - run: git config --global core.autocrlf false && git config --global core.eol lf - - name: git checkout - uses: actions/checkout@v6 - - name: Setup - uses: ./.github/actions/setup-windows - - name: Build - run: .github/scripts/windows/build.bat - - name: Test - run: .github/scripts/windows/test.bat - FREEBSD: - if: github.repository == 'php/php-src' || github.event_name == 'pull_request' - name: FREEBSD - runs-on: ubuntu-latest - timeout-minutes: 50 - steps: - - name: git checkout - uses: actions/checkout@v6 - - name: FreeBSD - uses: ./.github/actions/freebsd + name: profiles + path: ${{ github.workspace }}/benchmark/profiles + retention-days: 30 diff --git a/.github/workflows/root.yml b/.github/workflows/root.yml index 6958a9cd4147..9a47d5ceec4b 100644 --- a/.github/workflows/root.yml +++ b/.github/workflows/root.yml @@ -11,6 +11,7 @@ jobs: if: github.repository == 'php/php-src' || github.event_name == 'workflow_dispatch' runs-on: ubuntu-latest outputs: + all_variations: ${{ steps.set-matrix.outputs.all_variations }} branches: ${{ steps.set-matrix.outputs.branches }} steps: - uses: actions/checkout@v6 @@ -30,7 +31,7 @@ jobs: nightly- - name: Generate Matrix id: set-matrix - run: php .github/nightly_matrix.php "${{ github.event_name }}" "${{ github.run_attempt }}" "${{ github.head_ref || github.ref_name }}" + run: php .github/nightly_matrix.php "${{ github.event_name }}" "${{ github.run_attempt }}" "${{ github.head_ref || github.ref_name }}" '[]' NIGHTLY: needs: GENERATE_MATRIX name: ${{ matrix.branch.ref }} @@ -41,22 +42,6 @@ jobs: matrix: branch: ${{ fromJson(needs.GENERATE_MATRIX.outputs.branches) }} with: - asan_ubuntu_version: ${{ - (((matrix.branch.version[0] == 8 && matrix.branch.version[1] >= 5) || matrix.branch.version[0] >= 9) && '24.04') - || '22.04' }} - branch: ${{ matrix.branch.ref }} - community_verify_type_inference: ${{ (matrix.branch.version[0] == 8 && matrix.branch.version[1] >= 4) || matrix.branch.version[0] >= 9 }} - run_alpine: ${{ (matrix.branch.version[0] == 8 && matrix.branch.version[1] >= 4) || matrix.branch.version[0] >= 9 }} - run_linux_ppc64: ${{ (matrix.branch.version[0] == 8 && matrix.branch.version[1] >= 4) || matrix.branch.version[0] >= 9 }} - run_macos_arm64: ${{ (matrix.branch.version[0] == 8 && matrix.branch.version[1] >= 4) || matrix.branch.version[0] >= 9 }} - run_freebsd_zts: ${{ (matrix.branch.version[0] == 8 && matrix.branch.version[1] >= 3) || matrix.branch.version[0] >= 9 }} - ubuntu_version: ${{ - (((matrix.branch.version[0] == 8 && matrix.branch.version[1] >= 5) || matrix.branch.version[0] >= 9) && '24.04') - || '22.04' }} - windows_version: '2022' - vs_crt_version: ${{ ((matrix.branch.version[0] == 8 && matrix.branch.version[1] >= 4) && 'vs17') || 'vs16' }} - skip_laravel: false - symfony_version: ${{ (((matrix.branch.version[0] == 8 && matrix.branch.version[1] >= 4) || matrix.branch.version[0] >= 9) && '8.1') || '7.4' }} - skip_wordpress: false - variation_enable_zend_max_execution_timers: ${{ (matrix.branch.version[0] == 8 && matrix.branch.version[1] >= 3) || matrix.branch.version[0] >= 9 }} + all_variations: ${{ needs.GENERATE_MATRIX.outputs.all_variations == 'true' }} + branch: ${{ toJSON(matrix.branch) }} secrets: inherit From 60718c7f4379b70f1bdcf7f5de17ef1804107b8c Mon Sep 17 00:00:00 2001 From: Ilija Tovilo Date: Tue, 17 Feb 2026 17:55:23 +0100 Subject: [PATCH 03/12] Fix array_column() on null in nightly_matrix.php --- .github/nightly_matrix.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/nightly_matrix.php b/.github/nightly_matrix.php index 8e4e9e7606e2..0fd712f29db6 100644 --- a/.github/nightly_matrix.php +++ b/.github/nightly_matrix.php @@ -155,7 +155,7 @@ function select_jobs($trigger, $labels, $php_version, $ref, $all_variations) { ? get_branches() : [['ref' => $branch, 'version' => get_current_version()]]; -$labels = json_decode($argv[4] ?? '[]', true); +$labels = json_decode($argv[4] ?? '[]', true) ?? []; $labels = array_column($labels, 'name'); $all_variations = $trigger === 'schedule' || $trigger === 'workflow_dispatch' || in_array('CI: All variations', $labels, true); From 1931472f22abfd5c5f336c8e9f3c08403161e0d9 Mon Sep 17 00:00:00 2001 From: Ilija Tovilo Date: Mon, 16 Feb 2026 18:24:54 +0100 Subject: [PATCH 04/12] Fix borked SCCP of array containing partial object In SCCP, arrays containing partial objects must be marked as partial so that their values are not accidentally propagated. Fixes GH-21227 Closes GH-21232 --- NEWS | 2 ++ Zend/Optimizer/sccp.c | 4 ++-- ext/opcache/tests/gh21227.phpt | 23 +++++++++++++++++++++++ 3 files changed, 27 insertions(+), 2 deletions(-) create mode 100644 ext/opcache/tests/gh21227.phpt diff --git a/NEWS b/NEWS index ee8e49f73203..3ddd141ab9ba 100644 --- a/NEWS +++ b/NEWS @@ -34,6 +34,8 @@ PHP NEWS - Opcache: . Fixed bug GH-20718 ("Insufficient shared memory" when using JIT on Solaris). (Petr Sumbera) + . Fixed bug GH-21227 (Borked SCCP of array containing partial object). + (ilutov) - PDO_PGSQL: . Fixed bug GH-21055 (connection attribute status typo for GSS negotiation). diff --git a/Zend/Optimizer/sccp.c b/Zend/Optimizer/sccp.c index c1faf2a3fbe0..24b63a9cf407 100644 --- a/Zend/Optimizer/sccp.c +++ b/Zend/Optimizer/sccp.c @@ -965,7 +965,7 @@ static void sccp_visit_instr(scdf_ctx *scdf, zend_op *opline, zend_ssa_op *ssa_o SET_RESULT(op1, &zv); } else if (ct_eval_assign_dim(&zv, data, op2) == SUCCESS) { /* Mark array containing partial array as partial */ - if (IS_PARTIAL_ARRAY(data)) { + if (IS_PARTIAL_ARRAY(data) || IS_PARTIAL_OBJECT(data)) { MAKE_PARTIAL_ARRAY(&zv); } SET_RESULT(result, data); @@ -1165,7 +1165,7 @@ static void sccp_visit_instr(scdf_ctx *scdf, zend_op *opline, zend_ssa_op *ssa_o /* We can't add NEXT element into partial array (skip it) */ SET_RESULT(result, &zv); } else if (ct_eval_add_array_elem(&zv, op1, op2) == SUCCESS) { - if (IS_PARTIAL_ARRAY(op1)) { + if (IS_PARTIAL_ARRAY(op1) || IS_PARTIAL_OBJECT(op1)) { MAKE_PARTIAL_ARRAY(&zv); } SET_RESULT(result, &zv); diff --git a/ext/opcache/tests/gh21227.phpt b/ext/opcache/tests/gh21227.phpt new file mode 100644 index 000000000000..f236b8e0523a --- /dev/null +++ b/ext/opcache/tests/gh21227.phpt @@ -0,0 +1,23 @@ +--TEST-- +GH-21227: Borked SCCP of array containing partial object +--CREDITS-- +Daniel Chong (chongwick) +--EXTENSIONS-- +opcache +--INI-- +opcache.enable=1 +opcache.enable_cli=1 +--FILE-- +a = 3; + $objs = []; + $obj = new stdClass; + $objs[] = $obj; +} + +?> +===DONE=== +--EXPECT-- +===DONE=== From da43645515a0b1c2e33012a0a3ccfe1e2819c7c6 Mon Sep 17 00:00:00 2001 From: ndossche <7771979+ndossche@users.noreply.github.com> Date: Tue, 17 Feb 2026 21:37:53 +0100 Subject: [PATCH 05/12] Fix GH-21244: use after free in zend_test_class_free_obj Not really a bug, as zend_test shouldn't be used outside of debugging, but let's silence fuzzers. The problem is that the arg info should be cloned as well when the class is cloned; or we fix it the simple way in this patch and make it uncloneable. --- ext/zend_test/test.c | 1 + 1 file changed, 1 insertion(+) diff --git a/ext/zend_test/test.c b/ext/zend_test/test.c index d99c40bc72be..0faf65f36437 100644 --- a/ext/zend_test/test.c +++ b/ext/zend_test/test.c @@ -1527,6 +1527,7 @@ PHP_MINIT_FUNCTION(zend_test) memcpy(&zend_test_class_handlers, &std_object_handlers, sizeof(zend_object_handlers)); zend_test_class_handlers.get_method = zend_test_class_method_get; + zend_test_class_handlers.clone_obj = NULL; zend_test_class_handlers.free_obj = zend_test_class_free_obj; zend_test_class_handlers.offset = XtOffsetOf(zend_test_object, std); From 4b9e80eae9485e2eacb894566ab18dae6ce70ec5 Mon Sep 17 00:00:00 2001 From: ndossche Date: Tue, 20 Jan 2026 15:02:06 +0100 Subject: [PATCH 06/12] Fix memory leak in php_openssl_load_all_certs_from_file() when push fails --- ext/openssl/openssl.c | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/ext/openssl/openssl.c b/ext/openssl/openssl.c index 12383ac8c2c8..62ffa7f92000 100644 --- a/ext/openssl/openssl.c +++ b/ext/openssl/openssl.c @@ -2291,21 +2291,13 @@ static STACK_OF(X509) *php_openssl_load_all_certs_from_file( X509_INFO *xi; char cert_path[MAXPATHLEN]; - if(!(stack = sk_X509_new_null())) { - php_openssl_store_errors(); - php_error_docref(NULL, E_ERROR, "Memory allocation failure"); - goto end; - } - if (!php_openssl_check_path(cert_file, cert_file_len, cert_path, arg_num)) { - sk_X509_free(stack); goto end; } if (!(in = BIO_new_file(cert_path, PHP_OPENSSL_BIO_MODE_R(PKCS7_BINARY)))) { php_openssl_store_errors(); php_error_docref(NULL, E_WARNING, "Error opening the file, %s", cert_path); - sk_X509_free(stack); goto end; } @@ -2313,7 +2305,11 @@ static STACK_OF(X509) *php_openssl_load_all_certs_from_file( if (!(sk = PEM_X509_INFO_read_bio(in, NULL, NULL, NULL))) { php_openssl_store_errors(); php_error_docref(NULL, E_WARNING, "Error reading the file, %s", cert_path); - sk_X509_free(stack); + goto end; + } + + if(!(stack = sk_X509_new_reserve(NULL, sk_X509_INFO_num(sk)))) { + php_openssl_store_errors(); goto end; } From 01d598aea34825f67089801ea61234de5d499aaf Mon Sep 17 00:00:00 2001 From: ndossche Date: Tue, 20 Jan 2026 15:14:13 +0100 Subject: [PATCH 07/12] Fix memory leaks in php_array_to_X509_sk() when push fails --- ext/openssl/openssl.c | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/ext/openssl/openssl.c b/ext/openssl/openssl.c index 62ffa7f92000..39bfe912fc42 100644 --- a/ext/openssl/openssl.c +++ b/ext/openssl/openssl.c @@ -2581,7 +2581,10 @@ static STACK_OF(X509) *php_array_to_X509_sk(zval * zcerts, uint32_t arg_num, con } } - sk_X509_push(sk, cert); + if (sk_X509_push(sk, cert) <= 0) { + X509_free(cert); + goto push_fail_exit; + } } ZEND_HASH_FOREACH_END(); } else { /* a single certificate */ @@ -2599,11 +2602,20 @@ static STACK_OF(X509) *php_array_to_X509_sk(zval * zcerts, uint32_t arg_num, con goto clean_exit; } } - sk_X509_push(sk, cert); + if (sk_X509_push(sk, cert) <= 0) { + X509_free(cert); + goto push_fail_exit; + } } clean_exit: return sk; + +push_fail_exit: + php_openssl_store_errors(); + php_sk_X509_free(sk); + sk = NULL; + goto clean_exit; } /* }}} */ From ef54becb3e11a6fb05cdcd79c2a712f87f90d4dc Mon Sep 17 00:00:00 2001 From: ndossche Date: Tue, 20 Jan 2026 15:14:25 +0100 Subject: [PATCH 08/12] Fix missing error propagation when php_array_to_X509_sk() fails Execution shouldn't continue if this fails because it can give the wrong results. --- ext/openssl/openssl.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/ext/openssl/openssl.c b/ext/openssl/openssl.c index 39bfe912fc42..65e4b7b56d37 100644 --- a/ext/openssl/openssl.c +++ b/ext/openssl/openssl.c @@ -2684,6 +2684,9 @@ PHP_FUNCTION(openssl_pkcs12_export_to_file) if (args && (item = zend_hash_str_find(Z_ARRVAL_P(args), "extracerts", sizeof("extracerts")-1)) != NULL) { ca = php_array_to_X509_sk(item, 5, "extracerts"); + if (!ca) { + goto cleanup; + } } /* end parse extra config */ @@ -2777,6 +2780,9 @@ PHP_FUNCTION(openssl_pkcs12_export) if (args && (item = zend_hash_str_find(Z_ARRVAL_P(args), "extracerts", sizeof("extracerts")-1)) != NULL) { ca = php_array_to_X509_sk(item, 5, "extracerts"); + if (!ca) { + goto cleanup; + } } /* end parse extra config */ From 556ec779512b3851970fedf0a6769bddf719305b Mon Sep 17 00:00:00 2001 From: ndossche Date: Tue, 20 Jan 2026 15:20:11 +0100 Subject: [PATCH 09/12] Fix memory leaks in openssl_pkcs7_encrypt() when push fails --- ext/openssl/openssl.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/ext/openssl/openssl.c b/ext/openssl/openssl.c index 65e4b7b56d37..c99ce2931fd9 100644 --- a/ext/openssl/openssl.c +++ b/ext/openssl/openssl.c @@ -5849,7 +5849,10 @@ PHP_FUNCTION(openssl_pkcs7_encrypt) goto clean_exit; } } - sk_X509_push(recipcerts, cert); + if (sk_X509_push(recipcerts, cert) <= 0) { + X509_free(cert); + goto clean_exit; + } } ZEND_HASH_FOREACH_END(); } else { /* a single certificate */ @@ -5870,7 +5873,10 @@ PHP_FUNCTION(openssl_pkcs7_encrypt) goto clean_exit; } } - sk_X509_push(recipcerts, cert); + if (sk_X509_push(recipcerts, cert) <= 0) { + X509_free(cert); + goto clean_exit; + } } /* sanity check the cipher */ From f6887f04f62301fa91b7da945491bd4c859e6802 Mon Sep 17 00:00:00 2001 From: ndossche Date: Tue, 20 Jan 2026 15:21:13 +0100 Subject: [PATCH 10/12] Fix memory leaks in openssl_cms_encrypt() when push fails --- ext/openssl/openssl.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/ext/openssl/openssl.c b/ext/openssl/openssl.c index c99ce2931fd9..2f2aae1e7335 100644 --- a/ext/openssl/openssl.c +++ b/ext/openssl/openssl.c @@ -6464,7 +6464,10 @@ PHP_FUNCTION(openssl_cms_encrypt) goto clean_exit; } } - sk_X509_push(recipcerts, cert); + if (sk_X509_push(recipcerts, cert) <= 0) { + php_openssl_store_errors(); + goto clean_exit; + } } ZEND_HASH_FOREACH_END(); } else { /* a single certificate */ @@ -6484,7 +6487,10 @@ PHP_FUNCTION(openssl_cms_encrypt) goto clean_exit; } } - sk_X509_push(recipcerts, cert); + if (sk_X509_push(recipcerts, cert) <= 0) { + php_openssl_store_errors(); + goto clean_exit; + } } /* sanity check the cipher */ From b911748fefcb67598c4a0ccef185499bae821020 Mon Sep 17 00:00:00 2001 From: ndossche <7771979+ndossche@users.noreply.github.com> Date: Tue, 17 Feb 2026 21:40:24 +0100 Subject: [PATCH 11/12] Update NEWS for OpenSSL changes --- NEWS | 3 +++ 1 file changed, 3 insertions(+) diff --git a/NEWS b/NEWS index 3ddd141ab9ba..3f9e5c1354d7 100644 --- a/NEWS +++ b/NEWS @@ -37,6 +37,9 @@ PHP NEWS . Fixed bug GH-21227 (Borked SCCP of array containing partial object). (ilutov) +- OpenSSL: + . Fix a bunch of leaks and error propagation. (ndossche) + - PDO_PGSQL: . Fixed bug GH-21055 (connection attribute status typo for GSS negotiation). (lsaos) From e2059a4697a63ba82bd0265a9752158b066fb34a Mon Sep 17 00:00:00 2001 From: Niels Dossche <7771979+ndossche@users.noreply.github.com> Date: Sun, 21 Dec 2025 01:48:46 +0100 Subject: [PATCH 12/12] curl: Don't truncate length Truncating to an int seems dangerous, esp. in combination with a MIN macro. I don't see a reason to truncate the length from size_t to int, and especially no reason to change the signedness. Closes GH-20747. --- NEWS | 1 + ext/curl/interface.c | 6 +++--- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/NEWS b/NEWS index 3f9e5c1354d7..3c7e82dece6e 100644 --- a/NEWS +++ b/NEWS @@ -15,6 +15,7 @@ PHP NEWS - Curl: . Fixed bug GH-21023 (CURLOPT_XFERINFOFUNCTION crash with a null callback). (David Carlier) + . Don't truncate length. (ndossche) - Date: . Fixed bug GH-20936 (DatePeriod::__set_state() cannot handle null start). diff --git a/ext/curl/interface.c b/ext/curl/interface.c index 12db566c089a..7fc1c77e9a9a 100644 --- a/ext/curl/interface.c +++ b/ext/curl/interface.c @@ -583,7 +583,7 @@ static size_t curl_write(char *data, size_t size, size_t nmemb, void *ctx) return fwrite(data, size, nmemb, write_handler->fp); case PHP_CURL_RETURN: if (length > 0) { - smart_str_appendl(&write_handler->buf, data, (int) length); + smart_str_appendl(&write_handler->buf, data, length); } break; case PHP_CURL_USER: { @@ -860,7 +860,7 @@ static size_t curl_read(char *data, size_t size, size_t nmemb, void *ctx) if (!Z_ISUNDEF(retval)) { _php_curl_verify_handlers(ch, /* reporterror */ true); if (Z_TYPE(retval) == IS_STRING) { - length = MIN((size * nmemb), Z_STRLEN(retval)); + length = MIN(size * nmemb, Z_STRLEN(retval)); memcpy(data, Z_STRVAL(retval), length); } else if (Z_TYPE(retval) == IS_LONG) { length = Z_LVAL_P(&retval); @@ -891,7 +891,7 @@ static size_t curl_write_header(char *data, size_t size, size_t nmemb, void *ctx /* Handle special case write when we're returning the entire transfer */ if (ch->handlers.write->method == PHP_CURL_RETURN && length > 0) { - smart_str_appendl(&ch->handlers.write->buf, data, (int) length); + smart_str_appendl(&ch->handlers.write->buf, data, length); } else { PHPWRITE(data, length); }