Debug support for internal types?

Jan 27, 2009 at 10:16 PM
Running on 0.9 DLR release...

If I do a debug compile against DLR trees built using my own internal (non-public) types, I get MethodAccessException (attempting a method invocation, obviously).

A debug compile against the same types marked public (instead of internal) works fine.

A non-debug compile against the internal types works fine.

Did I miss a flipped bit somewhere? Is this a supported scenario? I've got lots of internal types that I want to execute in DLR but not expose to the world at large...

Thanks,
Josh

Jan 27, 2009 at 10:35 PM

> A debug compile against the same types marked public (instead of internal) works fine.
> A non-debug compile against the internal types works fine.
> Did I miss a flipped bit somewhere? Is this a supported scenario? I've got lots of internal types that I want to execute in DLR but not expose to the world at large...

Running expression trees against internal types is tricky. CLR security will generally prevent it from working. If the code is running in a DynamicMethod, it can work thanks to a special CLR feature (skipVisibility), as long as your application has the right permissions. However, if the code is emitted into a dynamic assembly using a TypeBuilder, it can’t refer to a non-public type in another assembly (which your language’s assembly affectively is).

I’m not 100% sure why it would work in release but not debug. My guess is it works in release mode because we’re generate DynamicMethods, whereas in debug mode we’re trying to save the code into Snippets so we can run peverify against it.

I would not recommend emitting ETs that use non-public types/methods, and instead make them public. If you’re worried about users seeing them, you could put them in some class/namespace that’s marked as internal use only. Unfortunately that’s the closest thing we currently support.

- John

Jan 28, 2009 at 1:06 AM
Yes, it makes perfect sense that the gen'ed assembly can't see my internal types... what was throwing me off was the difference in debug vs. release behavior.

I tracked down the calls inside the DLR to AppDomain.DefineDynamicAssembly()... turns out that code path is only invoked for debug builds... so that jives with your explanation.

Incidentally, I see that the gen'ed assembly is always named "Snippets.debug" so (you can see where this is going :-) ) I added [assembly: InternalsVisibleTo( "Snippets.debug" )] to my assembly with internal types, and my trees execute fine now.

It's hacky, and I'd frankly prefer a better solution (deterministic control over the gen'ed assembly name would be a good start) but it still beats public types combined with a "DO NOT USE THESE TYPES" comment (our users tend to gleefully ignore such things :-) ).

Thanks for the help, John...

Josh

Mar 2, 2009 at 6:58 PM
A follow-up on this thread...

Use of InternalsVisibleTo gets me what I need here, but the added complication of exposing internal types from a strongly-named assembly does require some DLR source hacking that I would prefer to avoid, if for no other reason than eventually I'd like to be able to leverage the DLR libs from CLR4 instead of my own special branch.

I can appreciate that everyone has their pet bug or feature add to pester you guys about... but this scenario doesn't seem especially oddball or niche. Currently, embedding DLR in your app for scripting, etc. means that you have to publicly expose any scriptable types from that app's assembly (or use InternalsVisibleTo with Snippets.debug). I can envision scenarios where exposing scriptable types is exactly the behavior one might want (app automation scenarios, etc.). But it's not hard to envision cases where this is very undesirable (exposing BigNastyStatefulHairballClass that underpins your entire app infrastructure... no thanks).

Providing a programmatic means to specify a public key associated with the dynamically gen'ed assembly would give us an out for the semi-special case of "need to use InternalsVisibleTo with strongly-named assembly".

Thanks for considering this...

Josh