-
Notifications
You must be signed in to change notification settings - Fork 8.1k
Fix a module-loading regression that caused an infinite loop #6843
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
Conversation
| // session state is empty, then use the existing session state. | ||
| // This will be the case when ModuleToProcess is a binary module | ||
| // and there were nested modules. | ||
| if (newManifestInfo.SessionState == null && ss != null) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
When it's not module analysis (get-module -list), ss will never be null. I verified that binary root module also uses ss as the session state. This is why this check is no longer needed.
| // existing session state, then use the new module info's sessions state; | ||
| // This will be the case if the module to process is a script module | ||
| // but there where no nested modules. | ||
| else if (newManifestInfo.SessionState != null && ss == null) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ss == null only if we are doing module analysis, but when we are doing module analysis, newManifestInfo.SessionState is always null, because we don't really load anything. This is why this check is no longer needed.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These changes look good to me.
One question is: is there a possibility of a second-order nested module cycle?
Say A is a top level module, with nested module B, and B has in its nested modules A, then we'll still get caught in an infinite recursion? Unless that's not possible.
If it is possible, it seems like the only way to fix it is to carry a HashSet of module infos that we've seen with us down the recursive calls and ignore anything that's already in it. That would also prevent us reanalysing shared nested modules.
| // For example, module folder 'test' has two files: 'test.psd1' and 'test.psm1', and 'test.psd1' has the following content: | ||
| // "@{ ModuleVersion = '0.0.1'; RootModule = 'test'; NestedModules = @('test') }" | ||
| // Then, 'Import-Module test.psd1 -PassThru' will return a ModuleInfo object with circular nested modules. | ||
| continue; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Based on Issue which we fix I believe it make sense to inform users about the situation or even terminated the cmdlet.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Turning something that works to an error is a hard breaking change. As for the warning, I'm not sure if we should do it, since technically import-module is doing what it's asked to do ... (have itself as the nested module).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can ScriptAnalyzer catch this?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good point! I think the script analyzer should be able to catch this kind of issue. That's the best place to throw a warning. I just checked in VS Code and the analyzer doesn't catch that now. I can open an issue at the script analyzer repo.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Issue opened: PowerShell/PSScriptAnalyzer#997
| # Copyright (c) Microsoft Corporation. All rights reserved. | ||
| # Licensed under the MIT License. | ||
|
|
||
| Describe "Module basic tests" -tags "CI" { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe put the single test in test\powershell\Modules\Microsoft.PowerShell.Core\Import-Module.Tests.ps1?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
OK, will do.
|
@rjmholt I tried out the scenario you mentioned above and powershell handles it (yay!): |
PR Summary
Fix #6813
This regression was introduced by #6523, in
PSModuleInfo.cs. A circular nested module check was removed because the comment there suggested it happens only with a deprecated workflow module. This causes aStackOverflowexception when running into circular nested modules.Circular nested modules could happen for a module that is not well structured. For example, the module folder
testcontains two files:test.psd1andtest.psm1, andtest.psd1has the following content:The same value
testis put in both RootModule and NestedModule, which will end up with a module whose nested module points to itself.There are two changes in this PR:
PSModuleInfo.cs.Dbg.AssertinModuleCmdletBase.csand two checks before it.Dbg.Assert(newManifestInfo.SessionState == ss, when facing the example above, the nested module will first be loaded with a different session state, and then when trying to load the root module, the same loaded nested module will be reused for it. So 'newManifestInfo.SessionState' is notss. The assersion will fail in that case.PR Checklist
.h,.cpp,.cs,.ps1and.psm1files have the correct copyright headerWIP:to the beginning of the title and remove the prefix when the PR is ready.[feature]if the change is significant or affects feature tests