0

I have a simple project running under Windows. It consists of two DLLs and one EXE. The EXE loads the two DLLs. Each will create a shared memory object in a class instatiated by a std::unique_ptr globaly. The crash happens during FreeLibrary and only if I use the /MTd switch (Multi-threaded Debug) instead of /MDd (Multi-threaded Debug DLL).

I built boost libs using:

b2.exe -a -j %NUMBER_OF_PROCESSORS% --prefix=%BOOST% --libdir=%BOOST%/lib/x86 --reconfigure --build-type=complete --toolset=msvc-14.2 link=static address-model=32 runtime-link=static runtime-link=shared threading=multi define=BOOST_USE_WINDOWS_H define=NOMINMAX install

where %BOOST% points to my BOOST installation folder.

I hope someone can help me, Christian.

The example code:

APOLLOSHM\dllmain.cpp

#include <memory>
#include "../shared/SHMBASE.h"

std::unique_ptr<SHM> shm;
BOOL APIENTRY DllMain( HMODULE hModule, 
DWORD ul_reason_for_call, LPVOID )
{
    switch (ul_reason_for_call)
    {
    case DLL_PROCESS_ATTACH:
        shm = std::make_unique<SHM>("a_shm");
        break;
    case DLL_THREAD_ATTACH:
    case DLL_THREAD_DETACH:
    case DLL_PROCESS_DETACH:
        break;
    }
    return TRUE;
}

PHONYXSHM\dllmain.cpp

#include <memory>
#include "../shared/SHMBASE.h"

std::unique_ptr<SHM> shm;
BOOL APIENTRY DllMain( HMODULE hModule, DWORD ul_reason_for_call, LPVOID )
{
    switch (ul_reason_for_call)
    {
    case DLL_PROCESS_ATTACH:
        shm = std::make_unique<SHM>("p_shm");
        break;
    case DLL_THREAD_ATTACH:
    case DLL_THREAD_DETACH:
    case DLL_PROCESS_DETACH:
        break;
    }
    return TRUE;
}

shared\SHMBASE.h

#ifndef SHAREDMEM_H
#define SHAREDMEM_H
#include <boost/interprocess/shared_memory_object.hpp>
#include <boost/interprocess/mapped_region.hpp>
class SHMBASE
{
    boost::interprocess::shared_memory_object shm;
    boost::interprocess::mapped_region region;
protected:
    void* addr{ nullptr };
public:
    SHMBASE(const char* n)
    {
        try {
            boost::interprocess::shared_memory_object::remove(n);
            shm = boost::interprocess::shared_memory_object(
                  boost::interprocess::open_or_create, 
                  n, boost::interprocess::read_write);
        }
        catch (boost::interprocess::interprocess_exception & ex) {
            throw std::runtime_error(ex.what());
        }
    }
    void create_shm(size_t size)
    {
        shm.truncate(size);
        region = boost::interprocess::mapped_region(shm, 
                 boost::interprocess::read_write);
        addr = region.get_address();
    }
};

struct shared_memory_info
{
    char x[20];
    int y;
};

class SHM : public SHMBASE
{
public:
    SHM(const char* n) :
        SHMBASE(n)
    {
        create_shm(sizeof(shared_memory_info));
        shm = static_cast<shared_memory_info*>(addr);
    }
    shared_memory_info* shm;
};
#endif

SharedMemTest\SharedMemTest.cpp

#include <iostream>
#include <utility>
#include <vector>
#include <string>
#include <Windows.h>

struct LIBOBJ
{
    HMODULE libhandle{ nullptr };
    LIBOBJ(std::string libname){
        libhandle = LoadLibraryA(libname.c_str());
        if (!libhandle) {
            throw std::runtime_error("Cannot open library");
        }
    }
    ~LIBOBJ() {
        if (libhandle){
            FreeLibrary(libhandle);
        }
    }
};
int main(){
    std::vector<std::string> dlls = {"ApolloSHM.dll", "PhonyxSHM.dll"};
    std::vector<std::unique_ptr<LIBOBJ> > objs;
    try{
        for (auto& n : dlls){
            objs.emplace_back(std::make_unique<LIBOBJ>(n));
        }
        // if freelibrary in reverse order no crash
        // for (auto it = objs.rbegin(); it != objs.rend(); ++it)
        // if in order of loading it crashes, but only with /MTd
        // for (auto it = objs.begin(); it != objs.end(); ++it)
        for (auto it = objs.begin(); it != objs.end(); ++it){
            it->reset();
        }
    }
    catch (std::exception & e){
        std::cout << "Exception: " << e.what() << std::endl;
    }
    return 0;
}
cdannebe
  • 11
  • 2
  • 2
    Include the code in your question as text, not link. – pptaszni Jan 17 '20 at 09:09
  • Welcome to SO! Please follow pptaszni's advice and provide the troublesome code as searchable text if you hope for fast responses and usable answers. Few users take the time to download some ZIP file, unzip the contents, load stuff into the editor and so on. And this is an excellent opportunity to reduce your code to the absolutely required code, see https://stackoverflow.com/help/minimal-reproducible-example, which quite often helps to find the solution alone, see [rubber ducking](https://en.wikipedia.org/wiki/Rubber_duck_debugging). – Twonky Jan 17 '20 at 10:11

1 Answers1

0

I think I solved the issue (maybe just for me). The problem isn't the /MTd switch of the compiler. I think the problem is related to the singleton implementation inside boost::interprocess::shared_memory_object. My project structure is as follows:

An EXE file loads a DLL (a driver wrapper) which can load several device driver DLLs in parallel. Two of the driver DLLs are using their own shared_memory_object's as described in the doc and it work in both cases. Until I call FreeLibrary for the driver DLLs. In that case always the second FreeLibrary crashes (but not with /MDd I didn't understand this seconds fact, sorry).

I solved the issue by creating a boost::interprocess::shared_memory_object inside the driver wrapper DLL. I just instantiate such an object and in the next line I remove it. If I do this my DLLs does not crash any more.

I hope this helps the developer of boost::interprocess.

Kind regards, Christian

cdannebe
  • 11
  • 2