From 89951374ca96d9048e4e55f8cdc7f10c0e0996d1 Mon Sep 17 00:00:00 2001 From: Akmal Fairuz <35138228+AkmalFairuz@users.noreply.github.com> Date: Sun, 17 Nov 2024 20:20:28 +0700 Subject: [PATCH 01/25] PHP 8.4 support --- src/handlers.c | 4 ++++ src/prepare.c | 2 ++ src/store.c | 6 +++++- 3 files changed, 11 insertions(+), 1 deletion(-) diff --git a/src/handlers.c b/src/handlers.c index dbea1f6a..2485ffae 100644 --- a/src/handlers.c +++ b/src/handlers.c @@ -48,7 +48,11 @@ HashTable* pmmpthread_read_debug(PMMPTHREAD_READ_DEBUG_PASSTHRU_D) { HashTable* pmmpthread_read_properties(PMMPTHREAD_READ_PROPERTIES_PASSTHRU_D) { pmmpthread_zend_object_t* threaded = PMMPTHREAD_FETCH_FROM(object); +#if PHP_MAJOR_VERSION == 8 && PHP_MINOR_VERSION >= 4 + rebuild_object_properties_internal(&threaded->std); +#else rebuild_object_properties(&threaded->std); +#endif pmmpthread_store_tohash( &threaded->std, threaded->std.properties); diff --git a/src/prepare.c b/src/prepare.c index 10066104..aec028a4 100644 --- a/src/prepare.c +++ b/src/prepare.c @@ -480,10 +480,12 @@ static zend_class_entry* pmmpthread_copy_entry(const pmmpthread_ident_t* source, memcpy(&prepared->info.user, &candidate->info.user, sizeof(candidate->info.user)); +#if PHP_MAJOR_VERSION == 8 && PHP_MINOR_VERSION < 4 if ((PMMPTHREAD_ZG(options) & PMMPTHREAD_INHERIT_COMMENTS) && (candidate->info.user.doc_comment)) { prepared->info.user.doc_comment = pmmpthread_copy_string(candidate->info.user.doc_comment); } else prepared->info.user.doc_comment = NULL; +#endif if (candidate->attributes) { prepared->attributes = pmmpthread_copy_attributes(source, candidate->attributes, prepared->info.user.filename); diff --git a/src/store.c b/src/store.c index 20e15495..f2a4267f 100644 --- a/src/store.c +++ b/src/store.c @@ -58,7 +58,11 @@ void pmmpthread_store_destroy(pmmpthread_store_t* store) { /* {{{ Prepares local property table to cache items. We may use integer keys, so the ht must be explicitly initialized to avoid zend allocating it as packed, which will cause assert failures. */ static void pmmpthread_store_init_local_properties(zend_object* object) { +#if PHP_MAJOR_VERSION == 8 && PHP_MINOR_VERSION >= 4 + rebuild_object_properties_internal(object); +#else rebuild_object_properties(object); +#endif if (HT_FLAGS(object->properties) & HASH_FLAG_UNINITIALIZED) { zend_hash_real_init_mixed(object->properties); } @@ -143,7 +147,7 @@ static inline zend_bool pmmpthread_store_retain_in_local_cache(zval* val) { } static inline zend_bool pmmpthread_store_valid_local_cache_item(zval* val) { - //rebuild_object_properties() may add IS_INDIRECT zvals to point to the linear property table + //rebuild_object_properties_internal() may add IS_INDIRECT zvals to point to the linear property table //we don't want that, because they aren't used by pmmpthread and are always uninitialized return Z_TYPE_P(val) != IS_INDIRECT; } From 63335fccd717987928f524b892cd4ee4c9f0a708 Mon Sep 17 00:00:00 2001 From: Akmal Fairuz <35138228+AkmalFairuz@users.noreply.github.com> Date: Sun, 17 Nov 2024 20:24:11 +0700 Subject: [PATCH 02/25] Use zend_std_get_properties_ex instead rebuild_object_properties --- src/handlers.c | 2 +- src/store.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/handlers.c b/src/handlers.c index 2485ffae..5cfa40e7 100644 --- a/src/handlers.c +++ b/src/handlers.c @@ -49,7 +49,7 @@ HashTable* pmmpthread_read_properties(PMMPTHREAD_READ_PROPERTIES_PASSTHRU_D) { pmmpthread_zend_object_t* threaded = PMMPTHREAD_FETCH_FROM(object); #if PHP_MAJOR_VERSION == 8 && PHP_MINOR_VERSION >= 4 - rebuild_object_properties_internal(&threaded->std); + zend_std_get_properties_ex(&threaded->std); #else rebuild_object_properties(&threaded->std); #endif diff --git a/src/store.c b/src/store.c index f2a4267f..53382505 100644 --- a/src/store.c +++ b/src/store.c @@ -59,7 +59,7 @@ void pmmpthread_store_destroy(pmmpthread_store_t* store) { We may use integer keys, so the ht must be explicitly initialized to avoid zend allocating it as packed, which will cause assert failures. */ static void pmmpthread_store_init_local_properties(zend_object* object) { #if PHP_MAJOR_VERSION == 8 && PHP_MINOR_VERSION >= 4 - rebuild_object_properties_internal(object); + zend_std_get_properties_ex(object); #else rebuild_object_properties(object); #endif @@ -147,7 +147,7 @@ static inline zend_bool pmmpthread_store_retain_in_local_cache(zval* val) { } static inline zend_bool pmmpthread_store_valid_local_cache_item(zval* val) { - //rebuild_object_properties_internal() may add IS_INDIRECT zvals to point to the linear property table + //zend_std_get_properties_ex() may add IS_INDIRECT zvals to point to the linear property table //we don't want that, because they aren't used by pmmpthread and are always uninitialized return Z_TYPE_P(val) != IS_INDIRECT; } From 963a51c563dd15eba0c2118e45d240545ae3b132 Mon Sep 17 00:00:00 2001 From: Akmal Fairuz <35138228+AkmalFairuz@users.noreply.github.com> Date: Sun, 17 Nov 2024 20:51:19 +0700 Subject: [PATCH 03/25] Use PHP_VERSION_ID --- src/handlers.c | 2 +- src/prepare.c | 2 +- src/store.c | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/handlers.c b/src/handlers.c index 5cfa40e7..3ffbf1ea 100644 --- a/src/handlers.c +++ b/src/handlers.c @@ -48,7 +48,7 @@ HashTable* pmmpthread_read_debug(PMMPTHREAD_READ_DEBUG_PASSTHRU_D) { HashTable* pmmpthread_read_properties(PMMPTHREAD_READ_PROPERTIES_PASSTHRU_D) { pmmpthread_zend_object_t* threaded = PMMPTHREAD_FETCH_FROM(object); -#if PHP_MAJOR_VERSION == 8 && PHP_MINOR_VERSION >= 4 +#if PHP_VERSION_ID >= 80400 zend_std_get_properties_ex(&threaded->std); #else rebuild_object_properties(&threaded->std); diff --git a/src/prepare.c b/src/prepare.c index aec028a4..ce4da521 100644 --- a/src/prepare.c +++ b/src/prepare.c @@ -480,7 +480,7 @@ static zend_class_entry* pmmpthread_copy_entry(const pmmpthread_ident_t* source, memcpy(&prepared->info.user, &candidate->info.user, sizeof(candidate->info.user)); -#if PHP_MAJOR_VERSION == 8 && PHP_MINOR_VERSION < 4 +#if PHP_VERSION_ID < 80400 if ((PMMPTHREAD_ZG(options) & PMMPTHREAD_INHERIT_COMMENTS) && (candidate->info.user.doc_comment)) { prepared->info.user.doc_comment = pmmpthread_copy_string(candidate->info.user.doc_comment); diff --git a/src/store.c b/src/store.c index 53382505..c5a6dbe2 100644 --- a/src/store.c +++ b/src/store.c @@ -58,7 +58,7 @@ void pmmpthread_store_destroy(pmmpthread_store_t* store) { /* {{{ Prepares local property table to cache items. We may use integer keys, so the ht must be explicitly initialized to avoid zend allocating it as packed, which will cause assert failures. */ static void pmmpthread_store_init_local_properties(zend_object* object) { -#if PHP_MAJOR_VERSION == 8 && PHP_MINOR_VERSION >= 4 +#if PHP_VERSION_ID >= 80400 zend_std_get_properties_ex(object); #else rebuild_object_properties(object); From bfb4e6807c499e3035d08b50938407bd520cfbb6 Mon Sep 17 00:00:00 2001 From: Akmal Fairuz <35138228+AkmalFairuz@users.noreply.github.com> Date: Mon, 18 Nov 2024 01:26:45 +0700 Subject: [PATCH 04/25] Use zend_class_entry->doc_comment --- src/prepare.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/prepare.c b/src/prepare.c index ce4da521..c4fa4b15 100644 --- a/src/prepare.c +++ b/src/prepare.c @@ -480,12 +480,10 @@ static zend_class_entry* pmmpthread_copy_entry(const pmmpthread_ident_t* source, memcpy(&prepared->info.user, &candidate->info.user, sizeof(candidate->info.user)); -#if PHP_VERSION_ID < 80400 if ((PMMPTHREAD_ZG(options) & PMMPTHREAD_INHERIT_COMMENTS) && - (candidate->info.user.doc_comment)) { - prepared->info.user.doc_comment = pmmpthread_copy_string(candidate->info.user.doc_comment); - } else prepared->info.user.doc_comment = NULL; -#endif + (candidate->doc_comment)) { + prepared->doc_comment = pmmpthread_copy_string(candidate->doc_comment); + } else prepared->doc_comment = NULL; if (candidate->attributes) { prepared->attributes = pmmpthread_copy_attributes(source, candidate->attributes, prepared->info.user.filename); From c740635536b82ffce5bfa084d812234934d752d5 Mon Sep 17 00:00:00 2001 From: Akmal Fairuz <35138228+AkmalFairuz@users.noreply.github.com> Date: Mon, 18 Nov 2024 01:31:59 +0700 Subject: [PATCH 05/25] forgot to add backward compability --- src/prepare.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/prepare.c b/src/prepare.c index c4fa4b15..bbc842a5 100644 --- a/src/prepare.c +++ b/src/prepare.c @@ -479,11 +479,16 @@ static zend_class_entry* pmmpthread_copy_entry(const pmmpthread_ident_t* source, prepared->refcount = 1; memcpy(&prepared->info.user, &candidate->info.user, sizeof(candidate->info.user)); - if ((PMMPTHREAD_ZG(options) & PMMPTHREAD_INHERIT_COMMENTS) && +#if PHP_VERSION_ID >= 80400 (candidate->doc_comment)) { prepared->doc_comment = pmmpthread_copy_string(candidate->doc_comment); } else prepared->doc_comment = NULL; +#else + (candidate->info.user.doc_comment)) { + prepared->info.user.doc_comment = pmmpthread_copy_string(candidate->info.user.doc_comment); + } else prepared->info.user.doc_comment = NULL; +#endif if (candidate->attributes) { prepared->attributes = pmmpthread_copy_attributes(source, candidate->attributes, prepared->info.user.filename); From a0ad42725119790a6dc105608f5c7d59dbfa3a80 Mon Sep 17 00:00:00 2001 From: Akmal Fairuz <35138228+AkmalFairuz@users.noreply.github.com> Date: Mon, 18 Nov 2024 02:23:38 +0700 Subject: [PATCH 06/25] Add PHP 8.4 to .github/workflows/main.yml & appveyor.yml --- .github/workflows/main.yml | 1 + appveyor.yml | 9 ++++++++- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 86327cbc..1daa261f 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -15,6 +15,7 @@ jobs: - 8.1.26 - 8.2.13 - 8.3.0 + - 8.4.0beta5 uses: ./.github/workflows/main-php-matrix.yml with: diff --git a/appveyor.yml b/appveyor.yml index 22656abc..9ab29bda 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -10,10 +10,17 @@ environment: PHP_VER: 8.1 VC_VER: vs16 VCVARS_VER: "" + PHP_STABILITY: stable - ARCH: x64 PHP_VER: 8.2 VC_VER: vs16 VCVARS_VER: "" + PHP_STABILITY: stable + - ARCH: x64 + PHP_VER: 8.4 + VC_VER: vs16 + VCVARS_VER: "" + PHP_STABILITY: staging install: - cmd: cinst wget @@ -35,7 +42,7 @@ build_script: xcopy C:\projects\pmmpthread C:\projects\php-src\ext\pmmpthread /s /e /y /q - phpsdk_deps -u -t %VC_VER% -b %PHP_VER% -a %ARCH% -f -d C:\projects\php-src\deps + phpsdk_deps -u -t %VC_VER% -b %PHP_VER% -s %PHP_STABILITY% -a %ARCH% -f -d C:\projects\php-src\deps wget http://www.mirrorservice.org/sites/sources.redhat.com/pub/pthreads-win32/pthreads-w32-2-9-1-release.zip -q From 705449ce34286e6b9327b9c5331745b8210c5ca2 Mon Sep 17 00:00:00 2001 From: AkmalFairuz Date: Mon, 18 Nov 2024 10:58:49 +0700 Subject: [PATCH 07/25] Update CI & Use PHP 8.4.0RC4 for linux CI --- .github/workflows/main.yml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 64eca23b..d7fdd364 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -15,7 +15,7 @@ jobs: - 8.1.26 - 8.2.13 - 8.3.0 - - 8.4.0beta5 + - 8.4.0RC4 uses: ./.github/workflows/main-php-matrix.yml with: @@ -34,6 +34,9 @@ jobs: vs-crt: vs16 - php: 8.3 vs-crt: vs16 + - php: 8.4 + vs-crt: vs16 + build-type: staging uses: ./.github/workflows/main-php-matrix-windows.yml with: From 0b0713cfb6ddcfc1501d774008d9555053d56d55 Mon Sep 17 00:00:00 2001 From: AkmalFairuz Date: Mon, 18 Nov 2024 11:04:05 +0700 Subject: [PATCH 08/25] Fix CI: pass build-type --- .github/workflows/main.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index d7fdd364..a98b041a 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -42,4 +42,5 @@ jobs: with: php: ${{ matrix.php }} vs-crt: ${{ matrix.vs-crt }} + build-type: ${{ matrix.build-type }} secrets: inherit From 7e8635e13628586bfe6e4dd3fad71344f3ffc43f Mon Sep 17 00:00:00 2001 From: AkmalFairuz Date: Mon, 18 Nov 2024 11:07:50 +0700 Subject: [PATCH 09/25] Fix CI: use default build-type value when not defined --- .github/workflows/main.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index a98b041a..46eea85f 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -42,5 +42,5 @@ jobs: with: php: ${{ matrix.php }} vs-crt: ${{ matrix.vs-crt }} - build-type: ${{ matrix.build-type }} + build-type: ${{ matrix.build-type || inputs.build-type }} secrets: inherit From 0f8e2c7f0a2f7fa34aae75c7fbe25ad4686e5ee6 Mon Sep 17 00:00:00 2001 From: AkmalFairuz Date: Mon, 18 Nov 2024 11:10:36 +0700 Subject: [PATCH 10/25] Fix CI: explicitly use the 'stable' build-type in the matrix --- .github/workflows/main.yml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 46eea85f..23142dad 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -30,10 +30,13 @@ jobs: include: - php: 8.1 vs-crt: vs16 + build-type: stable - php: 8.2 vs-crt: vs16 + build-type: stable - php: 8.3 vs-crt: vs16 + build-type: stable - php: 8.4 vs-crt: vs16 build-type: staging @@ -42,5 +45,5 @@ jobs: with: php: ${{ matrix.php }} vs-crt: ${{ matrix.vs-crt }} - build-type: ${{ matrix.build-type || inputs.build-type }} + build-type: ${{ matrix.build-type }} secrets: inherit From 6ff891a8bb3632317f8f84fbdcbc3eca4d1b8020 Mon Sep 17 00:00:00 2001 From: Akmal Fairuz <35138228+AkmalFairuz@users.noreply.github.com> Date: Mon, 18 Nov 2024 16:14:11 +0700 Subject: [PATCH 11/25] Use vs17 to build PHP 8.4 for Windows --- .github/workflows/main.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 23142dad..29ad33b8 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -38,7 +38,7 @@ jobs: vs-crt: vs16 build-type: stable - php: 8.4 - vs-crt: vs16 + vs-crt: vs17 build-type: staging uses: ./.github/workflows/main-php-matrix-windows.yml From 9078f0a43bb4ab762d41f283a83f199f4a053c56 Mon Sep 17 00:00:00 2001 From: Akmal Fairuz <35138228+AkmalFairuz@users.noreply.github.com> Date: Mon, 18 Nov 2024 16:30:25 +0700 Subject: [PATCH 12/25] Bump PHP_SDK_BINARY_TOOLS_VER --- .github/workflows/main-php-matrix-windows.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/main-php-matrix-windows.yml b/.github/workflows/main-php-matrix-windows.yml index 7e158649..76d61db5 100644 --- a/.github/workflows/main-php-matrix-windows.yml +++ b/.github/workflows/main-php-matrix-windows.yml @@ -21,7 +21,7 @@ on: default: stable env: - PHP_SDK_BINARY_TOOLS_VER: 2.2.0 + PHP_SDK_BINARY_TOOLS_VER: 2.3.0 PTHREAD_W32_VER: 3.0.0 jobs: From f3319813834c6a6af40761be46703e95af077653 Mon Sep 17 00:00:00 2001 From: "Dylan T." Date: Mon, 18 Nov 2024 20:09:17 +0000 Subject: [PATCH 13/25] Update main.yml --- .github/workflows/main.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 43d88e1a..62e1b4c9 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -35,7 +35,7 @@ jobs: - php: 8.3.13 vs-crt: vs16 - php: 8.40RC4 - vs-crt: vs17 + vs-crt: vs16 #should be vs17 but deps aren't available yet uses: ./.github/workflows/main-php-matrix-windows.yml with: From f278aebb03754deefd630b6f4ba9f66f228b1338 Mon Sep 17 00:00:00 2001 From: "Dylan T." Date: Mon, 18 Nov 2024 20:09:39 +0000 Subject: [PATCH 14/25] Update main.yml --- .github/workflows/main.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 62e1b4c9..66c3b157 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -41,5 +41,4 @@ jobs: with: php: ${{ matrix.php }} vs-crt: ${{ matrix.vs-crt }} - build-type: ${{ matrix.build-type }} secrets: inherit From 20ecb751d7a6ef3345fd2aeb934eaf408fd384d3 Mon Sep 17 00:00:00 2001 From: "Dylan T." Date: Mon, 18 Nov 2024 20:11:23 +0000 Subject: [PATCH 15/25] Update main.yml --- .github/workflows/main.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 66c3b157..6e62d785 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -34,7 +34,7 @@ jobs: vs-crt: vs16 - php: 8.3.13 vs-crt: vs16 - - php: 8.40RC4 + - php: 8.4.0RC4 vs-crt: vs16 #should be vs17 but deps aren't available yet uses: ./.github/workflows/main-php-matrix-windows.yml From 31eaa98f80fe61580ec60dc76e9ebfef3067275d Mon Sep 17 00:00:00 2001 From: "Dylan T." Date: Mon, 18 Nov 2024 20:25:40 +0000 Subject: [PATCH 16/25] this *is* the correct crt, cryptic errors will be the death of me --- .github/workflows/main.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 6e62d785..60192018 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -35,7 +35,7 @@ jobs: - php: 8.3.13 vs-crt: vs16 - php: 8.4.0RC4 - vs-crt: vs16 #should be vs17 but deps aren't available yet + vs-crt: vs17 uses: ./.github/workflows/main-php-matrix-windows.yml with: From e8f1a6ddeacbea9e69418aa03c1bb27537c15088 Mon Sep 17 00:00:00 2001 From: "Dylan T." Date: Mon, 18 Nov 2024 20:33:42 +0000 Subject: [PATCH 17/25] Update main.yml --- .github/workflows/main.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 60192018..d7b7ca3a 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -36,6 +36,7 @@ jobs: vs-crt: vs16 - php: 8.4.0RC4 vs-crt: vs17 + runs-on: windows-2022 #duct tape until we can get vs16 on 2022 image uses: ./.github/workflows/main-php-matrix-windows.yml with: From f0893603e2cd881796a036151483468257b75a6e Mon Sep 17 00:00:00 2001 From: "Dylan T." Date: Mon, 18 Nov 2024 20:40:02 +0000 Subject: [PATCH 18/25] i hate devops with a passion --- .github/workflows/main.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index d7b7ca3a..202d35e8 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -30,10 +30,13 @@ jobs: include: - php: 8.1.30 vs-crt: vs16 + runs-on: windows-2019 - php: 8.2.25 vs-crt: vs16 + runs-on: windows-2019 - php: 8.3.13 vs-crt: vs16 + runs-on: windows-2019 - php: 8.4.0RC4 vs-crt: vs17 runs-on: windows-2022 #duct tape until we can get vs16 on 2022 image @@ -42,4 +45,5 @@ jobs: with: php: ${{ matrix.php }} vs-crt: ${{ matrix.vs-crt }} + runs-on: ${{ matrix.runs-on }} secrets: inherit From 333989a6d7df56042213339fda4a5921bd67e21f Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Sun, 12 Jan 2025 17:57:10 +0000 Subject: [PATCH 19/25] Fix test expectations for PHP 8.4 --- tests/closure-ts-this.phpt | 4 ++-- tests/closure-with-use-wrapped.phpt | 6 +++--- tests/lexical-vars.phpt | 2 +- tests/new-in-attributes.phpt | 10 +++++----- tests/readonly-properties.phpt | 6 +++--- tests/var-dump-consistency.phpt | 8 ++++---- 6 files changed, 18 insertions(+), 18 deletions(-) diff --git a/tests/closure-ts-this.phpt b/tests/closure-ts-this.phpt index 60d96642..324f8e2d 100644 --- a/tests/closure-ts-this.phpt +++ b/tests/closure-ts-this.phpt @@ -29,8 +29,8 @@ $thread->start(\pmmp\thread\Thread::INHERIT_ALL); $thread->join(); ?> ---EXPECT-- -object(Closure)#4 (1) { +--EXPECTF-- +object(Closure)#4 (%d) {%A ["this"]=> object(A)#3 (0) { } diff --git a/tests/closure-with-use-wrapped.phpt b/tests/closure-with-use-wrapped.phpt index aabb2680..ee68c9c5 100644 --- a/tests/closure-with-use-wrapped.phpt +++ b/tests/closure-with-use-wrapped.phpt @@ -40,10 +40,10 @@ $closureWithUse = static function () use ($test): void{ }; wrap($closureWithUse, $worker); ?> ---EXPECT-- -object(Closure)#4 (0) { +--EXPECTF-- +object(Closure)#4 (%d) {%A } -object(Closure)#7 (1) { +object(Closure)#7 (%d) {%A ["static"]=> array(1) { ["test"]=> diff --git a/tests/lexical-vars.phpt b/tests/lexical-vars.phpt index 694ee04b..d9543e2d 100644 --- a/tests/lexical-vars.phpt +++ b/tests/lexical-vars.phpt @@ -51,7 +51,7 @@ string(5) "thing" NULL object(pmmp\thread\ThreadSafeArray)#3 (0) { } -object(Closure)#4 (0) { +object(Closure)#4 (%d) {%A } array(5) { [0]=> diff --git a/tests/new-in-attributes.phpt b/tests/new-in-attributes.phpt index 81bd9452..5ee3737b 100644 --- a/tests/new-in-attributes.phpt +++ b/tests/new-in-attributes.phpt @@ -28,20 +28,20 @@ $w->start(\pmmp\thread\Thread::INHERIT_ALL) && $w->join(); test(); ?> ---EXPECT-- +--EXPECTF-- array(1) { [0]=> - object(Attr)#4 (1) { + object(Attr)#%d (1) { ["object"]=> - object(stdClass)#6 (0) { + object(stdClass)#%d (0) { } } } array(1) { [0]=> - object(Attr)#4 (1) { + object(Attr)#%d (1) { ["object"]=> - object(stdClass)#6 (0) { + object(stdClass)#%d (0) { } } } diff --git a/tests/readonly-properties.phpt b/tests/readonly-properties.phpt index 0d5543ae..7e8f26fd 100644 --- a/tests/readonly-properties.phpt +++ b/tests/readonly-properties.phpt @@ -41,10 +41,10 @@ $t->start(\pmmp\thread\Thread::INHERIT_ALL) && $t->join(); test(); ?> ---EXPECT-- +--EXPECTF-- int(1) string(40) "Cannot modify readonly property Test::$a" -string(62) "Cannot initialize readonly property Test::$b from global scope" +string(%d) "Cannot %s readonly property Test::$b from global scope" int(1) string(40) "Cannot modify readonly property Test::$a" -string(62) "Cannot initialize readonly property Test::$b from global scope" +string(%d) "Cannot %s readonly property Test::$b from global scope" diff --git a/tests/var-dump-consistency.phpt b/tests/var-dump-consistency.phpt index 6ba6027f..2c85b6ad 100644 --- a/tests/var-dump-consistency.phpt +++ b/tests/var-dump-consistency.phpt @@ -13,18 +13,18 @@ var_dump($t["sock"]); var_dump($t); ?> ---EXPECT-- +--EXPECTF-- object(stdClass)#4 (0) { } object(pmmp\thread\ThreadSafeArray)#2 (1) { ["sock"]=> - object(Closure)#3 (0) { + object(Closure)#3 (%d) {%A } } -object(Closure)#3 (0) { +object(Closure)#3 (%d) {%A } object(pmmp\thread\ThreadSafeArray)#2 (1) { ["sock"]=> - object(Closure)#3 (0) { + object(Closure)#3 (%d) {%A } } From 3d9d71453ce45aa87ab6c7114d01ddaee19cfd7f Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Sun, 12 Jan 2025 18:06:48 +0000 Subject: [PATCH 20/25] copy: account for IS_UNDEF literals these never appeared prior to 8.4, but show up now because of https://github.com/php/php-src/commit/1e7aac315ef1 During finalization of rope compilation, previously used literal slots may become unused and get turned into IS_UNDEF. --- src/copy.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/copy.c b/src/copy.c index b8b4243d..79560eda 100644 --- a/src/copy.c +++ b/src/copy.c @@ -351,7 +351,13 @@ static zval* pmmpthread_copy_literals(const pmmpthread_ident_t* owner, zval *old memcpy(memory, old, sizeof(zval) * last); while (literal < end) { - if (pmmpthread_copy_zval(owner, literal, old_literal) == FAILURE) { + if (Z_TYPE_P(old_literal) == IS_UNDEF) { + /* + * Literals may have unused holes in 8.4 due to compiler optimizations + * See https://github.com/php/php-src/commit/1e7aac315ef1 (zend_compile_rope_finalize) + */ + ZVAL_UNDEF(literal); + } else if (pmmpthread_copy_zval(owner, literal, old_literal) == FAILURE) { zend_error_at_noreturn( E_CORE_ERROR, filename, From 5b20bac44f7d5f64420ccb3cc15a60f6dee0a424 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Sun, 12 Jan 2025 18:16:14 +0000 Subject: [PATCH 21/25] copy: ZEND_JMP_FRAMELESS also needs jump addresses updating on copy --- src/copy.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/copy.c b/src/copy.c index 79560eda..080888c5 100644 --- a/src/copy.c +++ b/src/copy.c @@ -443,6 +443,9 @@ static zend_op* pmmpthread_copy_opcodes(zend_op_array *op_array, zval *literals, case ZEND_JMP_NULL: #if PHP_VERSION_ID >= 80300 case ZEND_BIND_INIT_STATIC_OR_JMP: +#endif +#if PHP_VERSION_ID >= 80400 + case ZEND_JMP_FRAMELESS: #endif opline->op2.jmp_addr = ©[opline->op2.jmp_addr - op_array->opcodes]; break; From 7becfbff1bc8003db310210eeabef2e073e58817 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Sun, 12 Jan 2025 19:57:02 +0000 Subject: [PATCH 22/25] Barely-tested support for property hooks on copied classes --- src/prepare.c | 96 +++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 71 insertions(+), 25 deletions(-) diff --git a/src/prepare.c b/src/prepare.c index bbc842a5..25c561b4 100644 --- a/src/prepare.c +++ b/src/prepare.c @@ -182,40 +182,80 @@ static void prepare_class_function_table(const pmmpthread_ident_t* source, zend_ } ZEND_HASH_FOREACH_END(); } /* }}} */ -/* {{{ */ -static void prepare_class_property_table(const pmmpthread_ident_t* source, zend_class_entry *candidate, zend_class_entry *prepared) { +static zend_property_info* copy_property_info( + const pmmpthread_ident_t* source, + const zend_class_entry *candidate, + zend_class_entry *prepared, + const zend_property_info* info +) { + zend_property_info* dup = zend_hash_index_find_ptr(&PMMPTHREAD_ZG(resolve), (zend_ulong)info); + if (dup) { + return dup; + } - zend_property_info *info; - zend_string *name; - ZEND_HASH_FOREACH_STR_KEY_PTR(&candidate->properties_info, name, info) { - zend_property_info *dup; + if (info->ce->type == ZEND_INTERNAL_CLASS) { + dup = pemalloc(sizeof(zend_property_info), 1); + } + else { + dup = zend_arena_alloc(&CG(arena), sizeof(zend_property_info)); + } + memcpy(dup, info, sizeof(zend_property_info)); - if (info->ce->type == ZEND_INTERNAL_CLASS) { - dup = pemalloc(sizeof(zend_property_info), 1); - } else { - dup = zend_arena_alloc(&CG(arena), sizeof(zend_property_info)); - } - memcpy(dup, info, sizeof(zend_property_info)); + zend_hash_index_update_ptr(&PMMPTHREAD_ZG(resolve), (zend_ulong)info, dup); - dup->name = pmmpthread_copy_string(info->name); - if (info->doc_comment) { - if (PMMPTHREAD_ZG(options) & PMMPTHREAD_INHERIT_COMMENTS) { - dup->doc_comment = pmmpthread_copy_string(info->doc_comment); - } else dup->doc_comment = NULL; + dup->name = pmmpthread_copy_string(info->name); + if (info->doc_comment) { + if (PMMPTHREAD_ZG(options) & PMMPTHREAD_INHERIT_COMMENTS) { + dup->doc_comment = pmmpthread_copy_string(info->doc_comment); } + else dup->doc_comment = NULL; + } - if (info->ce) { - if (info->ce == candidate) { - dup->ce = prepared; - } else dup->ce = pmmpthread_prepared_entry(source, info->ce); + if (info->ce) { + if (info->ce == candidate) { + dup->ce = prepared; } + else dup->ce = pmmpthread_prepared_entry(source, info->ce); + } + + pmmpthread_copy_zend_type(&info->type, &dup->type); - pmmpthread_copy_zend_type(&info->type, &dup->type); + if (info->attributes) { + dup->attributes = pmmpthread_copy_attributes(source, info->attributes, info->ce->type == ZEND_INTERNAL_CLASS ? NULL : info->ce->info.user.filename); + } - if (info->attributes) { - dup->attributes = pmmpthread_copy_attributes(source, info->attributes, info->ce->type == ZEND_INTERNAL_CLASS ? NULL : info->ce->info.user.filename); +#if PHP_VERSION_ID >= 80400 + if (info->prototype) { + dup->prototype = copy_property_info(source, candidate, prepared, info->prototype); + } else dup->prototype = NULL; + + if (info->hooks) { + dup->hooks = zend_arena_alloc(&CG(arena), ZEND_PROPERTY_HOOK_STRUCT_SIZE); + for (uint32_t i = 0; i < ZEND_PROPERTY_HOOK_COUNT; i++) { + if (info->hooks[i]) { + const zend_function* original_hook = info->hooks[i]; + zend_function* copy_hook = pmmpthread_copy_function(source, original_hook); + + if (original_hook->type == ZEND_USER_FUNCTION) { + ZEND_ASSERT(original_hook->op_array.prop_info); + copy_hook->op_array.prop_info = copy_property_info(source, candidate, prepared, info->hooks[i]->op_array.prop_info); + } + + dup->hooks[i] = copy_hook; + } else dup->hooks[i] = NULL; } + } else dup->hooks = NULL; +#endif + return dup; +} +/* {{{ */ +static void prepare_class_property_table(const pmmpthread_ident_t* source, zend_class_entry *candidate, zend_class_entry *prepared) { + + zend_property_info *info; + zend_string *name; + ZEND_HASH_FOREACH_STR_KEY_PTR(&candidate->properties_info, name, info) { + zend_property_info* dup = copy_property_info(source, candidate, prepared, info); if (!zend_hash_str_add_ptr(&prepared->properties_info, name->val, name->len, dup)) { if (dup->doc_comment) zend_string_release(dup->doc_comment); @@ -257,7 +297,11 @@ static void prepare_class_property_table(const pmmpthread_ident_t* source, zend_ } ZEND_HASH_FOREACH_PTR(&prepared->properties_info, info) { - if (info->ce == prepared && (info->flags & ZEND_ACC_STATIC) == 0) { + if (info->ce == prepared && (info->flags & ZEND_ACC_STATIC) == 0 +#if PHP_VERSION_ID >= 80400 + && (info->flags & ZEND_ACC_VIRTUAL) == 0 +#endif + ) { prepared->properties_info_table[OBJ_PROP_TO_NUM(info->offset)] = info; } } ZEND_HASH_FOREACH_END(); @@ -484,6 +528,8 @@ static zend_class_entry* pmmpthread_copy_entry(const pmmpthread_ident_t* source, (candidate->doc_comment)) { prepared->doc_comment = pmmpthread_copy_string(candidate->doc_comment); } else prepared->doc_comment = NULL; + prepared->num_hooked_props = candidate->num_hooked_props; + prepared->num_hooked_prop_variance_checks = candidate->num_hooked_prop_variance_checks; #else (candidate->info.user.doc_comment)) { prepared->info.user.doc_comment = pmmpthread_copy_string(candidate->info.user.doc_comment); From 92ebc57d0b3d81828c1b8d1ab570a7b5a4bfb5a9 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Sun, 12 Jan 2025 19:57:20 +0000 Subject: [PATCH 23/25] and a barely-there test --- tests/property-hooks.phpt | 106 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 106 insertions(+) create mode 100644 tests/property-hooks.phpt diff --git a/tests/property-hooks.phpt b/tests/property-hooks.phpt new file mode 100644 index 00000000..3d5fe2c1 --- /dev/null +++ b/tests/property-hooks.phpt @@ -0,0 +1,106 @@ +--TEST-- +Test that PHP 8.4 property read/write hooks work as expected on copied classes +--SKIPIF-- + +--FILE-- + $this->virtualBackingAsymmetric + 1; + //can't be set because it's not backed + } + + public int $virtualOnlySet { + //do NOT use an arrow function for this - it will make the property non-virtual + //thanks for the new footgun PHP!!! + set { $this->virtualBackingAsymmetric = $value - 1; } + } + + private int $virtualBacking = 0; + + public int $virtualReadWrite { + get => $this->virtualBacking + 1; + set => $this->virtualBacking = $value - 1; + } + + public int $backedOnlyGet { + get => $this->backedOnlyGet + 1; + //set will use default property write behaviour + } + + public int $backedOnlySet { + set => $value + 1; + } + + public int $backedGetSet { + get => $this->backedGetSet + 1; + set => $value - 1; + } +} + +function test(PropertyHooks $object) : void{ + var_dump($object); + + try{ + $object->virtualOnlyGet = 1; //error + echo "Something is wrong, this is not supposed to be writable\n"; + }catch(\Error $e){ + echo $e->getMessage() . "\n"; + } + + //TODO: test more stuff +} + +echo "--- main thread test ---\n"; +test(new PropertyHooks()); +echo "--- main thread done ---\n"; + +$t = new class extends \pmmp\thread\Thread{ + public function run() : void{ + echo "--- child thread test ---\n"; + test(new PropertyHooks()); + echo "--- child thread done ---\n"; + } +}; +$t->start(\pmmp\thread\Thread::INHERIT_ALL) && $t->join(); +echo "done\n"; +--EXPECTF-- +--- main thread test --- +object(PropertyHooks)#%d (2) { + ["virtualBackingAsymmetric":"PropertyHooks":private]=> + int(0) + ["virtualBacking":"PropertyHooks":private]=> + int(0) + ["virtualReadWrite"]=> + uninitialized(int) + ["backedOnlyGet"]=> + uninitialized(int) + ["backedOnlySet"]=> + uninitialized(int) + ["backedGetSet"]=> + uninitialized(int) +} +Property PropertyHooks::$virtualOnlyGet is read-only +--- main thread done --- +--- child thread test --- +object(PropertyHooks)#%d (2) { + ["virtualBackingAsymmetric":"PropertyHooks":private]=> + int(0) + ["virtualBacking":"PropertyHooks":private]=> + int(0) + ["virtualReadWrite"]=> + uninitialized(int) + ["backedOnlyGet"]=> + uninitialized(int) + ["backedOnlySet"]=> + uninitialized(int) + ["backedGetSet"]=> + uninitialized(int) +} +Property PropertyHooks::$virtualOnlyGet is read-only +--- child thread done --- +done From c70f21767588c9b28871c917d156d8fc6a320ad6 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Mon, 13 Jan 2025 13:46:59 +0000 Subject: [PATCH 24/25] prepare: don't bother making another property info copy if it already exists fo classes that were unlinked during first copy, we might've already copied the relevant property info to the destination thread. In this case in the past, this would just silently fail to insert the updated property info and go on to free it. We probably ought to get rid of the old property_info and replace it with the newly copied version, but for now this restores the original behaviour, which seemed to work anyway??? However, possible that this may break with property hooks inheritance. Needs further testing. --- src/prepare.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/src/prepare.c b/src/prepare.c index 25c561b4..847d7930 100644 --- a/src/prepare.c +++ b/src/prepare.c @@ -255,10 +255,15 @@ static void prepare_class_property_table(const pmmpthread_ident_t* source, zend_ zend_property_info *info; zend_string *name; ZEND_HASH_FOREACH_STR_KEY_PTR(&candidate->properties_info, name, info) { - zend_property_info* dup = copy_property_info(source, candidate, prepared, info); - if (!zend_hash_str_add_ptr(&prepared->properties_info, name->val, name->len, dup)) { - if (dup->doc_comment) - zend_string_release(dup->doc_comment); + zend_property_info* dup = zend_hash_find_ptr(&prepared->properties_info, name); + //TODO: if this is non-null it may need updating (if we copied it previously for an unlinked class) + //for now this just ensures that we don't have UAFs with reused property infos + //hopefully this doesn't shit a brick??? + if (dup == NULL) { + dup = copy_property_info(source, candidate, prepared, info); + if (!zend_hash_str_add_ptr(&prepared->properties_info, name->val, name->len, dup)) { + ZEND_ASSERT(0); + } } } ZEND_HASH_FOREACH_END(); From 2d0d49f381f58769e8a2c3bc1e4fd4efbaa228a2 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Mon, 13 Jan 2025 16:49:48 +0000 Subject: [PATCH 25/25] Deal with ZEND_ACC_VIRTUAL properties consistently --- src/handlers.c | 8 ++++---- src/object.c | 2 +- src/pmmpthread.h | 6 ++++++ src/prepare.c | 6 +----- src/store.c | 2 +- 5 files changed, 13 insertions(+), 11 deletions(-) diff --git a/src/handlers.c b/src/handlers.c index 3ffbf1ea..2d06bc47 100644 --- a/src/handlers.c +++ b/src/handlers.c @@ -93,7 +93,7 @@ zval* pmmpthread_read_property(PMMPTHREAD_READ_PROPERTY_PASSTHRU_D) { zend_property_info* info = zend_get_property_info(object->ce, member, 0); if (info == ZEND_WRONG_PROPERTY_INFO) { rv = &EG(uninitialized_zval); - } else if (info == NULL || (info->flags & ZEND_ACC_STATIC) != 0) { //dynamic property + } else if (info == NULL || !PMMPTHREAD_OBJECT_PROPERTY(info)) { //dynamic property if (pmmpthread_store_read(object, &zmember, type, rv) == FAILURE) { if (type != BP_VAR_IS) { zend_error(E_WARNING, "Undefined property: %s::$%s", ZSTR_VAL(object->ce->name), ZSTR_VAL(member)); @@ -161,7 +161,7 @@ zval* pmmpthread_write_property(PMMPTHREAD_WRITE_PROPERTY_PASSTHRU_D) { bool ok = true; zend_property_info* info = zend_get_property_info(object->ce, member, 0); if (info != ZEND_WRONG_PROPERTY_INFO) { - if (info != NULL && (info->flags & ZEND_ACC_STATIC) == 0) { + if (info != NULL && PMMPTHREAD_OBJECT_PROPERTY(info)) { ZVAL_STR(&zmember, info->name); //use mangled name to avoid private member shadowing issues zend_execute_data* execute_data = EG(current_execute_data); @@ -232,7 +232,7 @@ int pmmpthread_has_property(PMMPTHREAD_HAS_PROPERTY_PASSTHRU_D) { } else { zend_property_info* info = zend_get_property_info(object->ce, member, 1); if (info != ZEND_WRONG_PROPERTY_INFO) { - if (info != NULL && (info->flags & ZEND_ACC_STATIC) == 0) { + if (info != NULL && PMMPTHREAD_OBJECT_PROPERTY(info)) { ZVAL_STR(&zmember, info->name); //defined property, use mangled name } isset = pmmpthread_store_isset(object, &zmember, has_set_exists); @@ -272,7 +272,7 @@ void pmmpthread_unset_property(PMMPTHREAD_UNSET_PROPERTY_PASSTHRU_D) { } else { zend_property_info* info = zend_get_property_info(object->ce, member, 0); if (info != ZEND_WRONG_PROPERTY_INFO) { - if (info != NULL && (info->flags & ZEND_ACC_STATIC) == 0) { + if (info != NULL && PMMPTHREAD_OBJECT_PROPERTY(info)) { ZVAL_STR(&zmember, info->name); //defined property, use mangled name } pmmpthread_store_delete(object, &zmember); diff --git a/src/object.c b/src/object.c index c1288586..0b9dac98 100644 --- a/src/object.c +++ b/src/object.c @@ -248,7 +248,7 @@ static inline void pmmpthread_base_write_property_defaults(pmmpthread_zend_objec zval* value; int result; - if (info->flags & ZEND_ACC_STATIC) { + if (!PMMPTHREAD_OBJECT_PROPERTY(info)) { continue; } diff --git a/src/pmmpthread.h b/src/pmmpthread.h index 33c9f1ed..840238f9 100644 --- a/src/pmmpthread.h +++ b/src/pmmpthread.h @@ -163,6 +163,12 @@ typedef struct _pmmpthread_call_t { #define PMMPTHREAD_CALL_EMPTY {empty_fcall_info, empty_fcall_info_cache} +#if PHP_VERSION_ID >= 80400 +#define PMMPTHREAD_OBJECT_PROPERTY(prop_info) ((prop_info->flags & (ZEND_ACC_STATIC | ZEND_ACC_VIRTUAL)) == 0) +#else +#define PMMPTHREAD_OBJECT_PROPERTY(prop_info) ((prop_info->flags & ZEND_ACC_STATIC) == 0) +#endif + /* this is a copy of the same struct in zend_closures.c, which unfortunately isn't exported */ typedef struct _zend_closure { zend_object std; diff --git a/src/prepare.c b/src/prepare.c index 847d7930..96b5200b 100644 --- a/src/prepare.c +++ b/src/prepare.c @@ -302,11 +302,7 @@ static void prepare_class_property_table(const pmmpthread_ident_t* source, zend_ } ZEND_HASH_FOREACH_PTR(&prepared->properties_info, info) { - if (info->ce == prepared && (info->flags & ZEND_ACC_STATIC) == 0 -#if PHP_VERSION_ID >= 80400 - && (info->flags & ZEND_ACC_VIRTUAL) == 0 -#endif - ) { + if (info->ce == prepared && PMMPTHREAD_OBJECT_PROPERTY(info)) { prepared->properties_info_table[OBJ_PROP_TO_NUM(info->offset)] = info; } } ZEND_HASH_FOREACH_END(); diff --git a/src/store.c b/src/store.c index c5a6dbe2..002501c2 100644 --- a/src/store.c +++ b/src/store.c @@ -835,7 +835,7 @@ void pmmpthread_store_tohash(zend_object *object, HashTable *hash) { for (int i = 0; i < object->ce->default_properties_count; i++) { zend_property_info* info = object->ce->properties_info_table[i]; - if (info == NULL || (info->flags & ZEND_ACC_STATIC) != 0) { + if (info == NULL || !PMMPTHREAD_OBJECT_PROPERTY(info)) { continue; }