Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: handle short classes in Autoloader #41253

Merged
merged 1 commit into from
May 16, 2024
Merged

Conversation

phil-davis
Copy link
Contributor

@phil-davis phil-davis commented May 13, 2024

Description

See the issue for details of the problem.

If explode does not return enough parts, pad the returned array with empty strings so that the list() will have a big enough array to fill the variables in list().

Related Issue

How Has This Been Tested?

CI

Types of changes

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Database schema changes (next release will require increase of minor version instead of patch)
  • Breaking change (fix or feature that would cause existing functionality to change)
  • Technical debt
  • Tests only (no source changes)

Checklist:

  • Code changes
  • Unit tests added
  • Acceptance tests added
  • Documentation ticket raised:
  • Changelog item, see TEMPLATE

@jvillafanez
Copy link
Member

Do we know which classes are complained about?

If we expect classes with 3 components and somehow we get classes with just 2, either sending any class with 2 components is a bug (and we mustn't use those) or we should handle those classes better.
For the later, note that we'll get paths like appname/.php or appname/lib/.php (with the current fix) which could cause issues down the road

@phil-davis
Copy link
Contributor Author

Do we know which classes are complained about?

No, but I suppose that there are 6 of them, the number of notices reported.

I will try locally to log the ones with the problem and report back...

@phil-davis
Copy link
Contributor Author

@jvillafanez there are 4 different values for $class in calls to findClass($class) that are short:

OCA\Files
OCA\Files_Sharing
OCA\FederatedFileSharing
OCA\Files_Sharing

and I suppose if more apps are enabled, then there could be more similar examples passed in.

@jvillafanez
Copy link
Member

Is it possible to get a stacktrace to know the whole list of calls? I mean, we're trying to load the OCA\Files class, but there is no such class, so why are we trying to load it?

@phil-davis
Copy link
Contributor Author

I think that phpstan is somehow thinking that OCA\Files is a class that could be instantiated.

The call stack has this sort of stuff (sorry,it's long):

OCA\Files
/home/phil/git/owncloud/core/lib/private/Autoloader.php:143
findClass:
Arg value: OCA\Files
phar:///home/phil/git/owncloud/core/vendor-bin/phpstan/vendor/phpstan/phpstan/phpstan.phar/src/Reflection/BetterReflection/SourceLocator/AutoloadFunctionsSourceLocator.php:41
load:
Arg value: OCA\Files
phar:///home/phil/git/owncloud/core/vendor-bin/phpstan/vendor/phpstan/phpstan/phpstan.phar/vendor/ondrejmirtes/better-reflection/src/SourceLocator/Type/AggregateSourceLocator.php:26
locateIdentifier:
Arg is object of classPHPStan\BetterReflection\Reflector\DefaultReflector
Arg is object of classPHPStan\BetterReflection\Identifier\Identifier
phar:///home/phil/git/owncloud/core/vendor-bin/phpstan/vendor/phpstan/phpstan/phpstan.phar/vendor/ondrejmirtes/better-reflection/src/SourceLocator/Type/MemoizingSourceLocator.php:33
locateIdentifier:
Arg is object of classPHPStan\BetterReflection\Reflector\DefaultReflector
Arg is object of classPHPStan\BetterReflection\Identifier\Identifier
phar:///home/phil/git/owncloud/core/vendor-bin/phpstan/vendor/phpstan/phpstan/phpstan.phar/vendor/ondrejmirtes/better-reflection/src/Reflector/DefaultReflector.php:32
locateIdentifier:
Arg is object of classPHPStan\BetterReflection\Reflector\DefaultReflector
Arg is object of classPHPStan\BetterReflection\Identifier\Identifier
phar:///home/phil/git/owncloud/core/vendor-bin/phpstan/vendor/phpstan/phpstan/phpstan.phar/src/Reflection/BetterReflection/Reflector/MemoizingReflector.php:45
reflectClass:
Arg value: OCA\Files
phar:///home/phil/git/owncloud/core/vendor-bin/phpstan/vendor/phpstan/phpstan/phpstan.phar/src/Reflection/BetterReflection/BetterReflectionProvider.php:163
reflectClass:
Arg value: OCA\Files
phar:///home/phil/git/owncloud/core/vendor-bin/phpstan/vendor/phpstan/phpstan/phpstan.phar/src/Reflection/ReflectionProvider/MemoizingReflectionProvider.php:35
hasClass:
Arg value: OCA\Files
phar:///home/phil/git/owncloud/core/vendor-bin/phpstan/vendor/phpstan/phpstan/phpstan.phar/src/Type/Constant/ConstantStringType.php:195
hasClass:
Arg value: OCA\Files
phar:///home/phil/git/owncloud/core/vendor-bin/phpstan/vendor/phpstan/phpstan/phpstan.phar/src/Analyser/NodeScopeResolver.php:3426
isCallable:
phar:///home/phil/git/owncloud/core/vendor-bin/phpstan/vendor/phpstan/phpstan/phpstan.phar/src/Analyser/NodeScopeResolver.php:1985
processArgs:
Arg is object of classPhpParser\Node\Stmt\Expression
Arg is object of classPHPStan\Reflection\ResolvedMethodReflection
Arg is object of classPHPStan\Reflection\Php\PhpMethodReflection
Arg is object of classPHPStan\Reflection\ResolvedFunctionVariantWithOriginal
Arg is an array
Arg is object of classPHPStan\Analyser\MutatingScope
Arg is object of classClosure
Arg is object of classPHPStan\Analyser\ExpressionContext
phar:///home/phil/git/owncloud/core/vendor-bin/phpstan/vendor/phpstan/phpstan/phpstan.phar/src/Analyser/NodeScopeResolver.php:693
processExprNode:
Arg is object of classPhpParser\Node\Stmt\Expression
Arg is object of classPhpParser\Node\Expr\MethodCall
Arg is object of classPHPStan\Analyser\MutatingScope
Arg is object of classClosure
Arg is object of classPHPStan\Analyser\ExpressionContext
phar:///home/phil/git/owncloud/core/vendor-bin/phpstan/vendor/phpstan/phpstan/phpstan.phar/src/Analyser/NodeScopeResolver.php:430
processStmtNode:
Arg is object of classPhpParser\Node\Stmt\Expression
Arg is object of classPHPStan\Analyser\MutatingScope
Arg is object of classClosure
Arg is object of classPHPStan\Analyser\StatementContext
phar:///home/phil/git/owncloud/core/vendor-bin/phpstan/vendor/phpstan/phpstan/phpstan.phar/src/Analyser/NodeScopeResolver.php:632
processStmtNodes:
Arg is object of classPhpParser\Node\Stmt\ClassMethod
Arg is an array
Arg is object of classPHPStan\Analyser\MutatingScope
Arg is object of classClosure
Arg is object of classPHPStan\Analyser\StatementContext
phar:///home/phil/git/owncloud/core/vendor-bin/phpstan/vendor/phpstan/phpstan/phpstan.phar/src/Analyser/NodeScopeResolver.php:430
processStmtNode:
Arg is object of classPhpParser\Node\Stmt\ClassMethod
Arg is object of classPHPStan\Analyser\MutatingScope
Arg is object of classPHPStan\Node\ClassStatementsGatherer
Arg is object of classPHPStan\Analyser\StatementContext
phar:///home/phil/git/owncloud/core/vendor-bin/phpstan/vendor/phpstan/phpstan/phpstan.phar/src/Analyser/NodeScopeResolver.php:743
processStmtNodes:
Arg is object of classPhpParser\Node\Stmt\Class_
Arg is an array
Arg is object of classPHPStan\Analyser\MutatingScope
Arg is object of classPHPStan\Node\ClassStatementsGatherer
Arg is object of classPHPStan\Analyser\StatementContext
phar:///home/phil/git/owncloud/core/vendor-bin/phpstan/vendor/phpstan/phpstan/phpstan.phar/src/Analyser/NodeScopeResolver.php:430
processStmtNode:
Arg is object of classPhpParser\Node\Stmt\Class_
Arg is object of classPHPStan\Analyser\MutatingScope
Arg is object of classClosure
Arg is object of classPHPStan\Analyser\StatementContext
phar:///home/phil/git/owncloud/core/vendor-bin/phpstan/vendor/phpstan/phpstan/phpstan.phar/src/Analyser/NodeScopeResolver.php:713
processStmtNodes:
Arg is object of classPhpParser\Node\Stmt\Namespace_
Arg is an array
Arg is object of classPHPStan\Analyser\MutatingScope
Arg is object of classClosure
Arg is object of classPHPStan\Analyser\StatementContext
phar:///home/phil/git/owncloud/core/vendor-bin/phpstan/vendor/phpstan/phpstan/phpstan.phar/src/Analyser/NodeScopeResolver.php:398
processStmtNode:
Arg is object of classPhpParser\Node\Stmt\Namespace_
Arg is object of classPHPStan\Analyser\MutatingScope
Arg is object of classClosure
Arg is object of classPHPStan\Analyser\StatementContext
phar:///home/phil/git/owncloud/core/vendor-bin/phpstan/vendor/phpstan/phpstan/phpstan.phar/src/Analyser/FileAnalyser.php:179
processNodes:
Arg is an array
Arg is object of classPHPStan\Analyser\MutatingScope
Arg is object of classClosure
phar:///home/phil/git/owncloud/core/vendor-bin/phpstan/vendor/phpstan/phpstan/phpstan.phar/src/Command/WorkerCommand.php:137
analyseFile:
Arg value: /home/phil/git/owncloud/core/apps/files/lib/Controller/ViewController.php
Arg is an array
Arg is object of classPHPStan\Rules\LazyRegistry
Arg is object of classPHPStan\Collectors\Registry
Arg value: 
phar:///home/phil/git/owncloud/core/vendor-bin/phpstan/vendor/phpstan/phpstan/phpstan.phar/vendor/evenement/evenement/src/Evenement/EventEmitterTrait.php:97
PHPStan\Command\{closure}:
Arg is an array
phar:///home/phil/git/owncloud/core/vendor-bin/phpstan/vendor/phpstan/phpstan/phpstan.phar/vendor/clue/ndjson-react/src/Decoder.php:117
emit:
Arg value: data
Arg is an array
phar:///home/phil/git/owncloud/core/vendor-bin/phpstan/vendor/phpstan/phpstan/phpstan.phar/vendor/evenement/evenement/src/Evenement/EventEmitterTrait.php:97
handleData:
Arg is an array
phar:///home/phil/git/owncloud/core/vendor-bin/phpstan/vendor/phpstan/phpstan/phpstan.phar/vendor/react/stream/src/Util.php:62
emit:
Arg value: data
Arg is an array
phar:///home/phil/git/owncloud/core/vendor-bin/phpstan/vendor/phpstan/phpstan/phpstan.phar/vendor/evenement/evenement/src/Evenement/EventEmitterTrait.php:97
_PHPStan_d5a4746e9\React\Stream\{closure}:
Arg value: {"action":"analyse","files":["\/home\/phil\/git\/owncloud\/core\/apps\/files\/download.php","\/home\/phil\/git\/owncloud\/core\/apps\/files\/lib\/Helper.php","\/home\/phil\/git\/owncloud\/core\/apps\/files\/lib\/Controller\/ApiController.php","\/home\/phil\/git\/owncloud\/core\/apps\/files\/lib\/Controller\/ViewController.php","\/home\/phil\/git\/owncloud\/core\/apps\/files\/lib\/BackgroundJob\/CleanupPersistentFileLocks.php","\/home\/phil\/git\/owncloud\/core\/apps\/files\/lib\/BackgroundJob\/PreviewCleanupJob.php","\/home\/phil\/git\/owncloud\/core\/apps\/files\/lib\/BackgroundJob\/CleanupFileLocks.php","\/home\/phil\/git\/owncloud\/core\/apps\/files\/lib\/BackgroundJob\/DeleteOrphanedItems.php","\/home\/phil\/git\/owncloud\/core\/apps\/files\/lib\/BackgroundJob\/ScanFiles.php","\/home\/phil\/git\/owncloud\/core\/apps\/files\/lib\/AppInfo\/Application.php","\/home\/phil\/git\/owncloud\/core\/apps\/files\/lib\/Capabilities.php","\/home\/phil\/git\/owncloud\/core\/apps\/files\/lib\/Activity.php","\/home\/phil\/git\/owncloud\/core\/apps\/files\/lib\/Service\/TagService.php","\/home\/phil\/git\/owncloud\/core\/apps\/files\/lib\/Command\/RemoveStorageCache.php","\/home\/phil\/git\/owncloud\/core\/apps\/files\/lib\/Command\/Scan.php","\/home\/phil\/git\/owncloud\/core\/apps\/files\/lib\/Command\/CheckCache.php","\/home\/phil\/git\/owncloud\/core\/apps\/files\/lib\/Command\/TransferOwnership.php","\/home\/phil\/git\/owncloud\/core\/apps\/files\/lib\/Command\/DeleteOrphanedFiles.php","\/home\/phil\/git\/owncloud\/core\/apps\/files\/lib\/Command\/VerifyChecksums.php","\/home\/phil\/git\/owncloud\/core\/apps\/files\/lib\/Command\/TroubleshootTransferOwnership.php"]}

phar:///home/phil/git/owncloud/core/vendor-bin/phpstan/vendor/phpstan/phpstan/phpstan.phar/vendor/react/stream/src/DuplexResourceStream.php:154
emit:
Arg value: data
Arg is an array
phar:///home/phil/git/owncloud/core/vendor-bin/phpstan/vendor/phpstan/phpstan/phpstan.phar/vendor/react/event-loop/src/StreamSelectLoop.php:201
handleData:
Arg value: Resource id #7115
phar:///home/phil/git/owncloud/core/vendor-bin/phpstan/vendor/phpstan/phpstan/phpstan.phar/vendor/react/event-loop/src/StreamSelectLoop.php:173
waitForStreamActivity:
Arg value: 
phar:///home/phil/git/owncloud/core/vendor-bin/phpstan/vendor/phpstan/phpstan/phpstan.phar/src/Command/WorkerCommand.php:98
run:
phar:///home/phil/git/owncloud/core/vendor-bin/phpstan/vendor/phpstan/phpstan/phpstan.phar/vendor/symfony/console/Command/Command.php:259
execute:
Arg is object of class_PHPStan_d5a4746e9\Symfony\Component\Console\Input\ArgvInput
Arg is object of class_PHPStan_d5a4746e9\Symfony\Component\Console\Output\ConsoleOutput
phar:///home/phil/git/owncloud/core/vendor-bin/phpstan/vendor/phpstan/phpstan/phpstan.phar/vendor/symfony/console/Application.php:870
run:
Arg is object of class_PHPStan_d5a4746e9\Symfony\Component\Console\Input\ArgvInput
Arg is object of class_PHPStan_d5a4746e9\Symfony\Component\Console\Output\ConsoleOutput
phar:///home/phil/git/owncloud/core/vendor-bin/phpstan/vendor/phpstan/phpstan/phpstan.phar/vendor/symfony/console/Application.php:261
doRunCommand:
Arg is object of classPHPStan\Command\WorkerCommand
Arg is object of class_PHPStan_d5a4746e9\Symfony\Component\Console\Input\ArgvInput
Arg is object of class_PHPStan_d5a4746e9\Symfony\Component\Console\Output\ConsoleOutput
phar:///home/phil/git/owncloud/core/vendor-bin/phpstan/vendor/phpstan/phpstan/phpstan.phar/vendor/symfony/console/Application.php:157
doRun:
Arg is object of class_PHPStan_d5a4746e9\Symfony\Component\Console\Input\ArgvInput
Arg is object of class_PHPStan_d5a4746e9\Symfony\Component\Console\Output\ConsoleOutput
phar:///home/phil/git/owncloud/core/vendor-bin/phpstan/vendor/phpstan/phpstan/phpstan.phar/bin/phpstan:124
run:
phar:///home/phil/git/owncloud/core/vendor-bin/phpstan/vendor/phpstan/phpstan/phpstan.phar/bin/phpstan:125
_PHPStan_d5a4746e9\{closure}:
/home/phil/git/owncloud/core/vendor-bin/phpstan/vendor/phpstan/phpstan/phpstan:7
require:
Arg value: phar:///home/phil/git/owncloud/core/vendor-bin/phpstan/vendor/phpstan/phpstan/phpstan.phar/bin/phpstan
/home/phil/git/owncloud/core/vendor-bin/phpstan/vendor/bin/phpstan:115
include:
Arg value: /home/phil/git/owncloud/core/vendor-bin/phpstan/vendor/phpstan/phpstan/phpstan

It starts getting the idea that maybe OCA/Files could be a class:

phar:///home/phil/git/owncloud/core/vendor-bin/phpstan/vendor/phpstan/phpstan/phpstan.phar/src/Type/Constant/ConstantStringType.php:195
hasClass:
Arg value: OCA\Files

And that ends up diving way down into the Autoloader.

I suppose that there is a problem somewhere in all the phpstan Reflection stuff, maybe, where it wrongly thinks that something is (or could be) a real Class.

Now to think what to do next. It's not going to be simple to understand the whole path that phpstan goes through to find all the classes and load them, and then to find the point where something is a little bit wrong.

@jvillafanez
Copy link
Member

I have suspicions on https://github.com/search?q=repo%3Aowncloud%2Fcore%20loadAdditionalScripts&type=code and https://github.com/search?q=repo%3Aowncloud%2Fcore%20remote_shareReceived&type=code

Those are event names, but maybe phpstan is interpreting them as valid / possible methods that could be called. I don't know if it's worthy to change the names of those events to figure out whether that's the issue, because in the end we can't change the names (we could break apps)

Assuming that's basically the problem, we'll probably have to workaround with something similar to this PR. In this case, returning an empty array if there aren't enough components seems a good choice

	list(, $app, $rest) = \explode('\\', $class, 3);
	if ($rest === null) {
		return [];
	}
	$app = \strtolower($app);

We should include a comment to explain the situation because I don't think it's a good solution, but I don't see other viable alternatives

@phil-davis
Copy link
Contributor Author

phil-davis commented May 16, 2024

We should include a comment to explain the situation because I don't think it's a good solution, but I don't see other viable alternatives

Agree. I added code to return early when the problem happens, and a comment (that got quite long!).

Note: we have to adjust the list line anyway, with array_pad, because if the result of explode is too short, then list will emit a "notice" - and we have to avoid the notice.

@jvillafanez please review again.

Copy link

sonarcloud bot commented May 16, 2024

@phil-davis phil-davis merged commit 5417e28 into master May 16, 2024
3 checks passed
@delete-merged-branch delete-merged-branch bot deleted the fix-autoloader-findClass branch May 16, 2024 10:34
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

phpstan 1.11.0 is reporting Undefined offset
2 participants