19

I'm working on a library that allows users to input arbitrary expressions. My library then compiles those expressions as part of a larger expression into a delegate. Now, for still unknown reasons compiling the expression with Compile sometimes/often results in code that is far slower than it would be if it weren't a compiled expression. I asked a question about this before and one workaround was to not use Compile, but CompileToMethod and create a static method on a new type in a new dynamic assembly. That works and the code is fast.

But users can input arbitrary expressions and it turns out that if the user calls a non-public function or accesses a non-public field in the expression, it throws a System.MethodAccessException (in the case of a non-public method) when the delegate is invoked.

What I could probably do here is create a new ExpressionVisitor that checks if the expression accesses anything non-public and use the slower Compile in those cases, but I'd rather have that the dynamic assembly somehow gets the rights to access the non-public members. Or find out if there's anything I can do about Compile being slower (sometimes).

The full code to reproduce this problem:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Linq.Expressions;
using System.Reflection;
using System.Reflection.Emit;

namespace DynamicAssembly
{
  public class Program
  {
    private static int GetValue()
    {
      return 1;
    }

    public static int GetValuePublic()
    {
      return 1;
    }

    public static int Foo;

    static void Main(string[] args)
    {
      Expression<Func<int>> expression = () => 10 + GetValue();

      Foo = expression.Compile()();

      Console.WriteLine("This works, value: " + Foo);

      Expression<Func<int>> expressionPublic = () => 10 + GetValuePublic();

      var compiledDynamicAssemblyPublic = (Func<int>)CompileExpression(expressionPublic);

      Foo = compiledDynamicAssemblyPublic();

      Console.WriteLine("This works too, value: " + Foo);

      var compiledDynamicAssemblyNonPublic = (Func<int>)CompileExpression(expression);

      Console.WriteLine("This crashes");

      Foo = compiledDynamicAssemblyNonPublic();
    }

    static Delegate CompileExpression(LambdaExpression expression)
    {
      var assemblyBuilder = AppDomain.CurrentDomain.DefineDynamicAssembly(
        new AssemblyName("MyAssembly"+ Guid.NewGuid().ToString("N")), 
        AssemblyBuilderAccess.Run);

      var moduleBuilder = assemblyBuilder.DefineDynamicModule("Module");

      var typeBuilder = moduleBuilder.DefineType("MyType", TypeAttributes.Public);

      var methodBuilder = typeBuilder.DefineMethod("MyMethod", 
        MethodAttributes.Public | MethodAttributes.Static);

      expression.CompileToMethod(methodBuilder);

      var resultingType = typeBuilder.CreateType();

      var function = Delegate.CreateDelegate(expression.Type, 
        resultingType.GetMethod("MyMethod"));

      return function;
    }
  }
}
Community
  • 1
  • 1
JulianR
  • 16,213
  • 5
  • 55
  • 85
  • I don't have an answer for you, but why is it necessary to support calling private methods? – jlew Apr 22 '11 at 19:24
  • Because the user expects it should be possible. Because they *are* accessible when he creates the expression, like `() => CallPrivateMethod()`, but they will fail at runtime. There's nothing to him that would indicate it doesn't work until he runs it and it crashes and burns. That's really bad and violates the rule of "least surprise" so I can't justify doing that and I'll have to settle for slow code. – JulianR Apr 22 '11 at 19:33
  • Makes sense, if the user is a C# programmer (as opposed to somebody typing expressions into a form, for example). Have you benchmarked release vs debug mode for the compiled delegate? How do they compare with each other? – jlew Apr 22 '11 at 20:24
  • @jlew - Yeah, it's going to be a library used by programmers. As for details on the performance of compiling expression trees, I can refer you to my linked question which goes in depth with that :) – JulianR Apr 22 '11 at 22:29
  • This might be a half-baked thought, maybe you could split the difference performance-wise by replacing calls to private methods in the expression tree with calls to delegates that are passed in to your MethodBuilder method as parameters. Then, wrap up the private methods in delegates and pass them into your new method as arguments. This would get around the MethodAccess issue, but who knows whether it would negate the performance benefits. – jlew Apr 25 '11 at 13:19

4 Answers4

6

The problem is not permissions because there is no permission that can allow you to access a non-public field or member of another class without reflection. This is analogous to the situation where you compiled two non-dynamic assemblies and one assembly calls a public method in the second assembly. Then if you change the method to private without recompiling the first assembly, the first assemblies call will now fail at runtime. In other words the expression in your dynamic assembly is being compiled into an ordinary method call which it doesn't have permission to call anymore than you do from another class even in the same assembly.

Since no permission can solve your problem, you might be able to transform non-public field and method references into subexpressions that use reflection.

Here is an example taken from your test case. This fails:

Expression<Func<int>> expression = () => 10 + GetValue();

but this will succeed:

Expression<Func<int>> expression = () => 10 + (int)typeof(Program).GetMethod("GetValue", BindingFlags.Static | BindingFlags.NonPublic).Invoke(null, null);

Since this does not crash with an exception, you can see that your dynamic assembly does have reflection permission and it can access the private method, it just can't do it using an ordinary method call that CompileToMethod results in.

Rick Sladkey
  • 33,988
  • 6
  • 71
  • 95
1

I once had an issue accessing private elements of a class, from generated IL code using DynamicMethod.

It turned out that there was an overload of the constructor of the class DynamicMethod that receives the type of class into wich private access would be allowed:

http://msdn.microsoft.com/en-us/library/exczf7b9.aspx

This link contains samples of how to access private data... I know that this has nothing to do with expression trees, but it might give you some clues on how to do it.

May be there is some sort of similar thing when compiling expression trees... or that you can create that expression tree as a DynamicMethod.

Miguel Angelo
  • 23,796
  • 16
  • 59
  • 82
  • Thanks. But `CompileToMethod` only has one way to be called: it needs to be passed an instance of `MethodBuilder`. And you can only get a `MethodBuilder` from a `TypeBuilder` and you need a `ModuleBuilder` for that and for *that* you need an `AssemblyBuilder`. – JulianR Apr 24 '11 at 17:45
1

If the non-dynamic assembly is built by you, you can actually include a InternalsVisibleTo for the the dynamic assembly (even works with a strong name). That would allow using internal members, which may be enough in your case?

To get an idea, here's an example which shows hot to enable the dynamic assembly of Moq to use internal stuff from another assembly: http://blog.ashmind.com/2008/05/09/mocking-internal-interfaces-with-moq/

If this approach is not sufficient, I'd go with a combination of Rick's and Miguel's suggestions: create "proxy" DynamicMethods for each invocation to a non-public member and change the expression tree so that they are used instead of the original invocations.

Lucero
  • 59,176
  • 9
  • 122
  • 152
0

You can use the undocumented attribute IgnoreAccessCheckTo which is similar to InternalsVisibleTo but in the assembly that wants to access it.

for more details see my answer to this question.

yoel halb
  • 12,188
  • 3
  • 57
  • 52