Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Can't emit Ldftn with symbolDocumentWriter #6

Open
odinmillion opened this issue Aug 9, 2017 · 0 comments
Open

Can't emit Ldftn with symbolDocumentWriter #6

odinmillion opened this issue Aug 9, 2017 · 0 comments

Comments

@odinmillion
Copy link

odinmillion commented Aug 9, 2017

We are trying to emit Ldftn instruction. In some cases we see exception System.ArgumentException.

Look at this code:

public class Dummy
{
  public static int Add10(int x)
  {
    return x + 10;
  }
}
[TestFixture]
public class Tests
{
  [TestCase(true)]
  [TestCase(false)]
  public void TestLdftn(bool useDocumentWriter)
  {
    var id = $"asm-{Guid.NewGuid()}";
    var assembly = AppDomain.CurrentDomain.DefineDynamicAssembly(new AssemblyName(id), AssemblyBuilderAccess.RunAndCollect);
    var module = assembly.DefineDynamicModule(name: id, fileName: id + ".dll", emitSymbolInfo: true);
    var fooTypeBuilder = module.DefineType("Foo", TypeAttributes.Public | TypeAttributes.Class);
    var symWriter = module.GetSymWriter();
    var barMethod = fooTypeBuilder.DefineMethod("Bar", MethodAttributes.Public | MethodAttributes.Static, typeof(int), new[] { typeof(int) });
    var documentName = fooTypeBuilder.Name + "." + barMethod.Name + ".cil";
    var documentWriter = symWriter.DefineDocument(documentName, SymDocumentType.Text, SymLanguageType.ILAssembly, Guid.Empty);
    using (var il = useDocumentWriter
      ? new GroboIL(barMethod, documentWriter)
      : new GroboIL(barMethod))
    {
      il.Ldnull(); // stack: [null]
      il.Ldftn(typeof(Dummy).GetMethod("Add10")); // stack: [null, Add10*]
      il.Newobj(typeof(Func<int, int>).GetConstructor(new[] { typeof(object), typeof(IntPtr) })); // stack: [func]
      il.Ldc_I4(5); // stack: [func, 5]
      il.Call(typeof(Func<int, int>).GetMethod("Invoke")); // stack: [int]
      il.Ret();
    }
    var fooType = fooTypeBuilder.CreateType();

    var result = fooType.GetMethod("Bar").Invoke(null, new object[] { 5 });

    result.Should().Be(15);
  }
}

We can succesfully emit and run code without document writer. But we see that exception in opposite scenario:

System.ArgumentException : Не удается передать указанный код операции в метод EmitCall.
Имя параметра: opcode
   в System.Reflection.Emit.ILGenerator.EmitCall(OpCode opcode, MethodInfo methodInfo, Type[] optionalParameterTypes)
   в GrEmit.GroboIL.Emit(OpCode opCode, ILInstructionParameter parameter) в C:\BuildAgent\work\249acc80a2fd7042\GrEmit\GrEmit\GroboIL.cs:строка 2000
   в GrEmit.GroboIL.Dispose() в C:\BuildAgent\work\249acc80a2fd7042\GrEmit\GrEmit\GroboIL.cs:строка 147
   в GremitBugs.Tests.TestLdftn(Boolean useDocumentWriter) в C:\Users\****\Documents\Visual Studio 2017\Projects\GremitWeaks\GremitBugs\Tests.cs:строка 45

We assume that bug is located here:

else if(parameter is MethodILInstructionParameter)
il.EmitCall(opCode, ((MethodILInstructionParameter)parameter).Method, null);

Sometimes MethodILInstructionParameter leads to emit non call opcodes :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Development

No branches or pull requests

1 participant