…and just when you get comfortable in the Heaven of managed code…you get smacked right in the face with some old piece of C code…dancing on your now soft delicate body…a body that’s been marinated from the many years of coding in your CLR play pen… and invoking your privates with a stack of imbalance…SAY WHAT???
PInvokeStackImbalance
I came across this today after upgrading a class library that uses PInvoke to .NET 4.0. Specifically, after running the code, I got a PInvokeStackImbalance detection message from the VS2010 Managed Debugging Assistant (MDA). Obviously, my first thought was, as indicated by the message, that the PInvoke signature didn’t match the types of the C function I’m trying to call. However, I still couldn’t see a problem – all the parameter types seemed correct. Also, since I’m running Win 7 64-bit, I figured possibly this could be a 64-bit issue – so I changed the Platform target in my build settings from Any CPU to x86. Still no success.In the end, the problem seemed to disappear once I’ve changed my build target for the PInvoke class library to target .NET 3.5 (2.0 also works fine) instead. The code worked fine…however this solution just didn’t smell right to me, so I did a bit more digging…and good thing I did!
Turns out that this issue is mentioned in the .NET 4.0 Migration Issues document under the Interoperability section – I’ve copied the relevant section below for quick reference:
Platform invoke | To improve performance in interoperability with unmanaged code, incorrect calling conventions in a platform invoke now cause the application to fail. In previous versions, the marshaling layer resolved these errors up the stack. | Debugging your applications in Microsoft Visual Studio 2010 will alert you to these errors so you can correct them. If you have binaries that cannot be updated, you can include the <NetFx40_PInvokeStackResilience> element in your application's configuration file to enable calling errors to be resolved up the stack as in earlier versions. However, this may affect the performance of your application. |
Armed with this knowledge, it became apparent that the real source of my PInvoke problem was that the PInvoke calling convention for my method defaulted to StdCall – and I needed to use Cdecl instead. Once I updated the code, I was able to restore my class library to target the .NET 4.0 framework.
- [DllImport("libfftw3f-3.dll", EntryPoint = "fftwf_plan_r2r_1d", ExactSpelling = true, CallingConvention = CallingConvention.Cdecl)]
- public static extern IntPtr r2r_1d(int n, IntPtr input, IntPtr output, fftw_kind kind, fftw_flags flags);
5 comments:
Hey that's a good blog thanks for sharing the advice.
Billing Software Solution
The exact entry in app.config:
<runtime>
<NetFx40_PInvokeStackResilience enabled="1"/>
</runtime>
Regards and thanks for posting it,
Flo
Thanks. You saved me some head scratching.
Thanks for that - that confused me for the better part of a day.
In earlier versions of the .NET Framework, the marshaling layer detected incorrect platform invoke declarations on 32-bit platforms and automatically fixed the stack.
Post a Comment