php / php/php-src

magic property guards are not reset in timeout

Abierto
#14,983 13 comentarios 0 reacciones 0 asignados Ver en GitHub

Nadie ha tomado este issue todavía.

Bug Category: Engine Status: Needs Triage
Lenguaje dominante
C
Estrellas
40.4k
Forks
8.2k
Merge medio
2 d 13 h
PR fusionados (30 d)
96

Descripción

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

Guía de contribución

Abrir la guía de contribución

Primeros pasos

  1. Lee el issue completo y luego la guía de contribución del proyecto.
  2. Comenta en el issue que vas a ocuparte — evita que dos personas hagan lo mismo.
  3. Haz un fork del repositorio y trabaja en una rama.
  4. Abre un pull request que haga referencia al número del issue.

Línea de trabajo

Comienza con la lógica de protección de propiedades en Zend/zend_object_handlers.c en las líneas indicadas y luego sigue zend_interrupt_helper y ZEND_VM_INTERRUPT para el manejo del timeout. Usa la reproducción de PHP proporcionada para observar el comportamiento del apagado; se considera terminado cuando un timeout dentro de __get() no deja activo el guard y el manejador de apagado produce el resultado esperado de la búsqueda de la propiedad sin la advertencia de propiedad indefinida.

Escrito por el modelo de indexación a partir del texto del issue.

Evaluación

Stack tecnológico
c
Área
backend
Tipo de issue
Error
Dificultad
4/5
Tiempo estimado
3-5 días
Estado de actividad
Tranquilo
Claridad
Bastante claro
Aptitud para principiantes
45/100

Recibe los nuevos issues en tu correo

Un resumen breve de issues de GitHub para principiantes.