Page MenuHomePhabricator

PHP Deprecated: preg_replace(): Passing null to parameter #3 ($subject) of type array|string is deprecated
Closed, ResolvedPublicPRODUCTION ERROR

Description

Error
normalized_message
[{reqId}] {exception_url}   PHP Deprecated: preg_replace(): Passing null to parameter #3 ($subject) of type array|string is deprecated
FrameLocationCall
from/srv/mediawiki/php-1.44.0-wmf.24/includes/libs/rdbms/database/QueryBuilderFromRawSql.php(202)
#0[internal function]MediaWiki\Exception\MWExceptionHandler::handleError(int, string, string, int)
#1/srv/mediawiki/php-1.44.0-wmf.24/includes/libs/rdbms/database/QueryBuilderFromRawSql.php(202)preg_replace(string, string, null)
#2/srv/mediawiki/php-1.44.0-wmf.24/includes/libs/rdbms/database/utils/GeneralizedSql.php(56)Wikimedia\Rdbms\QueryBuilderFromRawSql::generalizeSQL(null)
#3/srv/mediawiki/php-1.44.0-wmf.24/includes/libs/rdbms/TransactionProfiler.php(572)Wikimedia\Rdbms\GeneralizedSql->stringify()
#4/srv/mediawiki/php-1.44.0-wmf.24/includes/libs/rdbms/TransactionProfiler.php(557)Wikimedia\Rdbms\TransactionProfiler->getGeneralizedSql(Wikimedia\Rdbms\GeneralizedSql)
#5/srv/mediawiki/php-1.44.0-wmf.24/includes/libs/rdbms/TransactionProfiler.php(351)Wikimedia\Rdbms\TransactionProfiler->reportExpectationViolated(string, Wikimedia\Rdbms\GeneralizedSql, int, string, string)
#6/srv/mediawiki/php-1.44.0-wmf.24/includes/libs/rdbms/database/TransactionManager.php(574)Wikimedia\Rdbms\TransactionProfiler->recordQueryCompletion(Wikimedia\Rdbms\GeneralizedSql, float, bool, int, string, string)
#7/srv/mediawiki/php-1.44.0-wmf.24/includes/libs/rdbms/database/Database.php(858)Wikimedia\Rdbms\TransactionManager->recordQueryCompletion(Wikimedia\Rdbms\GeneralizedSql, float, bool, int, string)
#8/srv/mediawiki/php-1.44.0-wmf.24/includes/libs/rdbms/database/Database.php(711)Wikimedia\Rdbms\Database->attemptQuery(Wikimedia\Rdbms\Query, string, bool)
#9/srv/mediawiki/php-1.44.0-wmf.24/includes/libs/rdbms/database/Database.php(638)Wikimedia\Rdbms\Database->executeQuery(Wikimedia\Rdbms\Query, string, int)
#10/srv/mediawiki/php-1.44.0-wmf.24/includes/libs/rdbms/database/Database.php(1367)Wikimedia\Rdbms\Database->query(Wikimedia\Rdbms\Query, string)
#11/srv/mediawiki/php-1.44.0-wmf.24/includes/libs/rdbms/database/DBConnRef.php(127)Wikimedia\Rdbms\Database->select(array, array, array, string, array, array)
#12/srv/mediawiki/php-1.44.0-wmf.24/includes/libs/rdbms/database/DBConnRef.php(351)Wikimedia\Rdbms\DBConnRef->__call(string, array)
#13/srv/mediawiki/php-1.44.0-wmf.24/includes/libs/rdbms/querybuilder/SelectQueryBuilder.php(762)Wikimedia\Rdbms\DBConnRef->select(array, array, array, string, array, array)
#14/srv/mediawiki/php-1.44.0-wmf.24/includes/user/UserSelectQueryBuilder.php(271)Wikimedia\Rdbms\SelectQueryBuilder->fetchResultSet()
#15[internal function]MediaWiki\User\UserSelectQueryBuilder->fetchUserIdentities()
#16/srv/mediawiki/php-1.44.0-wmf.24/extensions/GrowthExperiments/includes/Mentorship/Store/DatabaseMentorStore.php(134)iterator_to_array(Generator)
#17/srv/mediawiki/php-1.44.0-wmf.24/extensions/GrowthExperiments/includes/MentorDashboard/MenteeOverview/DatabaseMenteeOverviewDataProvider.php(81)GrowthExperiments\Mentorship\Store\DatabaseMentorStore->getMenteesByMentor(MediaWiki\User\User, string)
#18/srv/mediawiki/php-1.44.0-wmf.24/includes/libs/objectcache/WANObjectCache.php(1846)GrowthExperiments\MentorDashboard\MenteeOverview\DatabaseMenteeOverviewDataProvider->GrowthExperiments\MentorDashboard\MenteeOverview\{closure}(array, int, array, float, array)
#19/srv/mediawiki/php-1.44.0-wmf.24/includes/libs/objectcache/WANObjectCache.php(2634)Wikimedia\ObjectCache\WANObjectCache->fetchOrRegenerate(string, int, Closure, array, array)
#20/srv/mediawiki/php-1.44.0-wmf.24/includes/deferred/MWCallableUpdate.php(52)Wikimedia\ObjectCache\WANObjectCache->Wikimedia\ObjectCache\{closure}(string)
#21/srv/mediawiki/php-1.44.0-wmf.24/includes/deferred/DeferredUpdates.php(459)MediaWiki\Deferred\MWCallableUpdate->doUpdate()
#22/srv/mediawiki/php-1.44.0-wmf.24/includes/deferred/DeferredUpdates.php(201)MediaWiki\Deferred\DeferredUpdates::attemptUpdate(MediaWiki\Deferred\MWCallableUpdate)
#23/srv/mediawiki/php-1.44.0-wmf.24/includes/deferred/DeferredUpdates.php(288)MediaWiki\Deferred\DeferredUpdates::run(MediaWiki\Deferred\MWCallableUpdate)
#24/srv/mediawiki/php-1.44.0-wmf.24/includes/deferred/DeferredUpdatesScope.php(243)MediaWiki\Deferred\DeferredUpdates::MediaWiki\Deferred\{closure}(MediaWiki\Deferred\MWCallableUpdate, int)
#25/srv/mediawiki/php-1.44.0-wmf.24/includes/deferred/DeferredUpdatesScope.php(172)MediaWiki\Deferred\DeferredUpdatesScope->processStageQueue(int, int, Closure)
#26/srv/mediawiki/php-1.44.0-wmf.24/includes/deferred/DeferredUpdates.php(307)MediaWiki\Deferred\DeferredUpdatesScope->processUpdates(int, Closure)
#27/srv/mediawiki/php-1.44.0-wmf.24/includes/MediaWikiEntryPoint.php(674)MediaWiki\Deferred\DeferredUpdates::doUpdates()
#28/srv/mediawiki/php-1.44.0-wmf.24/includes/MediaWikiEntryPoint.php(496)MediaWiki\MediaWikiEntryPoint->restInPeace()
#29/srv/mediawiki/php-1.44.0-wmf.24/includes/MediaWikiEntryPoint.php(454)MediaWiki\MediaWikiEntryPoint->doPostOutputShutdown()
#30/srv/mediawiki/php-1.44.0-wmf.24/includes/MediaWikiEntryPoint.php(211)MediaWiki\MediaWikiEntryPoint->postOutputShutdown()
#31/srv/mediawiki/php-1.44.0-wmf.24/rest.php(39)MediaWiki\MediaWikiEntryPoint->run()
#32/srv/mediawiki/w/rest.php(3)require(string)
#33{main}
Impact
Notes

Details

Request URL
https://en.wikipedia.org/w/rest.php/growthexperiments/v0/mentees?limit=*&maxedits=*&minedits=*&offset=*&onlystarred=*&order=*&sortby=*&uselang=*
Related Changes in Gerrit:

Event Timeline

Restricted Application added a subscriber: Aklapper. · View Herald Transcript
Michael moved this task from Backlog to Freezer on the Growth-Team (Maintenance) board.
Michael added subscribers: aaron, BPirkle, HCoplin-WMF.

This is probably not a GrowthExperiments issue. The error occurs in the last preg_replace call of \Wikimedia\Rdbms\QueryBuilderFromRawSql::generalizeSQL:

QueryBuilderFromRawSql.php
	public static function generalizeSQL( $sql ) {
		# This does the same as the regexp below would do, but in such a way
		# as to avoid crashing php on some large strings.
		# $sql = preg_replace( "/'([^\\\\']|\\\\.)*'|\"([^\\\\\"]|\\\\.)*\"/", "'X'", $sql );

		$sql = str_replace( "\\\\", '', $sql );
		$sql = str_replace( "\\'", '', $sql );
		$sql = str_replace( "\\\"", '', $sql );
		$sql = preg_replace( "/'.*'/s", "'X'", $sql );
		$sql = preg_replace( '/".*"/s', "'X'", $sql );

		# All newlines, tabs, etc replaced by single space
		$sql = preg_replace( '/\s+/', ' ', $sql );

		# All numbers => N,
		# except the ones surrounded by characters, e.g. l10n
		$sql = preg_replace( '/-?\d++(,-?\d++)+/', 'N,...,N', $sql );
		$sql = preg_replace( '/(?<![a-zA-Z])-?\d+(?![a-zA-Z])/', 'N', $sql );  // <-- Error Stacktrace is referencing this line

		return $sql;
	}

The error says that the last argument, $sql is null. That means that the previous preg_replace call must have returned null. That line in particular was last changed in rdbms: avoid pcre.backtrack_limit in QueryBuilderFromRawSql::generalizeSQL() for T366640: QueryBuilderFromRawSql::generalizeSQL: PHP Deprecated: preg_replace(): Passing null to parameter #3 ($subject) of type array|string is deprecated. So, I'm adding the respective tags and such.

I'll put this in our freezer because our involvement seems to be incidental. Please let us know if there is actually something wrong on our side here.

Umherirrender subscribed.

QueryBuilderFromRawSqlTest has a test failure to test the regex for a IN clause with 5000 items. That pass, but changing to 9000 makes it fail. That indicates another backtrace issue

Change #1172083 had a related patch set uploaded (by Umherirrender; author: Umherirrender):

[mediawiki/core@master] rdbms: Reduce backtrack on regex for generalizeSQL

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

Change #1172083 merged by jenkins-bot:

[mediawiki/core@master] rdbms: Reduce backtrack on regex for generalizeSQL

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

The root cause – if you want to call it like that – are mentors that have several 1000 mentees. The code actually generates SQL queries with thousands and thousands of distinct user ids in a single WHERE … IN clause.

I wonder if this is really necessary in all the situations where the code currently calls DatabaseMentorStore::getMenteesByMentor?

For example, I found quite a lot of places that drop the returned UserIdentity[] array and use only the user ids. It looks like at least some of these places can be rewritten to use a much cheaper query that returns growthexperiments_mentor_mentee.gemm_mentee_id directly, or possibly an even cheaper COUNT( growthexperiments_mentor_mentee.gemm_mentee_id ). @Michael, what do you think?