Fix null reference when module is null in hosting scenarios#9404
Fix null reference when module is null in hosting scenarios#9404daxian-dbw merged 9 commits intoPowerShell:masterfrom
Conversation
test/powershell/Modules/Microsoft.PowerShell.Utility/MarkdownCmdlets.Tests.ps1
Outdated
Show resolved
Hide resolved
test/powershell/Modules/Microsoft.PowerShell.Utility/MarkdownCmdlets.Tests.ps1
Outdated
Show resolved
Hide resolved
| { | ||
| throw new InvalidOperationException(); | ||
| } | ||
| _mdOption = this.CommandInfo.Module?.SessionState.PSVariable.GetValue("PSMarkdownOptionInfo", new PSMarkdownOptionInfo()) as PSMarkdownOptionInfo; |
There was a problem hiding this comment.
Could you please clarify for my education why is this.CommandInfo.Module null in the scenario?
There was a problem hiding this comment.
Its part of the PR context.
There was a problem hiding this comment.
My question is why this is null if it is running in new runspace. I do not understand the difference and therefore I am afraid that there may be a bug.
There was a problem hiding this comment.
https://docs.microsoft.com/en-us/dotnet/api/system.management.automation.commandinfo.module?view=powershellsdk-1.1.0#System_Management_Automation_CommandInfo_Module indicates that this shouldn't be null since this cmdlet is part of a module. Seems like there's a bug somewhere else. I don't think this would block this PR, but we should have an issue open to investigate this.
There was a problem hiding this comment.
We already have #9390 for tracking. If it is "a bug somewhere else". Since we are at the beginning of a new milestone we could only add pending test in the PR without temporary fix.
There was a problem hiding this comment.
Yes, if it's a snapin, it won't show up as a module
There was a problem hiding this comment.
Yep, it's because powershell built-in modules are loaded as snapins with [runspacefactory]::CreateRunspacePool(1, 2, $Host), as well as [runspacefactory]::CreateRunspace().
This issue repros with the following script too:
PS:100> $ps = [powershell]::Create()
PS:101> $ps.AddScript("'# test' | convertfrom-markdown").Invoke()
PS:102> $ps.Streams.Error
convertfrom-markdown : Object reference not set to an instance of an object.
At line:1 char:12
+ '# test' | convertfrom-markdown
+ ~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (:) [ConvertFrom-Markdown], NullReferenceException
+ FullyQualifiedErrorId : System.NullReferenceException,Microsoft.PowerShell.Commands.ConvertFromMarkdownCommand
There was a problem hiding this comment.
Thanks for clarify. If snapins is deprecated should we change loading built-in modules too? If possible this would be the best fix.
There was a problem hiding this comment.
The public interface of PSSnapin is deprecated, meaning user cannot define a snapin to work with PowerShell, but the snapin itself is still useful, especially in the hosting scenario.
Loading as snapin doesn't require the modules to be present (module folder or .psd1 file and etc.), so for some hosting scenario, this is convenient as the hosting application doesn't need to ship the built-in powershell modules along with the application.
There was a problem hiding this comment.
I wonder - we can create an assembly with Add-Type and load it with Import-Module. We use this in our tests without creating module folder and etc.
test/powershell/Modules/Microsoft.PowerShell.Utility/MarkdownCmdlets.Tests.ps1
Outdated
Show resolved
Hide resolved
src/Microsoft.PowerShell.Commands.Utility/commands/utility/ConvertFromMarkdownCommand.cs
Outdated
Show resolved
Hide resolved
* Instead of using the module scope variable, we now use a dictionary with the runspace as the key to store the options. * Update tests accordingly.
1b26c6d to
b5be0db
Compare
src/Microsoft.PowerShell.Commands.Utility/commands/utility/MarkdownOptionCommands.cs
Outdated
Show resolved
Hide resolved
test/powershell/Modules/Microsoft.PowerShell.Utility/MarkdownCmdlets.Tests.ps1
Outdated
Show resolved
Hide resolved
test/powershell/Modules/Microsoft.PowerShell.Utility/MarkdownCmdlets.Tests.ps1
Show resolved
Hide resolved
test/powershell/Modules/Microsoft.PowerShell.Utility/MarkdownCmdlets.Tests.ps1
Show resolved
Hide resolved
|
@daxian-dbw Can you have a look again. |
When moduleInfo is available we use the module scope variable. But, when it is not available, we use a concurrent dictionary with runspace instance ID as the key to store the options.
src/Microsoft.PowerShell.Commands.Utility/commands/utility/MarkdownOptionCommands.cs
Outdated
Show resolved
Hide resolved
src/Microsoft.PowerShell.Commands.Utility/commands/utility/MarkdownOptionCommands.cs
Outdated
Show resolved
Hide resolved
src/Microsoft.PowerShell.Commands.Utility/commands/utility/MarkdownOptionCommands.cs
Outdated
Show resolved
Hide resolved
src/Microsoft.PowerShell.Commands.Utility/commands/utility/ConvertFromMarkdownCommand.cs
Outdated
Show resolved
Hide resolved
src/Microsoft.PowerShell.Commands.Utility/commands/utility/ConvertFromMarkdownCommand.cs
Outdated
Show resolved
Hide resolved
src/Microsoft.PowerShell.Commands.Utility/commands/utility/MarkdownOptionCommands.cs
Outdated
Show resolved
Hide resolved
src/Microsoft.PowerShell.Commands.Utility/commands/utility/MarkdownOptionCommands.cs
Outdated
Show resolved
Hide resolved
src/Microsoft.PowerShell.Commands.Utility/commands/utility/ConvertFromMarkdownCommand.cs
Outdated
Show resolved
Hide resolved
|
Also talked to @adityapatwardhan offline, and we agreed it's better to move all |
|
@daxian-dbw I have updated to address your comments. Please have another look. |
| // If we have the moduleInfo then store are module scope variable | ||
| if (command.Module != null) | ||
| { | ||
| return command.Module.SessionState.PSVariable.GetValue(MarkdownOptionInfoVariableName, new PSMarkdownOptionInfo()) as PSMarkdownOptionInfo; |
There was a problem hiding this comment.
I wonder that the API to force creating default value before trying to get a value.
|
@daxian-dbw Ping.. |
src/Microsoft.PowerShell.Commands.Utility/commands/utility/MarkdownOptionCommands.cs
Outdated
Show resolved
Hide resolved
|
@daxian-dbw This is ready for merging. |
PR Summary
Fixes #9390
If the
CommandInfo.Moduleis null, then default to a newPSMarkdownOptionInfo.PR Context
In hosting scenarios as module are loaded as snapins, the
CommandInfo.Moduleis null. In those cases we default back to defaultPSMarkdownOptionInfo.PR Checklist
.h,.cpp,.cs,.ps1and.psm1files have the correct copyright headerWIP:or[ WIP ]to the beginning of the title (theWIPbot will keep its status check atPendingwhile the prefix is present) and remove the prefix when the PR is ready.