Skip to content

Commit

Permalink
Fixed TypeLoadException when inspecting state machine attribute updat…
Browse files Browse the repository at this point in the history
…ed by ENC (dotnet#57165)

* Fixed TypeLoadException when inspecting state machine attribute updated by EnC

Issue: dotnet#54929

Use Module::ApplyMetaData() in EditAndContinueModule::ApplyEditAndContinue to update the AvailableClassHash for reflection, etc. ensure that the new TypeRefs, AssemblyRefs and MethodDefs can be stored.
  • Loading branch information
mikem8361 authored Aug 11, 2021
1 parent e74c18b commit f6593f7
Show file tree
Hide file tree
Showing 9 changed files with 123 additions and 14 deletions.
8 changes: 5 additions & 3 deletions src/coreclr/vm/ceeload.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -204,7 +204,7 @@ BOOL Module::SetTransientFlagInterlocked(DWORD dwFlag)
}
}

#if PROFILING_SUPPORTED
#if defined(PROFILING_SUPPORTED) || defined(EnC_SUPPORTED)
void Module::UpdateNewlyAddedTypes()
{
CONTRACTL
Expand Down Expand Up @@ -262,7 +262,9 @@ void Module::UpdateNewlyAddedTypes()
m_dwExportedTypeCount = countExportedTypesAfterProfilerUpdate;
m_dwCustomAttributeCount = countCustomAttributeCount;
}
#endif // PROFILING_SUPPORTED || EnC_SUPPORTED

#if PROFILING_SUPPORTED
void Module::NotifyProfilerLoadFinished(HRESULT hr)
{
CONTRACTL
Expand Down Expand Up @@ -1179,12 +1181,12 @@ void Module::ApplyMetaData()
HRESULT hr = S_OK;
ULONG ulCount;

#if PROFILING_SUPPORTED
#if defined(PROFILING_SUPPORTED) || defined(EnC_SUPPORTED)
if (!IsResource())
{
UpdateNewlyAddedTypes();
}
#endif // PROFILING_SUPPORTED
#endif // PROFILING_SUPPORTED || EnC_SUPPORTED

// Ensure for TypeRef
ulCount = GetMDImport()->GetCountWithTokenKind(mdtTypeRef) + 1;
Expand Down
11 changes: 3 additions & 8 deletions src/coreclr/vm/encee.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -262,17 +262,12 @@ HRESULT EditAndContinueModule::ApplyEditAndContinue(
// Field is new - add it
IfFailGo(AddField(token));
break;

case mdtTypeRef:
EnsureTypeRefCanBeStored(token);
break;

case mdtAssemblyRef:
EnsureAssemblyRefCanBeStored(token);
break;
}
}

// Update the AvailableClassHash for reflection, etc. ensure that the new TypeRefs, AssemblyRefs and MethodDefs can be stored.
ApplyMetaData();

ErrExit:
if (pIMDInternalImportENC)
pIMDInternalImportENC->EnumClose(&enumENC);
Expand Down
21 changes: 21 additions & 0 deletions src/libraries/System.Runtime.Loader/System.Runtime.Loader.sln
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{6963C709-FD2
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "System.Reflection.Metadata.ApplyUpdate.Test.CustomAttributeDelete", "tests\ApplyUpdate\System.Reflection.Metadata.ApplyUpdate.Test.CustomAttributeDelete\System.Reflection.Metadata.ApplyUpdate.Test.CustomAttributeDelete.csproj", "{EEAE2A15-E2AE-4421-8D30-AAB17AC805F8}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "System.Reflection.Metadata.ApplyUpdate.Test.AsyncMethodChange", "tests\ApplyUpdate\System.Reflection.Metadata.ApplyUpdate.Test.AsyncMethodChange\System.Reflection.Metadata.ApplyUpdate.Test.AsyncMethodChange.csproj", "{582AA5E5-051B-4774-B02D-747E197A5C56}"
EndProject
Global
GlobalSection(SharedMSBuildProjectFiles) = preSolution
..\System.Private.CoreLib\src\System.Private.CoreLib.Shared.projitems*{64ddd2af-bf90-4dd8-ac24-d2084db8d558}*SharedItemsImports = 5
Expand Down Expand Up @@ -465,6 +467,24 @@ Global
{EEAE2A15-E2AE-4421-8D30-AAB17AC805F8}.Release|x64.Build.0 = Release|Any CPU
{EEAE2A15-E2AE-4421-8D30-AAB17AC805F8}.Release|x86.ActiveCfg = Release|Any CPU
{EEAE2A15-E2AE-4421-8D30-AAB17AC805F8}.Release|x86.Build.0 = Release|Any CPU
{582AA5E5-051B-4774-B02D-747E197A5C56}.Checked|Any CPU.ActiveCfg = Debug|Any CPU
{582AA5E5-051B-4774-B02D-747E197A5C56}.Checked|Any CPU.Build.0 = Debug|Any CPU
{582AA5E5-051B-4774-B02D-747E197A5C56}.Checked|x64.ActiveCfg = Debug|Any CPU
{582AA5E5-051B-4774-B02D-747E197A5C56}.Checked|x64.Build.0 = Debug|Any CPU
{582AA5E5-051B-4774-B02D-747E197A5C56}.Checked|x86.ActiveCfg = Debug|Any CPU
{582AA5E5-051B-4774-B02D-747E197A5C56}.Checked|x86.Build.0 = Debug|Any CPU
{582AA5E5-051B-4774-B02D-747E197A5C56}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{582AA5E5-051B-4774-B02D-747E197A5C56}.Debug|Any CPU.Build.0 = Debug|Any CPU
{582AA5E5-051B-4774-B02D-747E197A5C56}.Debug|x64.ActiveCfg = Debug|Any CPU
{582AA5E5-051B-4774-B02D-747E197A5C56}.Debug|x64.Build.0 = Debug|Any CPU
{582AA5E5-051B-4774-B02D-747E197A5C56}.Debug|x86.ActiveCfg = Debug|Any CPU
{582AA5E5-051B-4774-B02D-747E197A5C56}.Debug|x86.Build.0 = Debug|Any CPU
{582AA5E5-051B-4774-B02D-747E197A5C56}.Release|Any CPU.ActiveCfg = Release|Any CPU
{582AA5E5-051B-4774-B02D-747E197A5C56}.Release|Any CPU.Build.0 = Release|Any CPU
{582AA5E5-051B-4774-B02D-747E197A5C56}.Release|x64.ActiveCfg = Release|Any CPU
{582AA5E5-051B-4774-B02D-747E197A5C56}.Release|x64.Build.0 = Release|Any CPU
{582AA5E5-051B-4774-B02D-747E197A5C56}.Release|x86.ActiveCfg = Release|Any CPU
{582AA5E5-051B-4774-B02D-747E197A5C56}.Release|x86.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
Expand Down Expand Up @@ -492,6 +512,7 @@ Global
{9AD657ED-396B-4BE7-BCB6-BCA130825418} = {F36F0790-5CF7-4CAD-B903-4A3EE0DC1345}
{29E02AA9-E3D5-400C-B2C5-970B6E6D8562} = {F36F0790-5CF7-4CAD-B903-4A3EE0DC1345}
{EEAE2A15-E2AE-4421-8D30-AAB17AC805F8} = {F36F0790-5CF7-4CAD-B903-4A3EE0DC1345}
{582AA5E5-051B-4774-B02D-747E197A5C56} = {F36F0790-5CF7-4CAD-B903-4A3EE0DC1345}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {73D0667D-A181-41CA-B57B-DD177166E019}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
using System;
using System.Threading.Tasks;

namespace System.Reflection.Metadata.ApplyUpdate.Test
{
public class AsyncMethodChange
{
public AsyncMethodChange () {}

#pragma warning disable CS1998 // Async method lacks 'await' operators and will run synchronously
public static async Task<string> TestTaskMethod()
#pragma warning restore CS1998 // Async method lacks 'await' operators and will run synchronously
{
return "TestTaskMethod";
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
using System;
using System.Threading.Tasks;

namespace System.Reflection.Metadata.ApplyUpdate.Test
{
public class AsyncMethodChange
{
public AsyncMethodChange () {}

#pragma warning disable CS1998 // Async method lacks 'await' operators and will run synchronously
public static async Task<string> TestTaskMethod()
#pragma warning restore CS1998 // Async method lacks 'await' operators and will run synchronously
{
return "TestTaskMethod v1";
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<RootNamespace>System.Runtime.Loader.Tests</RootNamespace>
<TargetFrameworks>$(NetCoreAppCurrent)</TargetFrameworks>
<TestRuntime>true</TestRuntime>
<DeltaScript>deltascript.json</DeltaScript>
<SkipTestUtilitiesReference>true</SkipTestUtilitiesReference>
</PropertyGroup>
<ItemGroup>
<Compile Include="AsyncMethodChange.cs" />
</ItemGroup>
</Project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"changes": [
{"document": "AsyncMethodChange.cs", "update": "AsyncMethodChange_v1.cs"}
]
}

36 changes: 36 additions & 0 deletions src/libraries/System.Runtime.Loader/tests/ApplyUpdateTest.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System.Runtime.CompilerServices;
using Xunit;

namespace System.Reflection.Metadata
Expand Down Expand Up @@ -179,6 +180,41 @@ public void CustomAttributeDelete()
});
}

[ActiveIssue("https://github.com/dotnet/runtime/issues/52993", TestRuntimes.Mono)]
[ConditionalFact(typeof(ApplyUpdateUtil), nameof (ApplyUpdateUtil.IsSupported))]
public void AsyncMethodChanges()
{
// Test that changing an async method doesn't cause any type load exceptions
ApplyUpdateUtil.TestCase(static () =>
{
Assembly assembly = typeof(System.Reflection.Metadata.ApplyUpdate.Test.AsyncMethodChange).Assembly;

ApplyUpdateUtil.ApplyUpdate(assembly);
ApplyUpdateUtil.ClearAllReflectionCaches();

Type ty = typeof(System.Reflection.Metadata.ApplyUpdate.Test.AsyncMethodChange);
Assert.NotNull(ty);

MethodInfo mi = ty.GetMethod(nameof(System.Reflection.Metadata.ApplyUpdate.Test.AsyncMethodChange.TestTaskMethod), BindingFlags.Public | BindingFlags.Static);
Assert.NotNull(mi);

string result = ApplyUpdate.Test.AsyncMethodChange.TestTaskMethod().GetAwaiter().GetResult();
Assert.Equal("TestTaskMethod v1", result);

object[] attributes = mi.GetCustomAttributes(true);
Assert.NotNull(attributes);
Assert.True(attributes.Length > 0);

foreach (var attribute in attributes)
{
if (attribute is AsyncStateMachineAttribute asm)
{
Assert.Contains("<TestTaskMethod>", asm.StateMachineType.Name);
}
}
});
}

class NonRuntimeAssembly : Assembly
{
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
<EmbeddedResource Include="MainStrings*.resx" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="ApplyUpdate\System.Reflection.Metadata.ApplyUpdate.Test.AsyncMethodChange\System.Reflection.Metadata.ApplyUpdate.Test.AsyncMethodChange.csproj" />
<ProjectReference Include="ApplyUpdate\System.Reflection.Metadata.ApplyUpdate.Test.CustomAttributeDelete\System.Reflection.Metadata.ApplyUpdate.Test.CustomAttributeDelete.csproj" />
<ProjectReference Include="System.Runtime.Loader.Test.Assembly\System.Runtime.Loader.Test.Assembly.csproj" ReferenceOutputAssembly="false" OutputItemType="EmbeddedResource" />
<ProjectReference Include="System.Runtime.Loader.Test.Assembly2\System.Runtime.Loader.Test.Assembly2.csproj" ReferenceOutputAssembly="false" OutputItemType="EmbeddedResource" />
Expand Down Expand Up @@ -50,9 +51,7 @@
<TrimmerRootAssembly Condition="$([System.String]::Copy('%(ResolvedFileToPublish.FileName)%(ResolvedFileToPublish.Extension)').EndsWith('System.Reflection.Metadata.ApplyUpdate.Test.MethodBody1.dll'))" Include="%(ResolvedFileToPublish.FullPath)" />
<TrimmerRootAssembly Condition="$([System.String]::Copy('%(ResolvedFileToPublish.FileName)%(ResolvedFileToPublish.Extension)').EndsWith('System.Reflection.Metadata.ApplyUpdate.Test.ClassWithCustomAttributes.dll'))" Include="%(ResolvedFileToPublish.FullPath)" />
<TrimmerRootAssembly Condition="$([System.String]::Copy('%(ResolvedFileToPublish.FileName)%(ResolvedFileToPublish.Extension)').EndsWith('System.Reflection.Metadata.ApplyUpdate.Test.CustomAttributeUpdate.dll'))" Include="%(ResolvedFileToPublish.FullPath)" />
<TrimmerRootAssembly
Condition="$([System.String]::Copy('%(ResolvedFileToPublish.FileName)%(ResolvedFileToPublish.Extension)').EndsWith('System.Reflection.Metadata.ApplyUpdate.Test.LambdaBodyChange.dll'))"
Include="%(ResolvedFileToPublish.FullPath)" />
<TrimmerRootAssembly Condition="$([System.String]::Copy('%(ResolvedFileToPublish.FileName)%(ResolvedFileToPublish.Extension)').EndsWith('System.Reflection.Metadata.ApplyUpdate.Test.LambdaBodyChange.dll'))" Include="%(ResolvedFileToPublish.FullPath)" />
</ItemGroup>
</Target>

Expand Down

0 comments on commit f6593f7

Please sign in to comment.