Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using Marshal::GetFunctionPointerForDelegate and calling a callback from unmanaged code causes a buffer overrun when quitting application

I am using Visual Studio 2008 with .NET Framework 3.5 and making a C++/CLI/.NET Forms application; an editor for a game. All the game code other than the editor is in pure C++. I'm getting to a point where I need callbacks in the Forms code to be called from unmanaged code.

I'm using GetFunctionPointerForDelegate.

First I have these in my Form class:

public: delegate void ADelegate(Int32, float, float, float, Int32);
public: static ADelegate^ delegateInstance;

Then I set up the callback in the Form constructor:

        // Set up World Objects callback
        typedef void (__stdcall *WorldLocationUpdateCallback)(Int32, float, float, float, Int32);
        WorldLocationUpdateCallback _callback;

        // Create an instance of a delegate, using GetFunctionPointerForDelegate
        delegateInstance = gcnew ADelegate( this, &MainForm::InitWorldObjectPane );

        // Convert the delegate to a pointer
        IntPtr anIntPtr = Marshal::GetFunctionPointerForDelegate( delegateInstance );

        // Cast the pointer into a function pointer
        _callback = static_cast<WorldLocationUpdateCallback>(anIntPtr.ToPointer());

        CEditorUI::UI()->setWorldLocationUpdateCallback( (void*)_callback );

So I store the pointer and in the unmanaged code, call the callback early on in the initialization of my app, from a different thread:

    // Set up World Object pane in editor to use this map/maptile/etc
    {
        typedef void (*WorldLocCallback)(int, float, float, float, int);
        void* _callback = CEditorUI::UI()->getWorldLocationUpdateCallback();
        int _mapId = charGfxObj->getMapId();
        float _posX = charGfxObj->getPos().x;
        float _posY = charGfxObj->getPos().y;
        float _posZ = charGfxObj->getPos().z;
        int _tileRadius = TILE_RADIUS;
        ((WorldLocCallback)(_callback))( _mapId, _posX, _posY, _posZ, _tileRadius );
    }

Everything works perfectly, functionally in my app, all the way until when I close the application. It always dies with a Buffer overrun error in the calling thread, the call stack being rather unhelpful:

editor.exe!__crt_debugger_hook()    Unknown
>editor.exe!__report_gsfailure()  Line 298 + 0x7 bytes  C
editor.exe!__CorExeMain@0()  + 0xe3 bytes   C++

The kicker here is that it crashes even if the callback does literally nothing at all. All I have to do to cause the crash is to enable that last line of code that calls the callback. With that line disabled, no problems. Keep in mind the crash happens only when quitting, and not when actually using the callback.

Any recommendations to try?

like image 663
relaxok Avatar asked Feb 16 '26 19:02

relaxok


1 Answers

After an entire day messing with this and searching for other related things, I somewhat solved this, in case anyone else has this issue.

Moving the delegate declaration outside the class and decorating it with:

[UnmanagedFunctionPointerAttribute(CallingConvention::Cdecl)] 

...solved it for me. Apparently the stack clearing effect of cdecl solves the overrun.

like image 192
relaxok Avatar answered Feb 19 '26 17:02

relaxok



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!