mirror of
https://github.com/PowerShell/PowerShell
synced 2026-06-08 12:12:50 +00:00
Fix for duplicate types in TypeTable (#3141)
When a TypeTable is created it includes the types from type files provided along with references to the type files. When the InitialSessionState (ISS) object processes these types it reads the type files again and ends up with duplicate type entries. PowerShell V5.1 ISS type processing was re-written to improve performance and no longer removes duplicate types, so that this scenario (runspace ISS reuse) results in errors causing a regression. The fix is to copy only type data when a TypeTable is passed to the ISS.
This commit is contained in:
committed by
Dongbo Wang
parent
d60dc730a4
commit
c266c8ebca
@@ -1309,7 +1309,7 @@ namespace System.Management.Automation.Runspaces
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// Add items to this collection.
|
||||
/// </summary>
|
||||
/// <param name="items"></param>
|
||||
public void Add(IEnumerable<T> items)
|
||||
@@ -1326,6 +1326,27 @@ namespace System.Management.Automation.Runspaces
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Special add for TypeTable type entries that removes redundant file entries.
|
||||
/// </summary>
|
||||
internal void AddTypeTableTypesInfo(IEnumerable<T> items)
|
||||
{
|
||||
if (typeof(T) != typeof(SessionStateTypeEntry)) { throw new PSInvalidOperationException(); }
|
||||
|
||||
lock (_syncObject)
|
||||
{
|
||||
foreach (var element in items)
|
||||
{
|
||||
var typeEntry = element as SessionStateTypeEntry;
|
||||
if (typeEntry.TypeData != null)
|
||||
{
|
||||
// Skip type file entries.
|
||||
_internalCollection.Add(element);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get enumerator for this collection.
|
||||
/// </summary>
|
||||
@@ -3851,7 +3872,12 @@ namespace System.Management.Automation.Runspaces
|
||||
context.TypeTable = typeTable;
|
||||
|
||||
Types.Clear();
|
||||
Types.Add(typeTable.typesInfo);
|
||||
|
||||
// A TypeTable contains types info along with type file references used to create the types info,
|
||||
// which is redundant information. When resused in a runspace the ISS unpacks the file types again
|
||||
// resulting in duplicate types and duplication errors when processed.
|
||||
// So use this special Add method to filter all types files found in the TypeTable.
|
||||
Types.AddTypeTableTypesInfo(typeTable.typesInfo);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
|
||||
<Types>
|
||||
<Type>
|
||||
<Name>System.Array</Name>
|
||||
<Members>
|
||||
<AliasProperty>
|
||||
<Name>Counts</Name>
|
||||
<ReferencedMemberName>Length</ReferencedMemberName>
|
||||
</AliasProperty>
|
||||
</Members>
|
||||
</Type>
|
||||
</Types>
|
||||
@@ -54,4 +54,75 @@ Describe "InitialSessionState capacity" -Tags CI {
|
||||
$ps.AddScript('New-Alias -Name a5000 -Value f1; a5000').Invoke() | Should Be "fn f1"
|
||||
$ps.Streams.Error | Should Be $null
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
##
|
||||
## A reused InitialSessionState created from a TypeTable should not have duplicate types.
|
||||
##
|
||||
Describe "TypeTable duplicate types in reused runspace InitialSessionState TypeTable" -Tags 'Feature' {
|
||||
|
||||
Context "No duplicate types test" {
|
||||
|
||||
BeforeAll {
|
||||
|
||||
$typeTable = [System.Management.Automation.Runspaces.TypeTable]::new([string[]](Join-Path $PSScriptRoot "../Common/TestTypeFile.ps1xml"))
|
||||
[initialsessionstate] $iss = [initialsessionstate]::Create()
|
||||
$iss.Types.Add($typeTable)
|
||||
[runspace] $rs1 = [runspacefactory]::CreateRunspace($iss)
|
||||
|
||||
# Process TypeTable types from ISS
|
||||
$rs1.Open()
|
||||
|
||||
# Get processed ISS from runspace.
|
||||
$issReused = $rs1.InitialSessionState.Clone()
|
||||
$issReused.ThrowOnRunspaceOpenError = $true
|
||||
|
||||
# Create new runspace with reused ISS.
|
||||
$rs2 = [runspacefactory]::CreateRunspace($issReused)
|
||||
}
|
||||
|
||||
AfterAll {
|
||||
|
||||
if ($rs1 -ne $null) { $rs1.Dispose() }
|
||||
if ($rs2 -ne $null) { $rs2.Dispose() }
|
||||
}
|
||||
|
||||
It "Verifies that a reused InitialSessionState object created from a TypeTable object does not have duplicate types" {
|
||||
|
||||
{ $rs2.Open() } | Should Not Throw
|
||||
}
|
||||
}
|
||||
|
||||
Context "Cannot use shared TypeTable in ISS test" {
|
||||
|
||||
BeforeAll {
|
||||
|
||||
# Create default ISS and add shared TypeTable.
|
||||
$typeTable = [System.Management.Automation.Runspaces.TypeTable]::new([string[]](Join-Path $PSScriptRoot "../Common/TestTypeFile.ps1xml"))
|
||||
[initialsessionstate] $iss = [initialsessionstate]::CreateDefault2()
|
||||
$iss.Types.Add($typeTable)
|
||||
$iss.ThrowOnRunspaceOpenError = $true
|
||||
[runspace] $rs = [runspacefactory]::CreateRunspace($iss)
|
||||
}
|
||||
|
||||
AfterAll {
|
||||
|
||||
if ($rs -ne $null) { $rs.Dispose() }
|
||||
}
|
||||
|
||||
It "Verifies that shared TypeTable is not allowed in ISS" {
|
||||
|
||||
# Process TypeTable types from ISS.
|
||||
$errorId = ""
|
||||
try
|
||||
{
|
||||
$rs.Open()
|
||||
throw "No Exception!"
|
||||
}
|
||||
catch
|
||||
{
|
||||
$_.Exception.InnerException.ErrorRecord.FullyQualifiedErrorId | Should Be "ErrorsUpdatingTypes"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user