alphabit Posted September 2, 2010 Share Posted September 2, 2010 Hello and apologizes for the long post, I keep receiving the following exception while running a LE2 based C# application: CallbackOnCollectedDelegate A callback was made on a garbage collected delegate of type 'Leadwerks!Leadwerks.Core+EntityCollisionCallback::Invoke'. This may cause application crashes, corruption and data loss. When passing delegates to unmanaged code, they must be kept alive by the managed application until it is guaranteed that they will never be called. According to the MSDN ( see http://msdn.microsoft.com/en-us/library/43yky316%28v=VS.100%29.aspx) access violations occur when attempting to call into managed code through function pointers that were obtained from managed delegates. These failures, while not common language runtime (CLR) bugs, may appear to be so because the access violation occurs in the CLR code. The failure is not consistent; sometimes the call on the function pointer succeeds and sometimes it fails. The failure might occur only under heavy load or on a random number of attempts (happens to me!). This error is thrown regardless of which LE version I try to wrap (2.32, 2.40). What I try is to track a collision on a sphere body like: sphereBody.Callback(SphereCollisionCallback, (int)EntityCallbackType.Collision); and simply handle that event: private void SphereCollisionCallback(IntPtr _entity1, IntPtr _entity2, Vector3 _position, Vector3 _normal, Vector3 _force, float speed){ ...} The wrapped LE call that leads to the exception is: [DllImport(EngineDll, EntryPoint = "UpdateFramework", CallingConvention = CallingConvention.StdCall)] public static extern void UpdateFramework(); Any special voodoo GC stuff I should consider? Do I have to configure something additionally in the Project settings? Is there anybody having similar experience? The implementation which shows the mentioned behaviour is available on my other post at MyOtherPost. Meanwhile I left the 2.0 Header because there I can't event use the CollisionCallback. The old headers don't work either (same problem as my implementation here). Atm, I practically cannot do anything decent in C# with LE which involves collisions, so any help and pointings into the right direction are very much appreciated Edit: Just an additional technical note from an exception trace This happens when the exception occurs in the engine.dll - Exception Tracing First chance exception 0xC0000005 ACCESS_VIOLATION occurred at 0x001E2B9D, read of address 0x00000004 at 0x001E2B9D 788 0x001E2B9D 788 0x00DF0C3D 788 0x1010E814 engine.dll 788 0x101121BC engine.dll 788 0x1015A10C engine.dll 788 0x1015A780 engine.dll 788 0x1019005E UpdateFramework + 0x12 in engine.dll 788 0x001E5D33 788 0x001E5D97 788 0x001E04B3 788 First chance exception 0xC000001D ILLEGAL_INSTRUCTION occurred at 0x00DF0CD0 788 0x00DF0CD0 788 0x101121BC engine.dll 788 0x1015A0CA engine.dll 788 0x1015A780 engine.dll 788 0x1019005E UpdateFramework + 0x12 in engine.dll 788 0x001E5D33 788 0x001E5D97 788 0x001E04B3 788 0x001E010B 788 0x001E00A6 788 Module loaded: C:\Windows\SysWOW64\version.dll; Base address: 0x75320000 Size: 21504 Version: 6.1.7600.16385 788 Module loaded: C:\Windows\Microsoft.NET\Framework\v4.0.30319\diasymreader.dll; Base address: 0x53940000 Size: 688472 Version: 10.0.30319.1 788 Second chance exception 0xC000001D ILLEGAL_INSTRUCTION occurred at 0x00DF0CD0 788 Best regards ps: I am using Visual Studio 2010 Professional on Windows 7 Ultimate x64 and the project is based on .NET 4.0 Quote Link to comment Share on other sites More sharing options...
L B Posted September 2, 2010 Share Posted September 2, 2010 @Tyler: Let's fix these callbacks and delegates tonight. Quote Link to comment Share on other sites More sharing options...
L B Posted September 11, 2010 Share Posted September 11, 2010 I am currently having the same problem. I don't know how to keep a reference to the Core.EntityCollisionCallback delegate and Tyler is not on (he's the delegate specialist between us). I'm trying to find out how at the moment. Will post here if I find something. Quote Link to comment Share on other sites More sharing options...
L B Posted September 11, 2010 Share Posted September 11, 2010 http://stackoverflow.com/questions/3691873/defining-a-delegate-as-a-function-pointer Quote Link to comment Share on other sites More sharing options...
alphabit Posted September 14, 2010 Author Share Posted September 14, 2010 (edited) Hi Lazlo, thanks for taking the time to investigate the problem. I see, it's one of the harder stuff to get rid off I also took some time these days to try to understand what could be the cause, but tbh I didn't dive into that much. Although I've collected a couple of links that I think might be helpful: Delegate Keep alive Marshal.GetFunctionPointerForDelegate Marshaling between Managed and Unmanaged Code Default Marshaling for Delegates Unmanaged Callbacks in .NET 2.0 How to: Marshal Callbacks and Delegates Using C++ Interop Pinning a delegate within a struct before passing to unmanaged code Unmanaged function pointers / Marshal.GetFunctionPointerForDelegate I've been reading your post at stackoverflow and that you managed to run the wrapper crash free while in debug build mode. Could it be that it's a matter of build optimization (Build - Optimize Code) that makes the difference in this case? It's not a practicable solution (I don't know if it would even fit this case), but maybe marking some specific methods to not be optimized could be a raw idea of a workaround? I was thinking about something like: [MethodImpl( MethodImplOptions.NoInlining | MethodImplOptions.NoOptimization )]. I hope the resources above help you a little bit... Best regards Edited September 14, 2010 by alphabit Quote Link to comment Share on other sites More sharing options...
L B Posted September 14, 2010 Share Posted September 14, 2010 I have solved the CallbackOnCollectedDelegate problem. Simply, have a reference to the delegate that is alive as long as you need it. Therefore, instead of using: e.Callback(new EntityCollisionCallback(...)); Use: EntityCollisionCallback c = new EntityCollisionCallback(...); e.Callback(c); Then, simply make sure "c" stays alive (is referenced, i.e. accessible in any way) as long as you intend the callback to run. Quote Link to comment Share on other sites More sharing options...
alphabit Posted September 16, 2010 Author Share Posted September 16, 2010 That's great news, Lazlo. Just tried it and it works as expected :-) Sometimes It can be so simple... after you know how it works I see that at the end it was a matter of keeping the delegate alive so that the GC wouldn't collect it. Since the delegate is now declared at class scope, it holds a valid reference that doesn't get GCed. Weird things happen, but in the end it has its good sides... If we ever will see such behavior again, we know what could be done to workaround it! Thank you for figuring this out. Cheers. Quote Link to comment Share on other sites More sharing options...
L B Posted September 9, 2011 Share Posted September 9, 2011 By the way, the event system handles that seamlessly now, no need to worry. cube.Collided += delegate { Console.WriteLine("Collision!"); }; Quote Link to comment Share on other sites More sharing options...
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.