DLL memory manager mixup

2020-02-15 03:32发布

问题:

I wrote an application which allows people to contribute plugins to extend the functionality. Such plugins are deployed as DLL files, which the framework picks up during runtime. Each plugin features a factory function which is called multiple times during the lifetime of the application to create objects. So far, in order to handle the ownership issue with these objects, I used a simple counting shared pointer on the returned objects so that they are destroyed whenever the last reference is removed.

However, this tends to trigger crashes on Windows since it's not unlikely to happen that the object is new'ed in the plugin DLL but later (due to a deref() call on the shared pointer) deleted in the main application - and AFAIK this malloc/free mixup is a no-no on Windows.

My current solution to this is to let deref() not call 'delete this;' directly but rather a 'release();' function which must be implemented by the plugins and calls 'delete this;'. However, it's quite annoying that each and every plugin has to implement this trivial function - I worked around this so far by providing a convenience macro plugin authors have to use. Does anybody have alternative ideas maybe?

So far, my approach is that all objects contributed by plugins is allocated in the plugins and also released there - of course, an alternative might be to let all memory be allocated in the main application (by providing a pointer to a malloc-like function to the plugins which they can then call as needed) and released there as well. The issue with this is that it's not as convenient for the plugin authors, I think.

I'd be interested in any other perspectives on this issue.

UPDATE: I just realized that I could reimplement operator new and operator delete on the baseclass of the objects returned by the plugins, so that new'ing them and delete'ing them will always result in function calls into the same module (so that either all allocations and free's are done in the plugin, or in the framework).

回答1:

There are two solutions. Solution one is "share more" - you can move new/delete across DLL boundaries if both sides use the same CRT DLL (/MD or /MDd in MSVC). Solution two is "share less" - let each DLL have its own C++ heap, and do not split new/delete across DLL boundaries.



回答2:

It turned out that the easiest way to make sure that memory is not allocated in one DLL and released in another is this: reimplement operator new and operator delete on the base class of the objects which are returned from the plugins. In the implementations of these functions, call 'alloc' and 'free' functions (which have been passed from the main application when loading the plugin). That way, plugins can keep using 'new' and 'delete' but the memory will actually be allocated and released in the main application.



回答3:

If the DLL code is responsible for allocating objects, it should also be responsible for freeing them. I think your problem is more with the reference counting and the "delete this". If you want to go that route, why not simply implemnt the objects as COM objects? This is after all one of the main problems that COM was designed to solve!