From bcdfa0fa4d146b5de78edede82073ed08c7280cd Mon Sep 17 00:00:00 2001 From: mikw Date: Wed, 12 Feb 2025 17:16:01 +0000 Subject: [PATCH] The windows_intermodule_singleton for getting the bootstamp path has a fixed binary format The windows_bootstamp clasa uses a simple C style string so that the binary format is the same in debug and release builds There can be multiple modules which use boost interprocess named objects (e.g. named_recursive_mutex). These modules can be built in release or debug mode and hence the binary format of std::basic_string<> will differ. This results in an access violation if the windows_intermodule_singleton for the windows_bootstamp is created in a module built in release mode, and accessed in a module build in debug mode (or vice-versa). It is not only release versus debug that is an issue. The access violation could also occur if the modules are built with different compilers. The solution is to create a new windows_intermodule_singleton because we cannot change the format of the existing windows_bootstamp class. The new singleton uses only C functions to allocate and free the the character string. This ensures that the build configuration mode or the compiler do not affect the binary layout of the singleton object. The new windows_intermodule_singleton has a class name which includes a version number. E.g. windows_bootstamp::version1 If the layout of this class needs to change, then the version number must be incremented. This would then create a new singleton, which is required. --- .../detail/shared_dir_helpers.hpp | 58 ++++++++++++++----- 1 file changed, 42 insertions(+), 16 deletions(-) diff --git a/include/boost/interprocess/detail/shared_dir_helpers.hpp b/include/boost/interprocess/detail/shared_dir_helpers.hpp index 8d9d36f2..fb4e0061 100644 --- a/include/boost/interprocess/detail/shared_dir_helpers.hpp +++ b/include/boost/interprocess/detail/shared_dir_helpers.hpp @@ -28,6 +28,7 @@ #if defined(BOOST_INTERPROCESS_HAS_KERNEL_BOOTTIME) && defined(BOOST_INTERPROCESS_WINDOWS) #include + #include #endif namespace boost { @@ -59,32 +60,57 @@ struct shared_dir_constants #if defined(BOOST_INTERPROCESS_HAS_KERNEL_BOOTTIME) #if defined(BOOST_INTERPROCESS_WINDOWS) - //This type will initialize the stamp - template - struct windows_bootstamp + // This type will initialize the stamp. + // The namespace allows future changes to the memory layout without + // causing a crash in older or newer versions of the code being used + // in the same process. + // If the memory layout is changed then the class name version suffix must + // be incremented. + // Note that we use winapi::HeapAlloc/HeapFree for memory allocation + // to avoid any differences in heap allocation across modules + namespace windows_bootstamp { - windows_bootstamp() + template + struct version1 { - //Throw if bootstamp not available - if(!winapi::get_last_bootup_time(stamp)){ - error_info err = system_error_code(); - throw interprocess_exception(err); + version1() + { + std::basic_string stamp; + //Throw if bootstamp not available + if(!winapi::get_last_bootup_time(stamp)){ + error_info err = system_error_code(); + throw interprocess_exception(err); + } + unsigned bytes = (stamp.length() + 1) * sizeof(CharT); + data = static_cast(boost::detail::allocate_raw_heap_memory(bytes)); + length = static_cast(stamp.length()); + stamp.copy(data, length); + data[length] = 0; } - } - //Use std::string. Even if this will be constructed in shared memory, all - //modules/dlls are from this process so internal raw pointers to heap are always valid - std::basic_string stamp; - }; + ~version1() + { + if (data) + boost::detail::free_raw_heap_memory(data); + data = nullptr; + length = 0; + } + + uint32_t length{}; + CharT * data {}; + }; + } template inline void get_bootstamp(std::basic_string &s, bool add = false) { - const windows_bootstamp &bootstamp = windows_intermodule_singleton >::get(); + using bootstamp_type = windows_bootstamp::version1; + const bootstamp_type &bootstamp = windows_intermodule_singleton::get(); + std::basic_string_view stamp(bootstamp.data, bootstamp.length); if(add){ - s += bootstamp.stamp; + s += stamp; } else{ - s = bootstamp.stamp; + s = stamp; } } #elif defined(BOOST_INTERPROCESS_HAS_BSD_KERNEL_BOOTTIME)