C#5 AsyncCtp BadImageFormatException
Please help me with this one, I've been writing a console applicaiton using the AsyncCtpLibrary and the C#5 ctp compiler. First time I got to actually running a code which awaits, I got this:
System.BadImageFormatException was unhandled
Message=An attempt was made to load a program with an incorrect format. (Exception from HRESULT: 0x8007000B)
Source=AsyncCtpLibrary
StackTrace:
Se开发者_Python百科rver stack trace:
at [...].<Execute>d__1c.MoveNext()
at [...].Execute()
at [...].<Move>d__1d.MoveNext() in[..]:line 266
Exception rethrown at [0]:
at System.Runtime.CompilerServices.AsyncVoidMethodBuilder.<SetException>b__1(Object state)
at System.Threading.QueueUserWorkItemCallback.WaitCallback_Context(Object state)
at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean ignoreSyncCtx)
at System.Threading.QueueUserWorkItemCallback.System.Threading.IThreadPoolWorkItem.ExecuteWorkItem()
at System.Threading.ThreadPoolWorkQueue.Dispatch()
at System.Threading._ThreadPoolWaitCallback.PerformWaitCallback()
InnerException:
Am I missing a dll to be referenced?
important new stuff
My failing method looks like this:public async override Task<bool> Execute()
{
//do stuff
await stuff;
//do other stuff
await base.Execute()
//do other stuff
return true;
}
I've followed Jon Skeet's advice trying to recreate the mistake little by little, and now I can tell that the await base.Execute() line is the killer! If I comment that line out, everything runs, if I leave it in, calling my method fails IMMEDIATELY (not when reaching the base.Execute()). So I assume the ctp compiler does something freaky. Why? What should I never do? How big is the bug?
old stuff:
EDIT:
As for 32bit/64bit issue, my system is 32bit (inside a virtual machine, mind you), and as far as I know AsyncCtpLibrary.dll doesn't contain unmanaged code. All my projects (class libraries and single console app) all have build tabs like this: What can possibly be still wrong?EDIT: I also checked the Fusion log viewer, the AsyncCtpLibrary is loaded without any error:
*** Assembly Binder Log Entry (6/10/2011 @ 9:04:11 PM) ***
The operation was successful.
Bind result: hr = 0x0. The operation completed successfully.
Assembly manager loaded from: C:\Windows\Microsoft.NET\Framework\v4.0.30319\clr.dll
Running under executable C:\Users\Daver\Documents\Visual Studio 2010\Projects\[...]\bin\Debug\MyApp.exe
--- A detailed error log follows.
=== Pre-bind state information ===
LOG: User = WIN-N74LV38NLV3\Daver
LOG: DisplayName = AsyncCtpLibrary, Version=1.0.4107.18181, Culture=neutral, PublicKeyToken=31bf3856ad364e35
(Fully-specified)
LOG: Appbase = file:///C:/Users/Daver/Documents/Visual Studio 2010/Projects/[...]/bin/Debug/
LOG: Initial PrivatePath = NULL
LOG: Dynamic Base = NULL
LOG: Cache Base = NULL
LOG: AppName = MyApp.exe
Calling assembly : MyLibrary, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null.
===
LOG: This bind starts in default load context.
LOG: Using application configuration file: C:\Users\Daver\Documents\Visual Studio 2010\Projects\[...]\bin\Debug\MyApp.exe.Config
LOG: Using host configuration file:
LOG: Using machine configuration file from C:\Windows\Microsoft.NET\Framework\v4.0.30319\config\machine.config.
LOG: Post-policy reference: AsyncCtpLibrary, Version=1.0.4107.18181, Culture=neutral, PublicKeyToken=31bf3856ad364e35
LOG: GAC Lookup was unsuccessful.
LOG: Attempting download of new URL file:///C:/Users/Daver/Documents/Visual Studio 2010/Projects/[...]/bin/Debug/AsyncCtpLibrary.DLL.
LOG: Assembly download was successful. Attempting setup of file: C:\Users\Daver\Documents\Visual Studio 2010\Projects\[...]\bin\Debug\AsyncCtpLibrary.dll
LOG: Entering run-from-source setup phase.
LOG: Assembly Name is: AsyncCtpLibrary, Version=1.0.4107.18181, Culture=neutral, PublicKeyToken=31bf3856ad364e35
LOG: Binding succeeds. Returns assembly from C:\Users\Daver\Documents\Visual Studio 2010\Projects\[...]\bin\Debug\AsyncCtpLibrary.dll.
LOG: Assembly is loaded in default load context.
I also checked the IL code of the <Execute>d__1c
compiler-generated class' MoveNext() method, and the only assemblies it references ([assemblyName]) are mscorlib, System.Core, and AsyncCtpLibrary.
I checked the manifest of both my dll and AsyncCtpLibrary, mine said .corflags 0x00000003 // ILONLY 32BITREQUIRED
, AsyncCtpLibrary said .corflags 0x00000009 // ILONLY
, I'm unsure if this can be the problem.
Please help, I'm out of ideas!
EDIT: I've heard back from the compiler team, who have confirmed it as a bug. It had already been fixed in their codebase, so hopefully we'll see that fix in the next release / beta / CTP. The fix isn't going to be back-ported to "normal" VS2010 as it's a pretty unusual set of circumstances, at least before async.
EDIT: Okay, I've now got a really short but complete program which demonstrates the problem. I believe it's a mixture of generics and calling a base method:
using System;
using System.Threading.Tasks;
public abstract class AsyncAction<T>
{
public virtual Task<T> Execute()
{
// We never get this far
Console.WriteLine("Execute called");
return null;
}
}
public class BoolAction : AsyncAction<bool>
{
public async override Task<bool> Execute()
{
return await base.Execute();
}
}
class Test
{
static void Main()
{
BoolAction b = new BoolAction();
b.Execute();
}
}
EDIT: Okay, I've come up with a workaround. Basically, to call the base class method non-virtually, the compiler creates a synthetic method in BoolAction
. It gets that slightly wrong, but we can get it right:
public class BoolAction : AsyncAction<bool>
{
public async override Task<bool> Execute()
{
return await BaseExecute();
}
private Task<bool> BaseExecute()
{
return base.Execute();
}
}
So whenever you were writing base.Execute
, write BaseExecute
and insert that extra method. It's not too bad a workaround, until the team fix the bug.
EDIT: I've simplified the example a bit - you don't need any overrides, and in particular you don't need the base class to expose a Task<T>
. A call to any virtual base.Foo
method will do it:
public abstract class AsyncAction<T>
{
public virtual T GetT()
{
return default(T);
}
}
public class BoolAction : AsyncAction<bool>
{
#pragma warning disable 1998 // We're not awaiting anything
public async void Execute()
{
base.GetT();
}
#pragma warning restore 1998
}
class Test
{
static void Main()
{
BoolAction b = new BoolAction();
b.Execute();
}
}
EDIT: Contrary to my previous thoughts, this does affect iterators as well. No async CTP required...
public abstract class Base<T>
{
public virtual T GetT()
{
return default(T);
}
}
public class Derived : Base<bool>
{
public System.Collections.IEnumerator Foo()
{
base.GetT();
yield break;
}
}
class Test
{
static void Main()
{
Derived d = new Derived();
d.Foo().MoveNext();
}
}
EDIT: And it affects anonymous functions too...
using System;
public abstract class Base<T>
{
public virtual T GetT()
{
return default(T);
}
}
public class Derived : Base<bool>
{
public void Foo()
{
Action x = () => base.GetT();
x();
}
}
class Test
{
static void Main()
{
Derived d = new Derived();
d.Foo();
}
}
You are hitting known VS 2010 bug
https://connect.microsoft.com/VisualStudio/feedback/details/626550/badimageformatexception-on-simple-program-using-generics-and-lambdas
This exception often occurs when you try and load a 32 bit DLL in a 64 bit environment.
If you are running on a 64 bit OS try changing your projects settings to compile directly for x86 (rather than AnyCPU).
(This might sound backwards, but it's because if you are loading an external 32 bit DLL you need to force your whole project to be 32 bit.)
精彩评论