ReflectionProperty::skipLazyInitialization() copies invalid constant defaults with OPcache
Chưa có ai nhận issue này.
Đánh giá
- Độ khó
- 3/5
- Thời gian dự kiến
- 1-2 ngày
- Mức phù hợp với người mới
- 78/100
Hướng nghiên cứu
Start in ext/reflection/php_reflection.c at ReflectionProperty::skipLazyInitialization(), then review the supplied PHPT regression test and the CE_DEFAULT_PROPERTIES_TABLE() handling described in the issue. Run the regression test with OPcache enabled; done means the class-constant default produces string(3) "EUR" and the related reflection and lazy-object tests remain passing.
Do mô hình lập chỉ mục viết ra từ nội dung của issue.
Mô tả
Description
AI assistance disclosure: this report was prepared with an LLM. The reproduction commands, source build, candidate patch, and test results below were executed and checked.
ReflectionProperty::skipLazyInitialization()gives a typed property an invalid value when its default refers to a class constant and shared-memory OPcache is enabled. This reproduces without Doctrine, Composer, autoloading, a database, or application code.Reproduced on PHP 8.4.21 and on a clean build of the official PHP 8.4.25 release archive (Linux aarch64, NTS).
Minimal reproduction
Save as
repro.php(run from a file, notphp -r):<?php class Currency { public const string EUR = 'EUR'; } class Product { public string $currency = Currency::EUR; public function getCurrency(): string { return $this->currency; } } $reflection = new ReflectionClass(Product::class); $product = $reflection->newLazyGhost(static function (Product $product): void {}); $reflection->getProperty('currency')->skipLazyInitialization($product); var_dump($product->getCurrency());With OPcache loaded, run:
php -d opcache.enable=1 -d opcache.enable_cli=1 \ -d opcache.file_cache_only=0 -d opcache.file_cache= \ -d opcache.preload= -d opcache.file_update_protection=0 \ -d opcache.optimization_level=0 \ -d opcache.jit=off -d opcache.jit_buffer_size=0 repro.phpExpected:
string(3) "EUR"Actual (both tested versions):
Fatal error: Uncaught TypeError: Product::getCurrency(): Return value must be of type string, int|float returnedRemoving
-d opcache.optimization_level=0producesUNKNOWN:0fromvar_dump()instead, with exit status 0, on both versions. JIT is disabled in both cases. No disk cache is required to reproduce the defect.Controls
On unmodified PHP 8.4.25, disabling CLI OPcache or enabling disk-only OPcache with a valid writable cache directory returns the expected
string(3) "EUR".On PHP 8.4.21, replacing
Currency::EURwith the literal'EUR'also passes with shared-memory OPcache. So does replacingskipLazyInitialization()with:$property = $reflection->getProperty('currency'); $property->setRawValueWithoutLazyInitialization($product, $property->getDefaultValue());Candidate fix and validation
In
ext/reflection/php_reflection.c,skipLazyInitialization()readsce->default_properties_tabledirectly.CE_DEFAULT_PROPERTIES_TABLE()accounts for the resolved defaults held in the class's mutable data under OPcache. The following one-line change fixes the reproduction with both the disabled and default optimizer in the local PHP 8.4.25 build:--- a/ext/reflection/php_reflection.c +++ b/ext/reflection/php_reflection.c @@ -6461,7 +6461,7 @@ RETURN_THROWS(); } - zval *src = &object->ce->default_properties_table[OBJ_PROP_TO_NUM(prop->offset)]; + zval *src = &CE_DEFAULT_PROPERTIES_TABLE(object->ce)[OBJ_PROP_TO_NUM(prop->offset)]; zval *dst = OBJ_PROP(object, prop->offset); if (!(Z_PROP_FLAG_P(dst) & IS_PROP_LAZY)) {The PHPT below fails before this change and passes afterward. Running it together with
Zend/tests/lazy_objectsandext/reflection/testson the patched build produced 729 passed, 14 skipped, 0 failed, 0 warned (743 tests total). This is local validation on PHP 8.4.25/aarch64; other architectures and PHP 8.5 were not tested.PHPT regression test
--TEST-- skipLazyInitialization() preserves a class-constant property default with OPcache --EXTENSIONS-- opcache --INI-- opcache.enable=1 opcache.enable_cli=1 opcache.file_cache_only=0 opcache.file_cache= opcache.optimization_level=0 opcache.file_update_protection=0 opcache.jit_buffer_size=0 --FILE-- <?php class Currency { public const string EUR = 'EUR'; } class Product { public string $currency = Currency::EUR; public function getCurrency(): string { return $this->currency; } } $reflection = new ReflectionClass(Product::class); $product = $reflection->newLazyGhost(static function (Product $product): void {}); $reflection->getProperty('currency')->skipLazyInitialization($product); var_dump($product->getCurrency()); --EXPECT-- string(3) "EUR"
PHP Version
PHP 8.4.25 (cli) (built: Sep 22 2026 10:44:45) (NTS)
Copyright (c) The PHP Group
Zend Engine v4.4.25, Copyright (c) Zend Technologies
with Zend OPcache v8.4.25, Copyright (c), by Zend Technologies
Also reproduced on PHP 8.4.21 (NTS), Zend OPcache v8.4.21.
Operating System
Alpine Linux 3.23.4, Linux aarch64 (Docker)
- Ngôn ngữ chính
- C
- Star
- 40.4k
- Fork
- 8.2k
- Merge trung bình
- 2 ngày 17 giờ
- Pull request đã merge (30 ngày)
- 115
Hướng dẫn đóng góp
Bắt đầu từ đâu
- Đọc hết issue, rồi đọc hướng dẫn đóng góp của dự án.
- Bình luận trên issue rằng bạn sẽ nhận — tránh hai người làm cùng một việc.
- Fork repository và làm thay đổi trên một nhánh.
- Mở pull request có tham chiếu số hiệu của issue.
Issue khác của php/php-src
-
Bug Status: Needs Triage
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 76/100
-
Bug Status: Needs Triage
Độ khó 1/5 Dưới một giờ Mức phù hợp với người mới 90/100
-
Bug Status: Needs Triage
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 78/100
-
Flaky hrtime.phpt test Đang mởBug Category: Tests Status: Verified
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 68/100
-
Bug SAPI: fpm Status: Needs Triage
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 65/100
Issue tương tự
-
bug
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 75/100
bradcypert/plum#53 ·
-
Component: GLib
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 70/100
-
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 75/100
-
Status: Opened
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 70/100
-
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 75/100
nextbsd/nextbsd-userland#285 ·