As a bit of a novelty, I'm trying to see how different the IL from light weight code generated at runtime looks vs code generated by the VS compiler, as I noticed that VS code tends to run with a different performance profile for things like casts.
So I wrote the following code::
Func<object,string> vs = x=>(string)x;
Expression<Func<object,string>> exp = x=>(string)x;
var compiled = exp.Compile();
Array.ForEach(vs.Method.GetMethodBody().GetILAsByteArray(),Console.WriteLine);
Array.ForEach(compiled.Method.GetMethodBody().GetILAsByteArray(),Console.WriteLine);
Unfortunately, this throws an exception as GetMethodBody is apparently an illegal operation on code generated by expression trees. How can I in a library manner (i.e. not with an external tool unless the tool has an API) look at the code generated by code using lightweight codegen?
Edit: the error occurs on line 5, compiled.Method.GetMethodBody() throws the exception.
Edit2:
Does anyone know how to recover the local variables declared in the method? Or is there no way to GetVariables?
Yeah, doesn't work, the method is generated by Reflection.Emit. The IL is stored in the MethodBuilder's ILGenerator. You can dig it out but you have to be pretty desperate. Reflection is needed to get to the internal and private members. This worked on .NET 3.5SP1:
using System.Linq.Expressions;
using System.Reflection;
using System.Reflection.Emit;
...
var mtype = compiled.Method.GetType();
var fiOwner = mtype.GetField("m_owner", BindingFlags.Instance | BindingFlags.NonPublic);
var dynMethod = fiOwner.GetValue(compiled.Method) as DynamicMethod;
var ilgen = dynMethod.GetILGenerator();
var fiBytes = ilgen.GetType().GetField("m_ILStream", BindingFlags.Instance | BindingFlags.NonPublic);
var fiLength = ilgen.GetType().GetField("m_length", BindingFlags.Instance | BindingFlags.NonPublic);
byte[] il = fiBytes.GetValue(ilgen) as byte[];
int cnt = (int)fiLength.GetValue(ilgen);
// Dump <cnt> bytes from <il>
//...
On .NET 4.0 you'll have to use ilgen.GetType().BaseType.GetField(...) because the IL generator was changed, DynamicILGenerator, derived from ILGenerator.
The ILReader here should work.
ILVisualizer 2010 Solution
Based off Hans Passant's work I was able to dig a little deeper there appears to be a method that you should call, called BakeByteArray so the following works::
var dynMethod = fiOwner.GetValue(compiled.Method) as DynamicMethod;
var ilgen =dynamicMethod.GetILGenerator();
byte[] il = ilgen.GetType().GetMethod("BakeByteArray", BindingFlags.NonPublic | BindingFlags.Instance).Invoke(ilgen, null) as byte[];
This certainly helps, but I still have no way to resolve VariableInfo's just yet which is something that would help in my work.
The current solutions here aren't addressing the current situation in .NET 4 very well. You can use either DynamicILInfo or ILGenerator to create the dynamic method, but the solutions listed here do not work with DynamicILInfo dynamic methods at all.
Whether you use the DynamicILInfo method of generating IL or the ILGenerator method, the IL bytecode ends up in DynamicMethod.m_resolver.m_code. You don't have to check both methods and it's a less complex solution.
This is the version you should be using:
public static byte[] GetILBytes(DynamicMethod dynamicMethod)
{
var resolver = typeof(DynamicMethod).GetField("m_resolver", BindingFlags.Instance | BindingFlags.NonPublic).GetValue(dynamicMethod);
if (resolver == null) throw new ArgumentException("The dynamic method's IL has not been finalized.");
return (byte[])resolver.GetType().GetField("m_code", BindingFlags.Instance | BindingFlags.NonPublic).GetValue(resolver);
}
See this answer for more helper methods and a solution for the DynamicMethod token resolution issue.
I just merged #Hans Passant and #jnm2 solutions into a extension method and added useful comments:
public static byte[] GetIlAsByteArray(this DynamicMethod dynMethod)
{
// First we try to retrieve the value of "m_resolver" field,
// which will always be null unless the dynamic method is completed
// by either calling 'dynMethod.CreateDelegate()' or 'dynMethod.Invoke()' function.
// Source: https://learn.microsoft.com/en-us/dotnet/api/system.reflection.emit.dynamicmethod.getilgenerator
// (Remarks section)
// Note that the dynamic method object does not know when it is ready for use
// since there is not API which indicates that IL generation has completed.
// Source: https://referencesource.microsoft.com/#mscorlib/system/reflection/emit/dynamicmethod.cs,7fc135a2ceea0854,references
// (Comment lines)
// So, if the dynamic method is not completed, we will retrieve the "m_ILStream" field instead.
// The only difference I notice between "m_resolver" and "m_ILStream" fields is that the IL bytes in "m_ILStream"
// will have trailing zeros / null bytes depending on the amount of unused bytes in this buffer.
// ( The buffer size for "m_ILStream" is allocated by a call to 'dynMethod.GetILGenerator(streamSize)' function. )
BindingFlags bindingFlags = bindingFlags.Instance | bindingFlags.NonPublic;
object fiResolver = typeof(DynamicMethod).GetField("m_resolver", bindingFlags).GetValue(dynMethod);
if (fiResolver == null)
{
ILGenerator ilGen = dynMethod.GetILGenerator();
FieldInfo fiIlStream = null;
// Conditional for .NET 4.x because DynamicILGenerator class derived from ILGenerator.
// Source: https://stackoverflow.com/a/4147132/1248295
if (Environment.Version.Major >= 4)
{
fiIlStream = ilGen.GetType().BaseType.GetField("m_ILStream", bindingFlags);
}
else // This worked on .NET 3.5
{
fiIlStream = ilGen.GetType().GetField("m_ILStream", bindingFlags);
}
return fiIlStream.GetValue(ilGen) as byte[];
}
else
{
return (byte[])(fiResolver.GetType().GetField("m_code", bindingFlags).GetValue(fiResolver));
}
}
Related
I need to replace a method with a call to a method with the same signature so that I can essentially replace the original method with a new method. Currently, I have the code below, which works, but when I try to patch the method again, it simply does nothing. I'm not sure if that's because Harmony doesn't like when I try to transpile it twice, or something else, either way it prevents me from repeatedly redirecting the original method.
// this is factored out of Transpiler() because yield return reasons
private static IEnumerable<CodeInstruction> TranspilerIterator(IEnumerable<CodeInstruction> instructions,
MethodBase original) {
var name = original.Name;
var par = original.GetParameters();
var method = newGuiType.GetMethod(name, (BindingFlags) FLAGS);
Console.WriteLine($"{name} == null == {method == null}");
if ((method.CallingConvention & CallingConventions.HasThis) != 0)
yield return new CodeInstruction(OpCodes.Ldarg_0);
for (var i = 0; i < par.Length; i++)
yield return new CodeInstruction(OpCodes.Ldarg_S, par[i].Position + 1);
yield return new CodeInstruction(OpCodes.Call, method);
yield return new CodeInstruction(OpCodes.Ret);
}
which is called by this:
private void DoPatches() {
Logger.Debug("Performing patches.");
var methods = oldGuiType.GetMethods((BindingFlags) FLAGS);
var t = this.GetType().GetMethod("Transpiler", BindingFlags.NonPublic | BindingFlags.Static);
for (var i = 0; i < methods.Length; i++) {
var name = methods[i].Name;
Logger.Debug($"Transpiling {name}");
harmony.Patch(methods[i], transpiler: new HarmonyMethod(t));
}
}
I can't use a prefix because I need to know the signature to get the args in a prefix, and I don't know the signature.
I know there are other libraries to make essentially this, but the game I'm modding ships with Harmony so I don't have to ship a whole lib with my very small mod.
For every change to an original method (like adding or removing a transpiler) Harmony will recalculate the replacement method by doing this (in pseudo code):
original_IL -> transpiler1 -> transpiler2 -> ... -> transpiler_n -> replacement_IL
where transpiler 1..n are all active transpilers. It then build the replacement by (roughly) structuring it like this:
// Note: the following is very simplified and only used to illustrate
// the difference between prefix/postfix and a transpiler.
REPLACEMENT()
{
if (Prefix_1() == false) return
// ...
if (Prefix_n() == false) return
// replacement_IL_here
Postfix_1()
// ...
Postfix_n()
}
Internally, Harmony has to therefore keep track of all patches and since those can be from different Assemblies it would need to serialize/deserialize state - which is in principle impossible if you have arbitrary state. Therefore, it only stores the simplest key for each patch possible: its MethodInfo which must be a static method.
As a result you cannot apply the same patch multiple times. It makes little sense since you could easily put all your code into one patch anyway.
For this application, ie updating a method to a newer method with an identical signature, Memory.DetourMethod(MethodBase original, MethodBase replacement) did what I needed.
// assuming newType is just a newer version of oldType
var newMethod = newType.getMethod("SomeMethod");
var oldMethod = oldType.getMethod("SomeMethod");
Memory.DetourMethod(oldMethod, newMethod);
This code effectively replaces the old method with the new method. The way it actually works is a bit more complicated.
Before beginning, this is my first question on SO. So there might be faults or lack of information about the problem. Please let me know if there's something that I need to correct. Thanks.
Using TypeBuilder, I'm building a class that implements an interface that contains a method. After implementing that method with ILGenerator, then I call TypeBuilder.CreateType() and everything goes well in the normal case.
But if the method contains any parameter with the in modifier, also known as readonly reference for value types, TypeBuilder.CreateType() throws TypeLoadException("Method 'SomeMethod' ... does not have an implementation.").
Unlike the usual case of TypeLoadException that implemented method with the same signature as the one declared in the interface(s) doesn't exist, this problem is raised only when the method contains in parameter(s) even signatures are the same. When I remove or change the in modifier to ref or out, TypeBuilder.CreateType() successfully recognizes the generated method as an implementation of one declared in the interface, and the type is built normally.
Here's a fully compilable example:
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Reflection;
using System.Reflection.Emit;
using System.Threading;
namespace EmitMethodWithInParamTest
{
public struct StructParam
{
public String Data;
}
public interface ISomeInterface
{
Int32 SomeMethod(in StructParam param);
}
static class EmitExtension
{
public static void ReplicateCustomAttributes(this ParameterBuilder paramBuilder, ParameterInfo paramInfo)
{
foreach (var attrData in paramInfo.GetCustomAttributesData())
{
var ctorArgs = attrData.ConstructorArguments.Select(arg => arg.Value).ToArray();
// Handling variable arguments
var ctorParamInfos = attrData.Constructor.GetParameters();
if (ctorParamInfos.Length > 0 &&
ctorParamInfos.Last().IsDefined(typeof(ParamArrayAttribute)) &&
ctorArgs.Last() is IReadOnlyCollection<CustomAttributeTypedArgument> variableArgs)
{
ctorArgs[ctorArgs.Length - 1] = variableArgs.Select(arg => arg.Value).ToArray();
}
var namedPropArgs = attrData.NamedArguments.Where(arg => !arg.IsField);
var namedPropInfos = namedPropArgs.Select(arg => (PropertyInfo)arg.MemberInfo).ToArray();
var namedPropValues = namedPropArgs.Select(arg => arg.TypedValue.Value).ToArray();
var namedFieldArgs = attrData.NamedArguments.Where(arg => arg.IsField);
var namedFieldInfos = namedFieldArgs.Select(arg => (FieldInfo)arg.MemberInfo).ToArray();
var namedFieldValues = namedFieldArgs.Select(arg => arg.TypedValue.Value).ToArray();
var attrBuilder = new CustomAttributeBuilder(attrData.Constructor,
ctorArgs, namedPropInfos, namedPropValues, namedFieldInfos, namedFieldValues);
paramBuilder.SetCustomAttribute(attrBuilder);
}
}
}
class Program
{
static Program()
{
Thread.CurrentThread.CurrentUICulture = CultureInfo.GetCultureInfo("en-us");
}
static void Main(String[] args)
{
var assemblyBuilder = AssemblyBuilder.DefineDynamicAssembly(new AssemblyName("DynamicAssembly"), AssemblyBuilderAccess.Run);
var moduleBuilder = assemblyBuilder.DefineDynamicModule("MainModule");
var typeBuilder = moduleBuilder.DefineType("SomeClass",
TypeAttributes.Public | TypeAttributes.Class | TypeAttributes.AutoClass | TypeAttributes.AnsiClass | TypeAttributes.BeforeFieldInit | TypeAttributes.AutoLayout,
null /*base class*/,
new[] { typeof(ISomeInterface) });
var methodInfoToImpl = typeof(ISomeInterface).GetMethod(nameof(ISomeInterface.SomeMethod));
var paramInfos = methodInfoToImpl.GetParameters();
var methodBuilder = typeBuilder.DefineMethod(methodInfoToImpl.Name,
MethodAttributes.Public | MethodAttributes.Virtual | MethodAttributes.Final,
CallingConventions.HasThis,
methodInfoToImpl.ReturnType,
paramInfos.Select(pi => pi.ParameterType).ToArray());
foreach (var paramInfo in paramInfos)
{
// paramInfo.Position is zero-based but DefineParameter requires 1-based index.
var paramBuilder = methodBuilder.DefineParameter(paramInfo.Position + 1, paramInfo.Attributes, paramInfo.Name);
if (paramInfo.Attributes.HasFlag(ParameterAttributes.HasDefault))
{
paramBuilder.SetConstant(paramInfo.DefaultValue);
}
paramBuilder.ReplicateCustomAttributes(paramInfo);
}
// Dummy implementation for example. Always throws NotImplementedException.
var ilGen = methodBuilder.GetILGenerator();
ilGen.Emit(OpCodes.Newobj, typeof(NotImplementedException).GetConstructor(Type.EmptyTypes));
ilGen.Emit(OpCodes.Throw);
var builtType = typeBuilder.CreateType(); // <- TypeLoadException("Method 'SomeMethod' in type 'SomeClass' from assembly 'DynamicAssembly, ...' does not have an implementation.") is thrown.
var generatedObj = (ISomeInterface)Activator.CreateInstance(builtType);
var someParam = new StructParam() { Data = "SomeData" };
var result = generatedObj.SomeMethod(in someParam); // <- NotImplementedException expected by dummy implementation if executed.
Console.WriteLine($"Result: {result}");
}
}
}
This code is also uploaded to Pastebin.
While digging down this problem, I found that the in parameter has two custom attributes, InteropServices.InAttribute and CompilerServices.IsReadOnlyAttribute. But when I generate a method without implementing the interface (this succeeds normally because no signature matching required), in parameter of generated method has only one custom attribute, InAttribute. So I replicated all custom attributes of parameters from the interface, but still TypeLoadException is being raised.
I've tested this on .NET Framework 4.6.1 and .NET Core 2.2 with C# 7.2 and 7.3. And all environments gave me the same exception. I'm using Visual Studio 2017 on Windows.
Is there anything that I have missed or are there any workarounds?
Thank you for any help in advance.
After writing the question above, I've been investigated built binary of sample code in IL and source code of CoreCLR for a few days, and now I found the problem and solution.
In short, required and optional custom modifiers of return type and each parameter type take a part of method signature like each types do, and it had to be replicated manually. I thought that it will be done by passing ParameterAttributes.In to MethodBuilder.DefineParameter and replicating the custom attribute InAttribute, but it was wrong.
And, among in, ref and out modifiers, only in emits a required custom modifier to specified parameter. In contrast, ref and out are represented only with their type itself. This is the reason why only in didn't work as expected.
To replicate custom modifiers, call to TypeBuilder.DefineMethod need be modified like this:
var methodBuilder = typeBuilder.DefineMethod(methodInfoToImpl.Name,
MethodAttributes.Public | MethodAttributes.Virtual | MethodAttributes.Final,
CallingConventions.HasThis,
methodInfoToImpl.ReturnType,
methodInfoToImpl.ReturnParameter.GetRequiredCustomModifiers(), // *
methodInfoToImpl.ReturnParameter.GetOptionalCustomModifiers(), // *
paramInfos.Select(pi => pi.ParameterType).ToArray(),
paramInfos.Select(pi => pi.GetRequiredCustomModifiers()).ToArray(), // *
paramInfos.Select(pi => pi.GetOptionalCustomModifiers()).ToArray() // *
);
Marked lines with // * are newly added to replicate custom modifiers of return/parameter types.
Or, we can do this by calling MethodBuilder.SetSignature method after calling DefineMethod without any type and custom modifiers arguments. If we decided to call SetSignature separately, we need to call it before any DefineParameter, SetCustomAttribute, Equals(Object), SetImplementationFlags, getter of property Signature and many other methods that call the internal method MethodBuilder.GetMethodSignature() that cache bytes representing method signature.
Thank you for reading and giving me advice. :)
In general I need to be able to invoke any unmanaged function from any DLL which I don't know at the compile time.
All the articles I seen (like this https://blogs.msdn.microsoft.com/jonathanswift/2006/10/03/dynamically-calling-an-unmanaged-dll-from-net-c/) suggest using delegates but I don't know at the compile time which function I gonna invoke and even which and how many parameters it requires.
Basically I have a user input like: call "Kernel32.dll" function "DeleteFile" arguments ["C:\testfile.txt"].
Could you please advice at least how to google it? The word "dynamically" doesn't help..
The task itself is a bit crazy just because actually it's a university project. Not sure it can be useful in real life..
var dll = "kernel32.dll";
var fun = "DeleteFile";
var args = new object[] { "C:\\dev\\test.txt" };
IntPtr pDll = NativeMethods.LoadLibrary(dll);
IntPtr pFun = NativeMethods.GetProcAddress(pDll, fun);
// How can I call it in a different way, without having a delegate?
Marshal.GetDelegateForFunctionPointer(pFun, typeof(?????));
I also agree with idea of Roslyn, but when I see "Dynamic" and "P/Invoke", good old System.Reflection.Emit comes to mind:
var asmName = new AssemblyName("Win32");
var asmBuilder = AppDomain.CurrentDomain.DefineDynamicAssembly(asmName, AssemblyBuilderAccess.Run);
var modBuilder = asmBuilder.DefineDynamicModule("Win32", emitSymbolInfo: false);
var typeBuilder = modBuilder.DefineType("Win32.User32", TypeAttributes.Class | TypeAttributes.Public);
// Optional: Use if you need to set properties on DllImportAttribute
var dllImportCtor = typeof(DllImportAttribute).GetConstructor(new Type[] { typeof(string) });
var dllImportBuilder = new CustomAttributeBuilder(dllImportCtor, new object[] { "user32.dll" });
var pinvokeBuilder = typeBuilder.DefinePInvokeMethod(
name: "ShowMessageBox",
dllName: "user32.dll",
entryName: "MessageBoxW",
attributes: MethodAttributes.Static | MethodAttributes.Public,
callingConvention: CallingConventions.Standard,
returnType: typeof(int), // typeof(void) if there is no return value.
// TODO: Construct this array from user input somehow:
parameterTypes: new Type[] { typeof(IntPtr), typeof(string), typeof(string), typeof(uint) },
nativeCallConv: CallingConvention.Winapi,
nativeCharSet: CharSet.Unicode);
pinvokeBuilder.SetCustomAttribute(dllImportBuilder);
Type user32Type = typeBuilder.CreateType();
const uint MB_YESNOCANCEL = 3;
user32Type
.GetMethod("ShowMessageBox", BindingFlags.Static | BindingFlags.Public)
// TODO: User input goes here:
.Invoke(null, new object[] { IntPtr.Zero, "Message Text", "Message Caption", MB_YESNOCANCEL });
Not pretty, I know. Just my $0.02.
WARNING: If this code is going to be called multiple times in a long running application, consider creating a new AppDoman each time, and disposing it when call is done; because this is the only way to unload generated dynamic assembly.
Not sure exactly what the end goal is, but I would take a slightly different approach. In .NET compilers are a service you can use, so you can dynamically generate an assembly and then load it and use it. So your program essentially is a "generator" you translate the input into code, compile it, load it, run it. You can use roslyn for this.
You can skip to my approach if you don't mind what I'm actually trying to do.
What I'm trying to do
Hey I'm trying to make mutant testing,
inspired by the talk
http://www.infoq.com/presentations/kill-better-test
But I'm using c# and the best mutant libraries are made in java such as
http://pitest.org/
There are some frameworks for c# such as ninjaturtles and visualmutator,
but they both doesn't work in my computer for some reason(I get a weird error).
and also I thought it would be interesting creating my own.
About mutant testing
For those who doesn't know what is mutant testing,
it's a testing for the tests, most people use
code coverage to check that their test cover all the scenarios,
but it's not enough,
cause just because it gets to a piece of code doesn't mean it tests it.
It changes a piece of code, and if the tests still pass
it means you didn't tested the piece of code.
My approach
So I've tried starting with a simple code
that gets the il codes of a method.
var classType = typeof(MethodClass);
var methodInfo = classType.GetMethod("ExecuteMethod", BindingFlags.NonPublic | BindingFlags.Static);
byte[] ilCodes = methodInfo.GetMethodBody().GetILAsByteArray();
this is the MethodClass I'm trying to change:
public class MethodClass
{
private static int ExecuteMethod()
{
var i = 0;
i += 5;
if (i >= 5)
{
i = 2;
}
return i;
}
}
now I'm trying to replace the ils
for (int i = 0; i < ilCodes.Length; i++)
{
if (ilCodes[i] == OpCodes.Add.Value)
{
ilCodes[i] = (byte)OpCodes.Sub.Value;
}
}
but then I'm not sure how to update my function to work with the new il codes.
I've tried using
var dynamicFunction = new DynamicMethod("newmethod", typeof(int), null);
var ilGenerator = dynamicFunction.GetILGenerator();
and then the il generator has a function emit, that gets operator and value, so I could use this. but I don't have the value to put in the emit..
Does anybody know how to do it?
Developing an app for Android (and later iOS) using Xamarin/Mono. Normally I use this code to call a non-static generic method and it works great:
serverService.GetCustomListObject<T> (firstRequestInLine,
null,
onGetCustomListObjectFromThread<T>,
onGetCustomListObjectFromThreadError);
where the callbacks are defined as:
private void onGetCustomListObjectFromThread<T> (List<T> list,
RequestStateGen<T>.SuccessfullDelegateType successDel
{ ... }
and
private void onGetCustomListObjectFromThreadError (String error,
WebRequest failedRequest)
{ ... }
However, now I need to call GetCustomListObject<t> where t is set dynamically. I am quite new to generics but have tried the following code from other examples without success:
typeof(ServerService).GetMethod ("GetCustomListObject").MakeGenericMethod (t).Invoke (serverService, new object[] {
firstRequestInLine,
null,
typeof(LocalServerService).GetMethod ("onGetCustomListObjectFromThread").MakeGenericMethod (t),
typeof(LocalServerService).GetMethod ("onGetCustomListObjectFromThreadError")
});
where LocalServerService is the class all my examples here are in and serverService is of type ServerService
I get the following error:
Error: Ambiguous matching in method resolution
Edit: GetCustomListObject in ServerService:
public void GetCustomListObject<T> (WebRequest request,
RequestStateGen<T>.SuccessfullDelegateType successDelegate,
RequestStateGen<T>.InternalSuccessDelegateType internalSuccessDelegate,
RequestStateGen<T>.ErrorDelegateType errorDelegate)
In your original code, you were calling a method passing in delegates.
In your reflection code, you appear to be passing in MethodInfo values instead - I don't believe they will automatically be converted to delegates.
Unfortunately it's hard to give a good code sample without knowing the declaration of your GetCustomListObject method, but you want something like:
Type thirdArgType = typeof(Foo<>).MakeGenericGenericType(t);
MethodInfo thirdArgMethod = typeof(LocalServerService)
.GetMethod("onGetCustomListObjectFromThread",
BindingFlags.Instance | BindingFlags.NonPublic)
.MakeGenericMethod(t);
Delegate thirdArg = Delegate.CreateDelegate(thirdArgType, this, thirdArgMethod);
MethodInfo fourthArgMethod = typeof(LocalServerService)
.GetMethod("onGetCustomListObjectFromThreadError",
BindingFlags.Instance | BindingFlags.NonPublic);
Delegate fourthArg = Delegate.CreateDelegate(typeof(Bar), this, fourthArgMethod);
MethodInfo method = typeof(ServerService).GetMethod("GetCustomListObject")
.MakeGenericMethod (t);
method.Invoke(serverService,
new object[] {firstRequestInline, null, thirdArg, fourthArg });