Modify

Opened 5 years ago

Closed 5 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: igaztanaga
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;
   // ...

Attachments (0)

Change History (1)

comment:1 Changed 5 years ago by igaztanaga

  • Resolution set to fixed
  • Status changed from new to closed

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.

Add Comment

Modify Ticket

Change Properties
Set your email in Preferences
Action
as closed The owner will remain igaztanaga.
The resolution will be deleted. Next status will be 'reopened'.
Author


E-mail address and user name can be saved in the Preferences.

 
Note: See TracTickets for help on using tickets.