Closed
Description
Applying cumulative updates to properties in generic classes seems to shutdown coreclr.
In effect this is the code before the first update:
using System;
namespace testProperty;
public class C1<T> {
public T MyProp1 {get; set;}
public static int M1() {
Console.WriteLine("Hello");
return 17;
}
}
Then the update changes it to:
using System;
namespace testProperty;
public class C1<T> {
public T MyProp1 {get; set;}
public T MyProp2 {
get => default(T);
set {
Console.WriteLine($"setting MyProp2 to {value}");
}
}
public static int M1() {
var x = new C1<string>();
x.MyProp1 = "hello1";
x.MyProp2 = "hello2";
return 42;
}
}
And finally change it to:
using System;
namespace testProperty;
public class C1<T> {
public T MyProp1 {get; set;}
public T MyProp2 {
get => default(T);
set {
Console.WriteLine($"updated setting MyProp2 to {value}");
}
}
public T[] MyProp3 {
get => default(T[]);
set {
Console.WriteLine($"setting MyProp3 to {value}");
}
}
public static int M1() {
var x = new C1<string>();
x.MyProp1 = "hello1";
x.MyProp2 = "hello2";
x.MyProp3 = new string[] { "hello3" };
return 45;
}
}
The actual invocations are done like this (ApplyUpdate
is just loading the bytes from the .dmeta and .dil files and calling the System.Reflection.Metadata.MetadataUpdater.ApplyUpdate
method):
int x = testProperty.C1<int>.M1();
ApplyUpdate();
x = testProperty.C1<string>.M1();
if (x != 42) {
throw new Exception("Expected 42, got " + x);
}
PropertyInfo pInfo = typeof(testProperty.C1<string>).GetProperty("MyProp2");
if (pInfo == null) {
throw new Exception("Can't find newly added property: MyProp2");
}
ApplyUpdate(2);
Console.WriteLine("Applied second update");
x = testProperty.C1<string>.M1();
if (x != 45) {
throw new Exception("Expected 45, got " + x);
}
pInfo = typeof(testProperty.C1<string>).GetProperty("MyProp3");
if (pInfo == null) {
throw new Exception("Can't find newly added property: MyProp3");
}
MethodInfo mInfo = pInfo.GetGetMethod();
if (mInfo == null) {
throw new Exception("Can't find newly added property getter: MyProp3");
}
I'm including a zip file with a .dll
and .dmeta
and .dil
files with the changes. Use the following runner program to run it after unzipping the test case into some directory.
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
using System.Reflection;
if (args.Length != 1)
{
Console.WriteLine("Usage: generic-runner <directory>");
return 1;
}
string directory = args[0];
if (!Directory.Exists(directory))
{
Console.WriteLine("Directory does not exist: {0}", directory);
return 1;
}
foreach (var subdir in Directory.GetDirectories(directory))
{
var alc = System.Runtime.Loader.AssemblyLoadContext.Default;
var assemblies = Directory.GetFiles(subdir, "*.dll");
foreach (var assembly in assemblies)
{
Console.WriteLine ($">>> {assembly}");
var asm = alc.LoadFromAssemblyPath(assembly);
var type = asm.GetType("HotReloadTest", throwOnError: false);
if (type == null)
continue;
var mi = type.GetMethod("Run", BindingFlags.Static | BindingFlags.Public);
if (mi == null)
continue;
Console.WriteLine("====================================================");
Console.WriteLine($"Running {asm.GetName().Name}");
var passed = false;
try
{
mi.Invoke(null, null);
passed = true;
}
catch (Exception e)
{
Console.WriteLine(e);
}
if (passed)
Console.WriteLine($"Passed {asm.GetName().Name}");
}
}
return 0;
Expected result:
$ MONO_ENV_OPTIONS=--interp DOTNET_MODIFIABLE_ASSEMBLIES=debug dotnet run -- /tmp/reproProps
>>> /tmp/reproProps/testProperty/testProperty.dll
====================================================
Running testProperty
--- [testProperty]: Running test
Hello
--- [testProperty]: Applying update 1
setting MyProp2 to hello2
--- [testProperty]: Applying update 2
Applied second update
updated setting MyProp2 to hello2
setting MyProp3 to System.String[]
Passed testProperty
Actual result:
$ DOTNET_MODIFIABLE_ASSEMBLIES=debug dotnet run -- /tmp/reproProps
>>> /tmp/reproProps/testProperty/testProperty.dll
====================================================
Running testProperty
--- [testProperty]: Running test
Hello
--- [testProperty]: Applying update 1
setting MyProp2 to hello2
--- [testProperty]: Applying update 2
Version info:
I'm running a "main" installer from https://github.com/dotnet/installer. 8.0.100-preview.5.23228.7
% dotnet --info
.NET SDK:
Version: 8.0.100-preview.5.23228.7
Commit: 0ce891843a
Runtime Environment:
OS Name: Mac OS X
OS Version: 13.3
OS Platform: Darwin
RID: osx.13-arm64
Base Path: /Users/alklig/work/net8-playground/dotnet/sdk/8.0.100-preview.5.23228.7/
.NET workloads installed:
There are no installed workloads to display.
Host:
Version: 8.0.0-preview.4.23225.14
Architecture: arm64
Commit: 9a7db5556f
.NET SDKs installed:
8.0.100-preview.4.23225.3 [/Users/alklig/work/net8-playground/dotnet/sdk]
8.0.100-preview.4.23228.11 [/Users/alklig/work/net8-playground/dotnet/sdk]
8.0.100-preview.5.23228.7 [/Users/alklig/work/net8-playground/dotnet/sdk]
.NET runtimes installed:
Microsoft.AspNetCore.App 8.0.0-preview.4.23224.5 [/Users/alklig/work/net8-playground/dotnet/shared/Microsoft.AspNetCore.App]
Microsoft.AspNetCore.App 8.0.0-preview.4.23225.8 [/Users/alklig/work/net8-playground/dotnet/shared/Microsoft.AspNetCore.App]
Microsoft.AspNetCore.App 8.0.0-preview.5.23226.1 [/Users/alklig/work/net8-playground/dotnet/shared/Microsoft.AspNetCore.App]
Microsoft.NETCore.App 8.0.0-preview.4.23224.7 [/Users/alklig/work/net8-playground/dotnet/shared/Microsoft.NETCore.App]
Microsoft.NETCore.App 8.0.0-preview.4.23225.10 [/Users/alklig/work/net8-playground/dotnet/shared/Microsoft.NETCore.App]
Microsoft.NETCore.App 8.0.0-preview.4.23225.14 [/Users/alklig/work/net8-playground/dotnet/shared/Microsoft.NETCore.App]
Other architectures found:
None
Environment variables:
DOTNET_ROOT [/Users/alklig/work/net8-playground/dotnet]