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