Preloading anonymous class inheriting from autoloaded unlinked class leads to return type error
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
Issue
When using PHP-FPM that is, and only starting when the respective code is used the second time.
The following code:
// preload.php
<?php
require __DIR__ . '/Main.php';
// index.php
<?php
require __DIR__ . '/Main.php';
spl_autoload_register(function ($class) {
if ($class === 'SomeType') require __DIR__ . '/SomeType.php';
});
var_dump((new Main)->create());
// Main.php
<?php
class Main {
function create(): SomeType {
return new class extends SomeType {};
}
}
// SomeType.php
<?php
class SomeType {}
# php.ini
opcache.enable=1
opcache.optimization_level=-1
opcache.preload=/var/www/html/preload.php
opcache.preload_user=www-data
Where index.php is called twice
Resulted in this output:
# During preload
Warning: Can't preload unlinked class SomeType@anonymous: Unknown parent SomeType in /var/www/html/Main.php on line 4
# Call 1
object(SomeType@anonymous)#3 (0) { }
# Call 2
Fatal error: Uncaught TypeError: Main::create(): Return value must be of type SomeType, SomeType@anonymous returned in /var/www/html/Main.php:4
Stack trace:
#0 /var/www/html/index.php(7): Main->create()
#1 {main}
thrown in /var/www/html/Main.php on line 4
But I expected this output instead:
# During preload
Warning: Can't preload unlinked class SomeType@anonymous: Unknown parent SomeType in /var/www/html/Main.php on line 4
# Call 1
object(SomeType@anonymous)#3 (0) { }
# Call 2
object(SomeType@anonymous)#3 (0) { }
Reproducing
This can be reproduced by additionally configuring these files
# php-fpm-www.conf
[www]
user=www-data
group=www-data
listen=127.0.0.1:9000
pm=static
pm.max_children=1
# nginx.conf
events {
worker_connections 4096;
}
http {
server {
location ~ \.php$ {
fastcgi_pass php-test:9000;
fastcgi_split_path_info ^(.+?\.php)(/.*)$;
fastcgi_param SCRIPT_FILENAME /var/www/html/$fastcgi_script_name;
include fastcgi_params;
}
}
}
and then running
docker run --rm -it --name php-test -v $(pwd):/var/www/html -v $(pwd)/php-fpm-www.conf:/usr/local/etc/php-fpm.d/www.conf -v $(pwd)/php.ini:/usr/local/etc/php/conf.d/php.ini php:8.1.13-fpm-bullseye bash -c "docker-php-ext-install opcache && php-fpm"
# separately / detached
docker run --rm -it -v $(pwd)/nginx.conf:/etc/nginx/nginx.conf -p 8080:80 --link php-test nginx:1.23.3
curl http://localhost:8080/index.php
curl http://localhost:8080/index.php
Segfaults
Under certain circumstances, this leads to segfaults, but I haven't been able to setup a sharable reproducible case.
Occasionally between segfaults I get errors like these:
Uncaught exception: Class "" not foundUncaught exception: Class "H?" not found
Backtrace from such a segfault:
Core was generated by `php-fpm: pool www '.
Program terminated with signal SIGSEGV, Segmentation fault.
#0 0x00005564d172fe35 in zend_lookup_class_ex (name=0x800000017c9e55d4, key=0x42973350, flags=2560) at /usr/src/php/Zend/zend_execute_API.c:1050
1050 /usr/src/php/Zend/zend_execute_API.c: No such file or directory.
[Current thread is 1 (Thread 0x7f8a9adbe980 (LWP 263))]
(gdb) bt
#0 0x00005564d172fe35 in zend_lookup_class_ex (name=0x800000017c9e55d4, key=0x42973350, flags=2560) at /usr/src/php/Zend/zend_execute_API.c:1050
#1 0x00005564d1731092 in zend_fetch_class_by_name (class_name=0x800000017c9e55d4, key=0x42973350, fetch_type=2560) at /usr/src/php/Zend/zend_execute_API.c:1601
#2 0x00005564d184233d in zend_do_link_class (ce=0x7f8a96404338, lc_parent_name=0x42973350, key=0x42973000) at /usr/src/php/Zend/zend_inheritance.c:2715
#3 0x00005564d178bae1 in ZEND_DECLARE_ANON_CLASS_SPEC_HANDLER () at /usr/src/php/Zend/zend_vm_execute.h:2955
#4 0x00005564d17fcd2c in execute_ex (ex=0x7f8a9aa14020) at /usr/src/php/Zend/zend_vm_execute.h:55863
#5 0x00005564d18014fa in zend_execute (op_array=0x7f8a9aa75140, return_value=0x0) at /usr/src/php/Zend/zend_vm_execute.h:60147
#6 0x00005564d17488dc in zend_execute_scripts (type=8, retval=0x0, file_count=3) at /usr/src/php/Zend/zend.c:1799
#7 0x00005564d169e08b in php_execute_script (primary_file=0x7fff379ad520) at /usr/src/php/main/main.c:2541
#8 0x00005564d18cf2d5 in main (argc=1, argv=0x7fff379ad9a8) at /usr/src/php/sapi/fpm/fpm/fpm_main.c:1914
PHP Version
8.1.13
Operating System
No response
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
Reproduisez le cas de préchargement PHP-FPM avec Main.php, SomeType.php, preload.php et la configuration Docker fournie, puis examinez zend_inheritance.c, zend_execute_API.c et le gestionnaire de classes anonymes dans zend_vm_execute.h. Suivez la deuxième requête et ajoutez un test de régression couvrant le type de retour déclaré, l’exécution répétée et l’avertissement de preload signalé, sans TypeError ni plantage.
Rédigé par le modèle d'indexation à partir du texte de l'issue.
Évaluation
- Stack technique
- php
- Domaine
- backend
- Type d'issue
- Bug
- Difficulté
- 4/5
- Temps estimé
- 3-5 jours
- Activité
- À l'abandon
- Clarté
- Plutôt claire
- Accessibilité débutants
- 35/100