Skip to content

[EnC] FieldInfo.GetValue on a newly-added ValueType field crashes CoreCLR #76702

@lambdageek

Description

@lambdageek

Found this while working on #76462, but it also reproduces with net7 (and probably net6.0 and older, see below)

Repro:

  1. dotnet new console
  2. Use the following for Program.cs:
// #define UPDATE

using System.Reflection;

public class Test {

	public static void Main ()
	{	
		bool stop = false;

		Console.CancelKeyPress += new ((sender, ev) => {
		  ev.Cancel = true;
		  stop = true;
		});

		var c0 = new C();
		int i = 0;
		while (!stop) {
		  Body (ref i);
		}
		Console.WriteLine ("stopping");
		GC.KeepAlive (c0);
	}

	static void Body (ref int i)
	{
		Console.WriteLine($"alive {i}");
		i += 1;
		Thread.Sleep (1000);
#if UPDATE
	        var c = new C();
                var fi = c.GetType().GetField ("MyS");

		var s = fi.GetValue (c); // bad!

		Console.WriteLine ("still alive");
#endif
	}

	class C {

#if UPDATE
		public S MyS;
#endif

		public C() {
#if UPDATE
			MyS = new S {
				D = -1985.0,
				O = new int[2] {15, 17},
			};
#endif
		}

#if UPDATE
		public struct S {
			public double D;
			public object O;
		};
#endif
	}
}
  1. Run dotnet watch (but I believe this would also reproduce with EnC in Visual Studio)
  2. Change // #define UPDATE to #define UPDATE and save (or hit "Apply Changes" in VS)

Expected result:

The hot reload change is applied and the application keeps running.

Actual result:

dotnet watch 🚀 Started
alive 0
alive 1
alive 2
alive 3
alive 4
alive 5
alive 6
dotnet watch ⌚ File changed: ./Program.cs.
alive 7
dotnet watch 🔥 Hot reload of changes succeeded.
alive 8
dotnet watch ❌ Exited with error code 139
dotnet watch ⏳ Waiting for a file to change before restarting dotnet...
dotnet watch 🛑 Shutdown requested. Press Ctrl+C again to force exit.

That is, the child process - dotnet running the user code crashed with exit code 139.

In #76462 we actually get a good combination of error messages from a CoreCLR builds on OSX and Windows, respectively:

Mac:

Assert failure(PID 21236 [0x000052f4], Thread: 191148 [0x2eaac]): IS_ALIGNED(src, sizeof(SIZE_T))
    File: /Users/runner/work/1/s/src/coreclr/classlibnative/bcltype/arraynative.cpp Line: 736
    Image: /private/tmp/helix/working/B02E09C7/p/dotnet

Windows:

Fatal error. Internal CLR error. (0x80131506)
   at System.RuntimeFieldHandle.GetValue(System.Reflection.RtFieldInfo, System.Object, System.RuntimeType, System.RuntimeType, Boolean ByRef)
   at System.Reflection.RtFieldInfo.GetValue(System.Object)
   at System.Reflection.Metadata.ApplyUpdateTest+<>c.<TestAddInstanceField>b__10_0()
   at System.RuntimeMethodHandle.InvokeMethod(System.Object, Void**, System.Signature, Boolean)
   at System.Reflection.MethodInvoker.InterpretedInvoke(System.Object, IntPtr*)
   at System.Reflection.MethodInvoker.Invoke(System.Object, IntPtr*, System.Reflection.BindingFlags)
   at System.Reflection.MethodInvoker.InlinedInvoke(System.Object, IntPtr*, System.Reflection.BindingFlags)
   at System.Reflection.RuntimeMethodInfo.Invoke(System.Object, System.Reflection.BindingFlags, System.Reflection.Binder, System.Object[], System.Globalization.CultureInfo)
   at System.Reflection.MethodBase.Invoke(System.Object, System.Object[])
   at Microsoft.DotNet.RemoteExecutor.Program.Main(System.String[])

Which points to InvokeUtil::GetFieldValue

if (pField->IsStatic())
p = pField->GetCurrentStaticAddress();
else {
p = (*((BYTE**)target)) + pField->GetOffset() + sizeof(Object);
}
GCPROTECT_END();
// copy the field to the unboxed object.
// note: this will be done only for the non-remoting case
if (p) {
CopyValueClass(obj->GetData(), p, fieldType.AsMethodTable());

This looks wrong - p = (*((BYTE**)target)) + pField->GetOffset() + sizeof(Object); for fields added by EnC - they aren't at some offset, they're allocated entirely separately from the target object.

By the way, the same wrong logic is also in InvokeUtil::SetValidField so probably RtFieldInfo.SetField/RuntimeFieldHandle.SetField has issues too.

Metadata

Metadata

Type

No type

Projects

No projects

Milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions