Related to How to mutate a boxed struct using IL I am trying to change the value of a boxed value type but in a generic way, so trying to implement the following method:
void MutateValueType<T>(object o, T v) where T : struct
So the following should be possible:
var oi = (object)17;
MutateValueType<int>(oi, 43);
Console.WriteLine(oi); // 43
var od = (object)17.7d;
MutateValueType<double>(od, 42.3);
Console.WriteLine(od); // 42.3
I am failing to get it this to work on .NET Framework (see comment by @hvd that the implementation without typeof(Program).Module
works on other runtimes). I have implemented this as seen below. However, this fails when calling the delegate del
with a:
System.Security.VerificationException: 'Operation could destabilize the runtime.'
Here is the implementation I have come up with:
public static void MutateValueType<T>(object o, T v)
{
var dynMtd = new DynamicMethod("EvilMutateValueType",
typeof(void), new Type[] { typeof(object), typeof(T) });
var il = dynMtd.GetILGenerator();
il.Emit(OpCodes.Ldarg_0); // object
il.Emit(OpCodes.Unbox, typeof(T)); // T&
il.Emit(OpCodes.Ldarg_1); // T (argument value)
il.Emit(OpCodes.Stobj, typeof(T)); // stobj !!T
il.Emit(OpCodes.Ret);
var del = (Action<object, T>)dynMtd.CreateDelegate(typeof(Action<object, T>));
del(o, v);
}
The above should be equivalent to the below IL, that works, but still the above fails, so the question is why this doesn't work.
.method public hidebysig static void Mutate<T>(object o, !!T Value) cil managed aggressiveinlining
{
.maxstack 2
ldarg.0
unbox !!T
ldarg.1
stobj !!T
ret
}
One solution, is by making an
Unbox
method in IL that callsunbox
and returns aref
to the type contained in the object:And then using this like:
This correctly outputs:
NOTE: This requires C# 7 support for
ref
returns.This might be added to say https://github.com/DotNetCross/Memory.Unsafe but it must also be possible with
il.Emit
also, so I am looking for that.The difference is that
DynamicMethod
by default requires verifiable code, whereas your own code (including custom IL) is by default allowed to be unverifiable.You can treat the
DynamicMethod
as part of your own module, allowing it to contain unverifiable IL, by specifying the module:Despite some other issues in PEVerify making it hard to get good diagnostics, it looks like this is intended to at least not be verifiable:
But it looks like it's intended to still be correct:
Note that there is no restriction on controlled-mutability managed pointers here, any pointer to
T
is allowed.Therefore, ensuring that no verification happens for your IL is the right way to go.