Problem/Motivation
When enabling my custom module that implements core access policy API, enabling the module via drush causes all site processes to hang. What is really interesting, is that this only occurs when using $account->hasPermission function inside of my alterPermissions.
Interestingly, the code seemed to work just fine when I added the permission check after the module was already installed.
I have not checked whether the same occurs from calculatePermissions yet.
Visiting the website in browser, after trying this many times, there is a WSOD and memory exhaustion errors, which tend to look like:
Fatal error: Allowed memory size of 1073741824 bytes exhausted (tried to allocate 20480 bytes) in /var/www/html/web/core/lib/Drupal/Core/Session/CalculatedPermissionsItem.php on line 30
Fatal error: Allowed memory size of 1073741824 bytes exhausted (tried to allocate 20480 bytes) in /var/www/html/web/core/lib/Drupal/Core/Database/Connection.php on line 1036
Fatal error: Allowed memory size of 1073741824 bytes exhausted (tried to allocate 32768 bytes) in /var/www/html/web/core/lib/Drupal/Core/Utility/Error.php on line 1
Fatal error: Allowed memory size of 1073741824 bytes exhausted (tried to allocate 20480 bytes) in /var/www/html/web/core/lib/Drupal/Core/Cache/Cache.php on line 29Steps to reproduce
- Create a custom module with a service that extends AccessPolicyBase
- Inside of alterPermissions, use the $account->hasPermission function
- Try to enable the module
Proposed resolution
Document how to check whether an account has a specific permission from inside of custom access policy implementations.
Remaining tasks
- Determine best way to document how to check whether the account has a permission (from inside of an alterPermissions call)
- Create that documentation
User interface changes
Introduced terminology
API changes
Data model changes
Release notes snippet
Issue fork drupal-3612399
Show commands
Start within a Git clone of the project using the version control instructions.
Or, if you do not have SSH keys set up on git.drupalcode.org:
- 3612399-Memory-issues-while-enabling-module
changes, plain diff MR !16391
Comments
Comment #2
aayushpathak commentedworking on it !
Comment #4
aayushpathak commentedOpened a Merge Request to fix the memory exhaustion bug. The issue was caused by an infinite recursion loop when $account->hasPermission() is called from within alterPermissions(). I've added a $processing state tracker to safely short-circuit recursive calls during the calculation phase, along with a dedicated unit test (testRecursiveAccessPolicy) to prevent future regressions. Needs review!
Comment #5
megakeegman commentedThis indeed did fix the issue. I followed the same steps I outlined and was able to install the module without any problem. Thanks!
Comment #6
megakeegman commentedOops sorry, false success. I just realized I had the hasPermission call commented out. I tried again, and am still having the same issue.
Comment #7
megakeegman commentedComment #8
megakeegman commentedSo in my case, the reason I am checking whether the account has a permission is because I only want to alter permissions for users that have not been granted a permission to bypass some restrictions. I am wondering about the possibility that this practice was simply not intended. But this does seem like an entirely reasonable check to make.
Comment #9
megakeegman commentedFrom looking around in code, I am starting to think that this should not be done within an AccessPolicy based class, but rather within an AccessResult based class. I don't understand yet how those class types interact, but will be sure to document here if I learn more. Either way, will be changing my approach and will not be calling hasPermission from alterPermissions anymore.
Comment #10
aayushpathak commentedI re-verified this locally using a test module that reproduces the scenario (calling $account->hasPermission() inside alterPermissions(), then drush en). With the MR patch applied to AccessPolicyProcessor.php, the module installs cleanly — no memory exhaustion or infinite recursion.
The fix tracks in-progress calculations in a $processing array, so recursive calls safely return partial permissions instead of looping.
The "Needs Work" status may have been set before the patch was fully applied in the test environment. Happy to share the test module if useful.
Comment #11
megakeegman commentedYes, you are right. My patch did not properly apply. I tested again and your patch does address the memory issue. I also reviewed the code with @wolcen and the changes seem minor and effective. I am still curious whether there are other intended practices for how to implement these functions, but moving this back to rbtc. Thanks for the fix.
Comment #12
megakeegman commentedI guess one question here. I notice that
$this->processing[$processing_key] = $calculated_permissions;gets called prior to merging policy permissions. I am wondering whether the value in the processing array gets updated with those merged permissions.Comment #13
quietone commentedThis issue does not have the proposed resolution section, which is used by reviewers and committers to understand how the problem is to be fixed. I am tagging for an issue summary. The is related to the Core Documentation Gate. Thanks
Comment #14
kristiaanvandeneyndeWell yes, the system is calculating your permissions and inside that calculation you are asking for the fully calculated permissions :D
From what you wrote on Slack, you're trying to grant a few permissions to whoever has a certain permission. That can indeed be achieved in the alter method and requires no extra cache stuff, provided your list of "extra permissions" never changes.
Otherwise you need a cache invalidation when that does happen e.g.:
So how do you check what permissions someone has? Well you have all of them in the alter method already!
Comment #16
megakeegman commentedThanks that is great information, and I will test that right away. As far as a proposed resolution, I wasn't sure when I wrote the issue because I couldn't tell if I was doing something wrong or there was a bug, and yes, I may have set RBTC preemptively. If indeed comment #14 is true, then I would suggest that we turn this into a documentation issue. I would appreciate suggestions for the best way to document, whether that is through recommendation of how to fix the problem when the error occurs, or on a documentation webpage, or otherwise.
Comment #17
megakeegman commentedI can confirm that #14 is correct. I do want to note that this option is not available from inside of calculatePermissions, which makes sense, but was not immediately obvious to me. Is it safe to assume that if you need to do such a check, that you should just be using alterPermissions?
Comment #18
megakeegman commented