magic property guards are not reset in timeout
Dieses Issue hat noch niemand übernommen.
- Vorherrschende Sprache
- C
- Sterne
- 40.4k
- Forks
- 8.1k
- Ø Merge
- 2 T. 13 Std.
- Gemergte PRs (30 T.)
- 96
Beschreibung
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
Beitragsleitfaden
Erste Schritte
- Lies das ganze Issue und danach den Beitragsleitfaden des Projekts.
- Schreib ins Issue, dass du es übernimmst — das erspart doppelte Arbeit.
- Forke das Repository und arbeite in einem Branch.
- Öffne einen Pull Request, der die Issue-Nummer nennt.
Rechercherichtung
Beginnen Sie mit der Property-Guard-Logik in Zend/zend_object_handlers.c an den referenzierten Zeilen und verfolgen Sie anschließend zend_interrupt_helper und ZEND_VM_INTERRUPT für die Timeout-Behandlung. Verwenden Sie die bereitgestellte PHP-Reproduktion, um das Shutdown-Verhalten zu beobachten; abgeschlossen ist die Aufgabe, wenn ein Timeout innerhalb von __get() den Guard nicht aktiv lässt und der Shutdown-Handler das erwartete Ergebnis der Property-Suche ohne die Warnung über eine undefinierte Property erzeugt.
Vom Indexierungsmodell aus dem Issue-Text verfasst.
Bewertung
- Tech-Stack
- c
- Bereich
- backend
- Issue-Typ
- Bug
- Schwierigkeit
- 4/5
- Geschätzter Aufwand
- 3-5 Tage
- Aktivitätsstatus
- Ruhig
- Klarheit
- Größtenteils klar
- Anfängerfreundlichkeit
- 45/100