Skip to content

Conversation

@daxian-dbw
Copy link
Member

@daxian-dbw daxian-dbw commented May 8, 2018

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 a StackOverflow exception when running into circular nested modules.

Circular nested modules could happen for a module that is not well structured. For example, the module folder test contains two files: test.psd1 and test.psm1, and test.psd1 has the following content:

@{ ModuleVersion = '0.0.1'; RootModule = 'test'; NestedModules = @('test') }

The same value test is 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:

  1. Add back the circular nested module check in PSModuleInfo.cs.
  2. Remove a wrong Dbg.Assert in ModuleCmdletBase.cs and two checks before it.
    • For the assertion 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 not ss. The assersion will fail in that case.
    • For the two checks before the assersion, they are not needed anymore based on the comments there.

PR Checklist

@daxian-dbw daxian-dbw changed the title Fix a module-loading regression that caused an infinite loop [WIP] Fix a module-loading regression that caused an infinite loop May 8, 2018
// 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)
Copy link
Member Author

@daxian-dbw daxian-dbw May 8, 2018

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)
Copy link
Member Author

@daxian-dbw daxian-dbw May 8, 2018

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.

@daxian-dbw daxian-dbw changed the title [WIP] Fix a module-loading regression that caused an infinite loop Fix a module-loading regression that caused an infinite loop May 8, 2018
Copy link
Collaborator

@rjmholt rjmholt left a 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;
Copy link
Collaborator

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.

Copy link
Member Author

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).

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can ScriptAnalyzer catch this?

Copy link
Member Author

@daxian-dbw daxian-dbw May 9, 2018

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.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT License.

Describe "Module basic tests" -tags "CI" {
Copy link
Collaborator

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?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK, will do.

@daxian-dbw
Copy link
Member Author

@rjmholt I tried out the scenario you mentioned above and powershell handles it (yay!):

PS:7> Import-Module mtest
Import-Module : Cannot load the module 'F:\tmp\dump\mtest\blah' because the module nesting limit has been exceeded. Modules can only be nested to 10 levels. Evaluate and change the order in which you are loading modules to prevent exceeding the nesting limit, and then try running your script again.
At line:1 char:1
+ Import-Module mtest
+ ~~~~~~~~~~~~~~~~~~~
+ CategoryInfo          : InvalidOperation: (F:\tmp\dump\mtest\blah:String) [Import-Module], InvalidOperationException
+ FullyQualifiedErrorId : Modules_ModuleTooDeeplyNested,Microsoft.PowerShell.Commands.ImportModuleCommand

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.

Process is terminating due to StackOverflowException

3 participants