php / php/php-src

magic property guards are not reset in timeout

Ouverte
#14,983 13 commentaires 0 réactions 0 personnes assignées Voir sur GitHub

Personne n'a encore pris cette issue.

Bug Category: Engine Status: Needs Triage
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->foo inside of __get() will return null and raise an E_WARNING if there is no foo property 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:

  1. 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

  1. 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

  1. Lisez l'issue en entier, puis le guide de contribution du projet.
  2. Signalez en commentaire que vous la prenez — cela évite que deux personnes fassent le même travail.
  3. Forkez le dépôt et travaillez sur une branche.
  4. 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

Recevez les nouvelles issues par e-mail

Un résumé court des issues GitHub adaptées aux débutants.