magic property guards are not reset in timeout
Personne n'a encore pris cette issue.
- Langage dominant
- C
- Étoiles
- 40.4k
- Forks
- 8.1k
- Merge moyen
- 2 j 13 h
- PR mergées (30 j)
- 96
Description
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
Guide de contribution
Ouvrir le guide de contribution
Par où commencer
- Lisez l'issue en entier, puis le guide de contribution du projet.
- Signalez en commentaire que vous la prenez — cela évite que deux personnes fassent le même travail.
- Forkez le dépôt et travaillez sur une branche.
- Ouvrez une pull request qui référence le numéro de l'issue.
Piste de recherche
Commencez par la logique de garde des propriétés dans Zend/zend_object_handlers.c aux lignes indiquées, puis suivez zend_interrupt_helper et ZEND_VM_INTERRUPT pour la gestion du timeout. Utilisez la reproduction PHP fournie pour observer le comportement lors de l’arrêt ; le travail est terminé lorsqu’un timeout dans __get() ne laisse pas la garde active et que le gestionnaire d’arrêt produit le résultat attendu de la recherche de propriété sans l’avertissement de propriété indéfinie.
Rédigé par le modèle d'indexation à partir du texte de l'issue.
Évaluation
- Stack technique
- c
- Domaine
- backend
- Type d'issue
- Bug
- Difficulté
- 4/5
- Temps estimé
- 3-5 jours
- Activité
- Calme
- Clarté
- Plutôt claire
- Accessibilité débutants
- 45/100