Jump to content

CallbackOnCollectedDelegate was detected


alphabit
 Share

Recommended Posts

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 :rolleyes:

 

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

Link to comment
Share on other sites

  • 2 weeks later...

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.

Link to comment
Share on other sites

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 by alphabit
Link to comment
Share on other sites

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.

Link to comment
Share on other sites

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 :lol:

 

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.

Link to comment
Share on other sites

  • 11 months later...

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.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

 Share

×
×
  • Create New...