[release/v7.4.2] Make sure the assembly/library resolvers are registered at early stage (#21361) (#21424)

This commit is contained in:
Patrick Meinecke
2024-04-04 15:23:05 -07:00
committed by GitHub
parent 7b6be49271
commit 200ac639e1
4 changed files with 56 additions and 7 deletions
@@ -36,16 +36,19 @@ namespace System.Management.Automation
/// <summary>
/// Initialize a singleton of PowerShellAssemblyLoadContext.
/// </summary>
internal static PowerShellAssemblyLoadContext InitializeSingleton(string basePaths)
internal static PowerShellAssemblyLoadContext InitializeSingleton(string basePaths, bool throwOnReentry)
{
lock (s_syncObj)
{
if (Instance != null)
if (Instance is null)
{
Instance = new PowerShellAssemblyLoadContext(basePaths);
}
else if (throwOnReentry)
{
throw new InvalidOperationException(SingletonAlreadyInitialized);
}
Instance = new PowerShellAssemblyLoadContext(basePaths);
return Instance;
}
}
@@ -581,7 +584,8 @@ namespace System.Management.Automation
{
ArgumentException.ThrowIfNullOrEmpty(basePaths);
PowerShellAssemblyLoadContext.InitializeSingleton(basePaths);
// Disallow calling this method from native code for more than once.
PowerShellAssemblyLoadContext.InitializeSingleton(basePaths, throwOnReentry: true);
}
}
@@ -25,6 +25,28 @@ namespace System.Management.Automation.Runspaces
{
#region constructors
/// <summary>
/// Initialize powershell AssemblyLoadContext and register the 'Resolving' event, if it's not done already.
/// If powershell is hosted by a native host such as DSC, then PS ALC may be initialized via 'SetPowerShellAssemblyLoadContext' before loading S.M.A.
/// </summary>
/// <remarks>
/// We do this both here and during the initialization of the 'ClrFacade' type.
/// This is because we want to make sure the assembly/library resolvers are:
/// 1. registered before any script/cmdlet can run.
/// 2. registered before 'ClrFacade' gets used for assembly related operations.
///
/// The 'ClrFacade' type may be used without a Runspace created, for example, by calling type conversion methods in the 'LanguagePrimitive' type.
/// And at the mean time, script or cmdlet may run without the 'ClrFacade' type initialized.
/// That's why we attempt to create the singleton of 'PowerShellAssemblyLoadContext' at both places.
/// </remarks>
static RunspaceBase()
{
if (PowerShellAssemblyLoadContext.Instance is null)
{
PowerShellAssemblyLoadContext.InitializeSingleton(string.Empty, throwOnReentry: false);
}
}
/// <summary>
/// Construct an instance of an Runspace using a custom
/// implementation of PSHost.
@@ -22,13 +22,23 @@ namespace System.Management.Automation
{
/// <summary>
/// Initialize powershell AssemblyLoadContext and register the 'Resolving' event, if it's not done already.
/// If powershell is hosted by a native host such as DSC, then PS ALC might be initialized via 'SetPowerShellAssemblyLoadContext' before loading S.M.A.
/// If powershell is hosted by a native host such as DSC, then PS ALC may be initialized via 'SetPowerShellAssemblyLoadContext' before loading S.M.A.
/// </summary>
/// <remarks>
/// We do this both here and during the initialization of the 'RunspaceBase' type.
/// This is because we want to make sure the assembly/library resolvers are:
/// 1. registered before any script/cmdlet can run.
/// 2. registered before 'ClrFacade' gets used for assembly related operations.
///
/// The 'ClrFacade' type may be used without a Runspace created, for example, by calling type conversion methods in the 'LanguagePrimitive' type.
/// And at the mean time, script or cmdlet may run without the 'ClrFacade' type initialized.
/// That's why we attempt to create the singleton of 'PowerShellAssemblyLoadContext' at both places.
/// </remarks>
static ClrFacade()
{
if (PowerShellAssemblyLoadContext.Instance == null)
if (PowerShellAssemblyLoadContext.Instance is null)
{
PowerShellAssemblyLoadContext.InitializeSingleton(string.Empty);
PowerShellAssemblyLoadContext.InitializeSingleton(string.Empty, throwOnReentry: false);
}
}
@@ -0,0 +1,13 @@
# Copyright (c) Microsoft Corporation.
# Licensed under the MIT License.
Describe "Assembly resolvers should be registered early at startup" -Tags "CI" {
## The PKI module requires loading an assembly from GAC, and thus depends on the PowerShell assembly resolver to work.
It "Can load the PKI module with 'pwsh -ExecutionPolicy bypass -NoProfile -c `"Import-Module PKI`"'" -Skip:(!$IsWindows) {
## Use 'Bypass' execution policy so that it doesn't trigger 'AuthorizationManager' which would trigger 'ClrFacade' initialization.
## We want to make sure even if 'ClrFacade' is not hit during startup, the resolvers are still registered early enough.
$out = pwsh -ExecutionPolicy bypass -NoProfile -c "Import-Module PKI; Get-Module | % name"
$out | Should -BeExactly "PKI"
}
}