Opened 10 years ago

Closed 10 years ago

#7152 closed Bugs (fixed)

Interprocess 1.50 windows_bootstamp fails when COM already initialized in multithreaded

Reported by: Charles Savoie <boost@…> Owned by: Ion Gaztañaga
Milestone: To Be Determined Component: interprocess
Version: Boost 1.50.0 Severity: Problem
Keywords: windows bootstamp tmpfile tempfile shared memory shm Cc:

Description

The windows_bootstamp class fails to obtain a bootstamp if the current thread has already been COM-initialized in MULTITHREADED mode. This is due to (detail/win32api.hpp) calling CoInitialize(0) and failing to test for RPC_E_CHANGED_MODE.

This causes opening of a shared_memory_object to fail due to a file path mismatch if one process' thread was not running in a multithreaded COM thread. If both processing were running multithreaded, the problem is masked -- the bootstamp returns an empty string and thus the shared memory file path is the same in both cases.

A slight modification to the example program in the shared memory documentation (http://www.boost.org/doc/libs/1_50_0/doc/html/interprocess/sharedmemorybetweenprocesses.html#interprocess.sharedmemorybetweenprocesses.sharedmemory) displays the problem:

#include <boost/interprocess/shared_memory_object.hpp>
#include <boost/interprocess/mapped_region.hpp>
#include <cstring>
#include <cstdlib>
#include <string>

#include <atlbase.h>

struct co_uninitializer{ ~co_uninitializer() { CoUninitialize(); } };

int main(int argc, char *argv[])
{
    using namespace boost::interprocess;

    if(argc == 1){  //Parent process

        //Remove shared memory on construction and destruction
        struct shm_remove
        {
            shm_remove() { shared_memory_object::remove("MySharedMemory"); }
            ~shm_remove(){ shared_memory_object::remove("MySharedMemory"); }
        } remover;

        //Create a shared memory object.
        shared_memory_object shm (create_only, "MySharedMemory", read_write);

        //Set size
        shm.truncate(1000);

        //Map the whole shared memory in this process
        mapped_region region(shm, read_write);

        //Write all the memory to 1
        std::memset(region.get_address(), 1, region.get_size());

        //Launch child process
        std::string s(argv[0]);
        s = "\"" + s + "\"" + " child ";

        if(0 != std::system( s.c_str() ) )
            return 1;
    }
    else{

        CoInitializeEx(NULL, COINIT_MULTITHREADED );  //***********
        co_uninitializer co_uninit;                   //***********

        //Open already created shared memory object.
        shared_memory_object shm (open_only, "MySharedMemory", read_only);

        //Map the whole shared memory in this process
        mapped_region region(shm, read_only);

        //Check that memory was initialized to 1
        char *mem = static_cast<char*>(region.get_address());
        for(std::size_t i = 0; i < region.get_size(); ++i)
            if(*mem++ != 1)
                return 1;   //Error checking memory
    }
    return 0;
}

The problem seems to be fixed by modifying get_wmi_class_attribute() in interprocess/detail/win32_api.hpp in the following way:

// ...
const   signed long RPC_E_CHANGED_MODE_BIPC = 0x80010106L;
// ...

inline bool get_wmi_class_attribute( std::wstring& strValue, const wchar_t *wmi_class, const wchar_t *wmi_class_var)
{
   //See example http://msdn.microsoft.com/en-us/library/aa390423%28v=VS.85%29.aspx
   long co_init_ret = CoInitialize(0);
   if(co_init_ret != S_OK_BIPC && co_init_ret != S_FALSE_BIPC && co_init_ret != RPC_E_CHANGED_MODE_BIPC )
      return false;

   // Uninitialize COM at function exit if not already initialized with different threading model
   std::auto_ptr<co_uninitializer> co_initialize_end(( co_init_ret != RPC_E_CHANGED_MODE_BIPC ) ? new co_uninitializer : (co_uninitializer*)0 );

   bool bRet = false;
   // ...

Change History (1)

comment:1 by Ion Gaztañaga, 10 years ago

Resolution: fixed
Status: newclosed

Thanks for the report, fixed in revisions 79609 and 79610 in release branch and 79611 & 79612 in trunk.

CoInitializeEx is used and a macro to select the initialization mode for Interprocess is also provided. See documentation notes and win32_api.hpp for more details.

Note: See TracTickets for help on using tickets.