magic property guards are not reset in timeout
Chưa có ai nhận issue này.
- Ngôn ngữ chính
- C
- Star
- 40.4k
- Fork
- 8.1k
- Merge trung bình
- 2 ngày 13 giờ
- Pull request đã merge (30 ngày)
- 96
Mô tả
Description
The overloaded methods are protected via property guards flags from circular calls. An example is at https://github.com/php/php-src/blob/0f398a437e401fc1abf2a23196918ba1ccb5d8c5/Zend/zend_object_handlers.c#L724-L726
However, these guards are not reset when a timeout happens within the overloaded method. We will get undefined property warnings in the shutdown handlers as a result. This is because PHP still thinks we are inside the __get method
From https://www.php.net/manual/en/language.oop5.overloading.php#object.get:
PHP will not call an overloaded method from within the same overloaded method. That means, for example, writing
return $this->fooinside of __get() will returnnulland raise anE_WARNINGif there is nofooproperty defined, rather than calling __get() a second time. However, overload methods may invoke other overload methods implicitly (such as __set() triggering __get()).
However, I believe that we are no longer inside the __get call when we are in the shutdown handlers and we should allow further __get calls to work.
Here's a repro script (https://3v4l.org/DhXZH) :
<?php
ini_set('max_execution_time', 1);
set_error_handler(null, E_ALL);
class A {
function __get($name) {
return $name;
}
}
global $a;
$a = new A;
function shutdown() {
global $a;
// Warning: Undefined property: A::$foo ...
var_dump($a->foo);
}
register_shutdown_function('shutdown');
// Try to trigger "Fatal error: Maximum execution time of 1 second exceeded"
// within the A::__get() method.
for ($i = 0; $i < 100000000; $i++) {
$a->foo;
}
And the possible outputs are:
- The timeout is triggered outside of the __get call (A
Fatal error: Maximum execution time of 1 second exceeded in /home/itse/development/Etsyweb/ivantestcase.php on line 26
string(3) "foo"
or
- The timeout is triggered within the __get call:
Fatal error: Maximum execution time of 1 second exceeded in /home/itse/development/Etsyweb/ivantestcase.php on line 9
Warning: Undefined property: A::$foo in /home/itse/development/Etsyweb/ivantestcase.php on line 18
NULL
I expect output 1 no matter when the timeout occurs. Output 2 shouldn't occur.
I attempted to dig into the source code for a fix. Perhaps in the zend_interrupt_helper that gets called from ZEND_VM_INTERRUPT, we can look at the call frames and reset the property guards? I'm not too familiar with PHP Virtual Machine so I am not sure if this is the correct approach.
https://github.com/php/php-src/compare/f58a3c392f4fc0ce2f82935399c5e6e64441e2e9...ivantsepp:php-src:61e0b6293829a508884de388f99ab093be9e4563?expand=1
Let me know if this is a bug that should be addressed and I would appreciate any pointers on what a potential fix might look like! I am interested in working on a fix if so.
PHP Version
PHP 8.4.0-dev
Operating System
macOS 13.6
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.
Hướng nghiên cứu
Bắt đầu với logic bảo vệ thuộc tính trong Zend/zend_object_handlers.c tại các dòng được tham chiếu, sau đó lần theo zend_interrupt_helper và ZEND_VM_INTERRUPT để xử lý timeout. Sử dụng bản tái hiện PHP được cung cấp để quan sát hành vi shutdown; công việc được hoàn tất khi một timeout bên trong __get() không để guard ở trạng thái active và trình xử lý shutdown tạo ra kết quả tra cứu thuộc tính như mong đợi mà không có cảnh báo thuộc tính không được định nghĩa.
Do mô hình lập chỉ mục viết ra từ nội dung của issue.
Đánh giá
- Công nghệ
- c
- Lĩnh vực
- backend
- Loại issue
- Lỗi
- Độ khó
- 4/5
- Thời gian dự kiến
- 3-5 ngày
- Mức độ hoạt động
- Ít trao đổi
- Độ rõ ràng
- Khá rõ ràng
- Mức phù hợp với người mới
- 45/100