mercredi 9 octobre 2019

SEGV thrown with std::unordered_map using boost interprocess allocators after shrink_to_fit()

I'm using boost-1.68 and gcc-7.3.0 with -std=c++11. The following code as written throws a SIGSEGV for me.

The problem is caused by the combination of using std::unordered_map along with the boost interprocess shrink_to_fit() method. Changing the shared::unordered_map type from std::unordered_map to boost::unordered_map and/or commenting out the call to shrink_to_fit() will fix the code.

I ultimately don't intend to use std::unordered_map, but the fact that this minimal example is failing makes me concerned that I'm not properly setting up and/or not properly using the allocators.

Any insight would be appreciated.

#include <iostream>
#include <unordered_map>
#include <scoped_allocator>

#include <boost/interprocess/managed_mapped_file.hpp>
#include <boost/interprocess/allocators/allocator.hpp>
#include <boost/interprocess/containers/string.hpp>
#include <boost/container_hash/hash.hpp>
#include <boost/unordered_map.hpp>
#include <boost/lexical_cast.hpp>

using std::cout;
using std::endl;

namespace shared {
    using segment_type = boost::interprocess::managed_mapped_file;
    using segment_manager = segment_type::segment_manager;

    template <typename T>
    using Alloc = boost::interprocess::allocator<T, segment_manager>;

    template <typename T>
    using ScopedAlloc = std::scoped_allocator_adaptor<Alloc<T>>;

    using string = boost::interprocess::basic_string<char, std::char_traits<char>, Alloc<char>>;

    template <typename Key, typename Val, typename KHash = boost::hash<Key>, typename KEqual = std::equal_to<Key>>
    using unordered_map =
        std::unordered_map<Key, Val, KHash, KEqual, ScopedAlloc<std::pair<const Key, Val>>>;
}

struct MyStruct {
    shared::unordered_map<shared::string, int> some_map;

    MyStruct (shared::segment_manager *smgr)
    : some_map{smgr}
    { }

    friend std::ostream& operator<< (std::ostream& os, const MyStruct& m) {
        os << "{";
        for (auto& e : m.some_map) {
            os << "{\"" << e.first << "\"," << e.second << "}";
        }
        os << "}";
        return os;
    }
};

int main () {
    const char *filename = "content.bin";
    std::remove(filename);

    {
        shared::segment_type segment(boost::interprocess::create_only, filename, (1<<20));
        MyStruct *o1 = segment.construct<MyStruct>("MyStruct01")(segment.get_segment_manager());
        o1->some_map.emplace("entry_1", 1);
        o1->some_map.emplace("entry_2", 2);
        o1->some_map.emplace("entry_3", 3);
        cout << "constructed MyStruct01: " << *o1 << endl;
    }

    shared::segment_type::shrink_to_fit(filename);

    {
        shared::segment_type segment(boost::interprocess::open_read_only, filename);
        MyStruct *o1 = (segment.find<MyStruct>("MyStruct01")).first;
        cout << "      found MyStruct01: " << *o1 << endl;
    }

    cout << "completed" << endl;
    return 0;
}

Aucun commentaire:

Enregistrer un commentaire