magic property guards are not reset in timeout
Nadie ha tomado este issue todavía.
- 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->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
Guía de contribución
Primeros pasos
- Lee el issue completo y luego la guía de contribución del proyecto.
- Comenta en el issue que vas a ocuparte — evita que dos personas hagan lo mismo.
- Haz un fork del repositorio y trabaja en una rama.
- 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