Bug in the dynamic language runtime in combination with IIS 7.5
Asked Answered
W

1

4

I apologize for this question length, but I think you'll all find it worth it. Before I begin, let me say that I was really trying to produce an isolated console application, but sadly that proved impossible. The bug does not happen in a console app. It doesn't happen in a self-contained ASP.NET app. It only happens when run within IIS 7.5 on Windows 7.

The error seems related to the dynamic language runtime as it involves the combination of a __TransparentProxy (via WCF) and a dynamic variable (an int). The line that produces the problem is the invocation of a static method (that happens to contain no method body) passing in both the proxy and the dynamic int.

Once the method is invoked, the w3wp.exe process takes up the entire CPU and starts increasing memory very rapidly (for me about 100 megs per second, though it tapers off presumably due to GC'ing).

To reproduce this error, create a new ASP.NET web site in Visual Studio ("New" | "Project" "C#" | "Web" | "ASP.NET Web Application"). Then create a new site in IIS whose home directory is your new project. (also, give "Everyone" full read/write access to that folder and make sure the app pool is using .NET 4.0) Give the new site a specific port, like 7080. Finally, paste this code into Global.asax.cs:

public class Global : System.Web.HttpApplication
{
    void Application_Start(object sender, EventArgs e)
    {
        dynamic dynamicId = 5;

        var serviceUrl = "http://localhost:7182/FooServices.svc";
        ChannelFactory factory = new ChannelFactory<IFooServices>(new WSHttpBinding(), new EndpointAddress(serviceUrl));
        factory.Open();
        IFooServices fooServices = ((ChannelFactory<IFooServices>)factory).CreateChannel();

        BlowUpTheProgram(fooServices, dynamicId);  // This line hangs
    }

    [ServiceContract]
    public interface IFooServices
    {
        [OperationContract]
        void Bar();
    }

    public static void BlowUpTheProgram(IFooServices eventServices, int authorMailboxId)
    {
    }
}

Now access the site in your browser via http://localhost:7080 (or whatever port you chose). Have task manager ready because you'll want to kill the w3wp.exe process after confirming the reported symptoms.

To confirm that the proxy and dynamic are working together to surface this bug, change this line:

dynamic dynamicId = 5;

To:

int dynamicId = 5;

Retry, and you'll notice the problem has gone away and the page loads. Now change it back to dynamic and then change this line:

IFooServices fooServices = ((ChannelFactory<IFooServices>)factory).CreateChannel();

To:

IFooServices fooServices = null;

Retry, and you'll again notice the problem is gone in this scenario too.

Finally, if I attach the debugger and break all, I can see what it's doing while stuck in this method call. It seems to always show something like:

mscorlib.dll!System.RuntimeMethodHandle.GetDeclaringType(System.IRuntimeMethodInfo method) + 0x2f bytes
mscorlib.dll!System.Reflection.Emit.DynamicResolver.ParentToken(int token) + 0x1f3 bytes
[Native to Managed Transition]
[Managed to Native Transition]
mscorlib.dll!System.Reflection.Emit.DynamicMethod.CreateDelegate(System.Type delegateType, object target) + 0x29 bytes
System.Core.dll!System.Linq.Expressions.Expression>.Compile() + 0xbb bytes
System.Core.dll!System.Runtime.CompilerServices.CallSiteBinder.BindCore>(System.Runtime.CompilerServices.CallSite> site, object[] args) + 0x10a bytes
System.Core.dll!System.Dynamic.UpdateDelegates.UpdateAndExecuteVoid3(System.Runtime.CompilerServices.CallSite site = {System.Runtime.CompilerServices.CallSite>}, WebApplication1.Global arg0 = {ASP.global_asax}, WebApplication1.Global.IFooServices arg1 = {System.Runtime.Remoting.Proxies.__TransparentProxy}, object arg2 = 5) + 0x3f0 bytes
WebApplication1.dll!WebApplication1.Global.Application_Start(object sender = {System.Web.HttpApplicationFactory}, System.EventArgs e = {System.EventArgs}) Line 19 + 0x1b8 bytes C#

For the record, I've tried it on three different machines and was able to repro only on the Windows7/IIS7.5 boxes. On the Windows Server 2008 / IIS7 box there was no problem.

The question is, how do I solve this problem and successfully invoke the method? Also, why is this happening? I'd hate to have to be overly careful about invoking things that will use the DLR because it will make IIS crash.

Warrantor answered 20/4, 2012 at 16:8 Comment(8)
The question is, "how do I invoke this method without it hanging?"Warrantor
Do you need to use dynamic? I'm just wondering whether solving the problem is enough or are you looking for the reason for it breaking? What's driving the decision to use dynamic?Rockwood
@Jamie, I'm using dapper dot net. The return types are dynamic. But you make a good point -- I suppose I could hack around it and force it to not use the DLR in this invocation. I'd still like to know why this is happening, though.Warrantor
I've had some problems with dynamic myself. Casting to the type whilst passing the result to your method could solve the problem for you. DontBlowUpTheProgram(fooServices, (int)dynamicId);Rockwood
See my question here for some info on the problem: #9837502 It's not exactly related to yours but who knows, it might be related somewhere along the lines. This then spawned this question: #9837972Rockwood
@Jamie, yeah, that works and is a good workaround. Would still like to know what's going on, though.Warrantor
put have a bounty on a similar question and I was able to reproduce the same problem in a console application and windows form application.Odontoblast
"I apologize for this question length..." don't be sorry. This level of detail and clarity on your attempts to resolve it are very valuable in achieving accurate answers.Soninlaw
R
6

I'm not able to answer Why this happens however casting your dynamic object to int when passing the parameter will work.

DontBlowUpTheProgram(fooServices, (int)dynamicId); 

Perhaps someone with more knowlege of the internals will wade in with a fuller explination.

Rockwood answered 20/4, 2012 at 16:22 Comment(4)
Why did you submit an answer if you cannot answer the question? Things like this should be in comments, not answers. I was all buttered up for an answer then I saw your first line...Roshelle
I do answer the question. It was how to solve it, not why it isn't working. It's changed a bit since it was first posted but here I answer the how without the why.Rockwood
@Phil, I think Jamie provided a very useful answer. To be perfectly frank, SO will "showcase" a question a little more if there are no upvotes to this question. ("Unaswered Questions") However, I fully intend on upvoting this answer (eventually), and more than likely will make it the "accepted" answer. Ultimately, I suspect I'll start a bounty on this in the hopes of getting some other opinions and more attention. But Jamie has been extremely helpful.Warrantor
This fixed it for me. I don't understand the details, but you've provided the solution to the past 6 hours of troubleshooting so you get a massive +1 from me!Soninlaw

© 2022 - 2024 — McMap. All rights reserved.