Page MenuHomePhabricator

Reports that class constants aren't resolved properly by autoloader in php 8.4
Closed, ResolvedPublicBUG REPORT

Description

There are reports that AbuseFilter is causing problems when running command line maintenance scripts under php 8.4 on MW 1.39. The reporter said php8.4 is fine on the web server, but on maintenance scripts (according to them all maintenance scripts) they get the following error:

[2f84f4a83c06cb6b9e7051a6] [no req]   Error: Class "MediaWiki\Extension\AbuseFilter\Parser\RuleCheckerFactory" not found
Backtrace:
from /var/www/html/w/extensions/AbuseFilter/includes/ServiceWiring.php(113)
#0 /var/www/html/w/vendor/wikimedia/services/src/ServiceContainer.php(124): require()
#1 /var/www/html/w/includes/MediaWikiServices.php(447): Wikimedia\Services\ServiceContainer->loadWiringFiles()
#2 /var/www/html/w/includes/MediaWikiServices.php(285): MediaWiki\MediaWikiServices::newInstance()
#3 /var/www/html/w/includes/Hooks.php(174): MediaWiki\MediaWikiServices::getInstance()
#4 /var/www/html/w/includes/exception/MWExceptionHandler.php(807): Hooks::runner()
#5 /var/www/html/w/includes/exception/MWExceptionHandler.php(336): MWExceptionHandler::logError()
#6 /var/www/html/w/includes/AutoLoader.php(244): MWExceptionHandler::handleError()
#7 /var/www/html/w/includes/AutoLoader.php(244): require(string)
#8 /var/www/html/w/extensions/AbuseFilter/includes/ServiceWiring.php(113): AutoLoader::autoload()
#9 /var/www/html/w/vendor/wikimedia/services/src/ServiceContainer.php(124): require(string)
#10 /var/www/html/w/includes/MediaWikiServices.php(447): Wikimedia\Services\ServiceContainer->loadWiringFiles()
#11 /var/www/html/w/includes/MediaWikiServices.php(285): MediaWiki\MediaWikiServices::newInstance()
#12 /var/www/html/w/includes/Setup.php(322): MediaWiki\MediaWikiServices::getInstance()
#13 /var/www/html/w/maintenance/doMaintenance.php(83): require_once(string)
#14 /var/www/html/w/extensions/CirrusSearch/maintenance/UpdateSearchIndexConfig.php(117): require_once(string)
#15 {main}

[They confirmed that the file and class exists when manually loaded with require]

They said they were running php8.4RC3. They said the issue immediately went away after downgrading to php8.2

Its possible that this is something specific to their setup, but i think its worth doing some extra testing of php 8.4 to see if we can reproduce it, just in case.

Original report: https://www.mediawiki.org/wiki/Topic:Yg6g78li1kxvioai https://discord.com/channels/178359708581625856/1306735828776779869

Event Timeline

I reproduce similar error with AbuseFilter but also with multiple other extensions (all with php84 and MediaWiki alpha).

CirrusSearch: Error: Class "CirrusSearch\Profile\SearchProfileServiceFactory" not found.
CampaignsEvent: Error: Class "MediaWiki\Extension\CampaignEvents\Participants\ParticipantsStore" not found

Then similar stack traces follow. In all cases, the exception happens in service wiring file when creating service callback.

The pattern that emerges here is that they're using a class constant (which requires autoload) to resolve the service name instead of string literal. It seems a lot of extensions are doing this.

Core service wiring file seems to exclusively use string literal currently.

Bawolff renamed this task from Reports of AbuseFilter incompatible with php 8.4 when running maintenance scripts to Reports that class constants aren't resolved properly by autoloader in php 8.4.Nov 21 2024, 5:40 PM

There are two usages of class constant for service name.
In AbuseFilter each Service class has a class constant with the name of that service. Wikibase has one class with constants for all services.
In case of AbuseFilter the load of the ServiceWiring.php triggers autoload of each service class to get the constant. Loading namespaced classes is not cheap, as there is no lookup table in extensions to do that cheap (core has one), and this autoload read many files, some are not used later on. But all should be in opcache and not a big deal to load (just to find). So not sure if this is relevant.

Maybe php8.4 has reached a limit (ulimit?) on open file handle and cannot load more files, but that indicate a bug on closing the autoloaded files.

Sometimes files are not found on beta as well (T371507)

This is because that class used to trigger deprecations:

Deprecated: MediaWiki\Extension\AbuseFilter\Parser\RuleCheckerFactory::newRuleChecker(): Implicitly marking parameter $vars as nullable is deprecated, the explicit nullable type must be used instead in /var/www/html/mediawiki/extensions/AbuseFilter/includes/Parser/RuleCheckerFactory.php on line 75

The class gets loaded eagerly by the $wgHooks assignment in Setup.php which is what first initializes the service container. The deprecation is logged when the class is autoloaded during container init, which causes the exception handler to invoke callLogExceptionHook, which then tries to initialize the service container once again and fails due to an autoload loop.

We should probably just avoid trying to access the container here if it hasn't been setup already.

Change #1112229 had a related patch set uploaded (by Máté Szabó; author: Máté Szabó):

[mediawiki/core@master] exception: Avoid service container init in exception handler

https://gerrit.wikimedia.org/r/1112229

Change #1112229 merged by jenkins-bot:

[mediawiki/core@master] exception: Avoid service container init in exception handler

https://gerrit.wikimedia.org/r/1112229

Ammarpad assigned this task to mszabo.

Change #1164628 had a related patch set uploaded (by Reedy; author: Máté Szabó):

[mediawiki/core@REL1_43] exception: Avoid service container init in exception handler

https://gerrit.wikimedia.org/r/1164628

Change #1164628 merged by jenkins-bot:

[mediawiki/core@REL1_43] exception: Avoid service container init in exception handler

https://gerrit.wikimedia.org/r/1164628

Change #1172409 had a related patch set uploaded (by Reedy; author: Máté Szabó):

[mediawiki/core@REL1_39] exception: Avoid service container init in exception handler

https://gerrit.wikimedia.org/r/1172409

Change #1172409 merged by jenkins-bot:

[mediawiki/core@REL1_39] exception: Avoid service container init in exception handler

https://gerrit.wikimedia.org/r/1172409