Storing containers within HCL containers is broken
- Dominant language
- C++
- Stars
- 6
- Forks
- 0
- PR merge metrics
- No merged PRs in 30d
Description
I had a hunch that storing containers in HCL containers was not working correctly after reading this from the Boost.Interprocess documentation:
```
Boost.Interprocess containers are placed in shared memory/memory mapped files, etc... using two mechanisms at the same time:
Boost.Interprocess construct<>, find_or_construct<>... functions. These functions place a C++ object in the shared memory/memory mapped file. But this places only the object, but not the memory that this object may allocate dynamically.
Shared memory allocators. These allow allocating shared memory/memory mapped file portions so that containers can allocate dynamically fragments of memory to store newly inserted elements.
This means that to place any Boost.Interprocess container (including Boost.Interprocess strings) in shared memory or memory mapped files, containers must:
Define their template allocator parameter to a Boost.Interprocess allocator.
Every container constructor must take the Boost.Interprocess allocator as parameter.
You must use construct<>/find_or_construct<>... functions to place the container in the managed memory.
If you do the first two points but you don't use construct<> or find_or_construct<> you are creating a container placed only in your process but that allocates memory for contained types from shared memory/memory mapped file.
```
We follow this advice properly for the HCL container itself. For example, the internal `bip::unordered_map` in the `hcl::unordered_map` takes a Boost.Interprocess shared memory allocator as a template parameter. However, if we then try to store a `bip::string` in our `hcl::unordered_map`, the documentation suggests that the string constructor needs to take a proper Boost.Interprocess allocator (which is currently not possible without changing the library). To verify my hunch, I did some investigation in the debugger. First, I examine the shared memory segment in `hcl::unordered_map` to see the valid range of memory addresses that it emcompasses.
```cpp
(gdb) p segment.m_mfile.m_mapped_region
$10 = {
m_base = 0x7fffea218000,
m_size = 134217728,
m_page_offset = 0,
m_mode = boost::interprocess::read_write,
m_is_xsi = false
}
```
So the shared memory addresses range from `0x7fffea218000` to `0x7ffff2218000`.
So let's see where our container data is being stored. `iterator` here is the result of calling `mymap->find(key);`
```cpp
(gdb) p &(*iterator)->second
$12 = (boost::container::basic_string, boost::container::new_allocator > *) 0x7fffea2181e0
```
The `bip::string` itself is stored within the valid shared memory address range. This is expected, since we define the appropriate shared memory allocator on the `hcl::unordered_map`. Now let's see where the `bip::string` has allocated its internal data:
```cpp
(gdb) p (*iterator)->second.data()
$11 = 0x555555fcee70 'x' ...
```
This address is well outside the bounds of our shared memory. As a sanity check, I performed the same test on an example of containers within containers from the Boost.Interprocess documentation:
```cpp
(gdb) p shm.m_mapped_region.m_base
$10 = (void *) 0x7ffff7ff5000
(gdb) p myshmvector
$11 = (MyShmStringVector *) 0x7ffff7ff5268
(gdb) p myshmvector->data()
$12 = (boost::container::basic_string<...> *) 0x7ffff7ff52a0
(gdb) p (*myshmvector)[0].data()
$13 = 0x7ffff7ff52a9 "this is my text"
```
Here we see that `myshmvector` (which is a `bip::vector` of `bip::string`, with all allocators correctly defined) is constructed in the shared memory address range, as is it's first element, as well as the internal data of the first element.
My guess is that fixing this issue will also resolve #4.
Contributor guide
No contributing guide indexed for this repository
Assessment
This issue has not been assessed yet.