Skip to content

Native callbacks can be freed while they're running #627

@kring

Description

@kring

UnityTaskProcessor::startTask has a one line implementation:

void UnityTaskProcessor::startTask(std::function<void()> f) {
  System::Threading::Tasks::Task::Run(f);
}

Task::Run takes a DotNet::System::Action instance, which is implicitly constructed from the std::function. The implicit constructor implementation looks like this:

void* (*Action::CreateDelegate)(void* pCallbackFunction) = nullptr;

Action::Action(std::function<FunctionSignature> callback) :
    _handle(CreateDelegate(reinterpret_cast<void*>(new std::function<FunctionSignature>(std::move(callback)))))
{
}

So a new std::function is allocated on the heap and then passed to CreateDelegate, which is a managed function. The managed function creates an instance of a managed class called ActionNativeFunction. ActionNativeFunction holds that std::function pointer (as an IntPtr). Its Invoke method calls back into native code to invoke the function. Finally, that Invoke is hooked up to a regular managed System.Action delegate.

End result: the C# System.Action "owns" a std::function that it can call at will. That System.Action can be passed to, in this case, Task.Run, which can now effectively call back into native code.

Here's the problem. When the managed ActionNativeFunction is finalized, the std::function will be deleted. This can happen even while the std::function is still running! I don't know how common this is, but I have a crash up on my screen right now where this is exactly what has happened (during finalization for AppDomain unload). This is #17 again, which was mostly fixed in #177, but apparently not for delegates.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions