System.AccessViolationException error when stored callback is executed

孤街浪徒 提交于 2020-05-17 06:49:13

问题


I have passed as callback a C++ member function to a C# project through a C++/CLI wrapper (this works fine). The C# project is going to call this delegate when receiving data from another .exe process: an event will be raised and a method will call this callback. So, I needed to "save" this Action delegate using an static instance of a C# class already created. I got the following code:

// C++ unmanaged function
WRAPPER_API void dispatchEvent(std::function<void(int)> processEvent)
{
    Iface::Wrapper wrapper;
    wrapper.callback = &processEvent;
    wrapper.PassCallback();
}

//C++ Managed
    public ref class Wrapper
    {
    public:
        std::function<void(int)>* callback;

        void ReturnToCallback(int data)
        {
            (*callback)(data);
        }
        void PassCallback()
        {
            StartGenerator^ startGen = gcnew StartGenerator(gcnew Action<int>(this, &Wrapper::ReturnToCallback));
        }
    };

// C# 
public class StartGenerator
{
    private Communication comm;

    public StartGenerator(Action<int> callback)
    {
        comm = Communication.Instance;
        comm.callback = callback;
    }
}

If I call the Action delegate in StartGenerator method, the C++ function is properly executed. However, my goal was saving the delegate to be able to call it afterwards, when data is received from another .exe process. When this data arrives, an event is raised and callback is called from the event method. It is at this point when I get the following exception:

Unhandled Exception: System.AccessViolationException: Attempted to read or write protected memory. This is often an indication that other memory is corrupt. at Iface.Wrapper.ReturnToCallback(Int32 data)

I think I need to manage the lifetime of the std::function, I don't know about the lifetime of the function object being pointed to by the managed class. The object seems to be deleted and the managed class is left holding a dangling pointer.


回答1:


I think I need to manage the lifetime of the std::function

Yes, I told you as much when I told you to store a pointer in the managed wrapper, here

I don't know about the lifetime of the function object being pointed to by the managed class.

The std::function is a native object and follows the native C++ rules. Putting a pointer in a managed wrapper won't make it garbage-collected.

The object seems to be deleted and the managed class is left holding a dangling pointer.

Yes, your terminology isn't exact but you've correctly diagnosed the problem. Take a look:

void dispatchEvent(std::function<void(int)> processEvent)
{
    Iface::Wrapper wrapper;
    wrapper.callback = &processEvent;
    wrapper.PassCallback();
}

processEvent is function argument, a std::function object passed by value. The copy made and stored in the argument lives until the end of scope. It has automatic storage duration. When the function returns, all the local variables, function arguments included, are destroyed (not "deleted").

You will need to dynamically allocate (a copy of) the std::function object, like:

typedef std::function<void(int)> cbfn;
wrapper.callback = new cbfn(processEvent);

Now you have a memory leak, but at least you aren't using the object after it's destroyed. If you only make a handful of these objects the leak might even be acceptable. In general, you should implement IDisposable on your wrapper and have the Dispose method do delete callback;. In C++/CLI you use destructor syntax to accomplish that.

~Wrapper()
{
    delete callback;
    callback = nullptr;
}


来源:https://stackoverflow.com/questions/61170340/system-accessviolationexception-error-when-stored-callback-is-executed

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!