Wednesday, September 12, 2007

Dynamic method interception with Mono.Cecil

For a couple months I've had an idea jangling in my head to use Mono.Cecil to instrument libraries to enable runtime dynamic interception of any method call (not just virtual ones). For example, this ability would be useful for extending Rhino.Mocks to support mocking static methods. It could also be used for tracing into unmodifiable code.

Of course, generally when you want to do these things you're doing something wrong. Let's set aside those objects for the moment. I've been curious to see whether the principle was sound and how much work it would be.

I tried hard to suppress it and focus on more important things. I was pretty successful at it. But I broke down over the weekend while I was writing a wee little code generator to help keep MbUnit Gallio Assertions all nice and consistent (I really wish C# had hygienic macros!). All that code gen on the brain was driving me to distraction. So I gave it a shot.

The results

1. The principle is sound.
2. It took about two days of heavy-duty hacking to get a proof of concept (while taking care of a bunch of other business). Pretty much what I expected but more than I'd hoped.

I've checked in code that uses Mono.Cecil to perform runtime interception in either of two different ways:
1. Statically instrumenting the assembly to include interception code that can be hotwired on demand. (easy)
2. Loading the assembly into the dynamic assembly context and patching method bodies on demand using MethodRental. (hard)

Moving forward

Generally the profiler API is better suited for dynamic interception but there are interesting scenarios where we can't use it (like in production code). So I can imagine there would be significant value to various projects if a variety of interception strategies were offered under a common simplified instrumentation interface. I'm sure the .Net AOP enthusiasts would put it to good use.

It was a good experiment but not immediately useful. (That's what hobbies are for...)

In any case, I don't plan on doing much of anything with this code anytime soon since I've got tons of other stuff on the go. Please let me know if you find this code of use or are interested in contributing to its continued development.

1 comment:

Jason Bock said...

For doing PEVerify on the fly, I've created a wrapper around the EXE, which may make some of your code a bit easier:

http://www.jasonbock.net/JB/CodeAssemblyVerifier.aspx

This seems like an interesting idea, I'll try to review it later to see if I can make some sense out of it :)