[Boost-bugs] [Boost C++ Libraries] #7152: Interprocess 1.50 windows_bootstamp fails when COM already initialized in multithreaded

Subject: [Boost-bugs] [Boost C++ Libraries] #7152: Interprocess 1.50 windows_bootstamp fails when COM already initialized in multithreaded
From: Boost C++ Libraries (noreply_at_[hidden])
Date: 2012-07-19 16:54:17


#7152: Interprocess 1.50 windows_bootstamp fails when COM already initialized in
multithreaded
------------------------------------------------------------------+---------
 Reporter: Charles Savoie <boost@…> | Owner: igaztanaga
     Type: Bugs | Status: new
Milestone: To Be Determined | Component: interprocess
  Version: Boost 1.50.0 | Severity: Problem
 Keywords: windows bootstamp tmpfile tempfile shared memory shm |
------------------------------------------------------------------+---------
 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:

 {{{
 #!div style="font-size: 80%"
   {{{#!c++

 #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:

 {{{
 #!div style="font-size: 80%"
   {{{#!c++
 // ...
 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;
    // ...
 }}}

-- 
Ticket URL: <https://svn.boost.org/trac/boost/ticket/7152>
Boost C++ Libraries <http://www.boost.org/>
Boost provides free peer-reviewed portable C++ source libraries.

This archive was generated by hypermail 2.1.7 : 2017-02-16 18:50:10 UTC