Boost logo

Boost Users :

Subject: [Boost-users] Interprocess container segmentation fault (example provided)
From: Davidson, Josh (josh.davidson_at_[hidden])
Date: 2012-03-01 13:01:26


I'm running into issues with using interprocess containers have other containers added to them during runtime. A very high level description is I have a set of data structures in shared memory that can be accessed and modified by more than one process. I'm creating the data structures in the first process and storing the name of the segment within the data structure. Methods that modify the data by adding another container first lookup the segment using its name, build the new container, and then insert it into the existing container. In the example I'm providing below, I have a map of lists. For some reason, when I add a new list, if I open the segment by name, and allocate the list using the segment manager returned via the lookup, the list isn't initialized correctly and accessing the list (via printData here) results in a segfault. However, if I bypass the segment lookup and just cache the raw pointer to the segment, it works. It's probably easiest just to look at the code below. In addMessage, you can see how I'm trying to initialize the list in a manner that will work across multiple processes. This breaks. Commented out directly below it is a hack that will work. I can't see any reason why one works and the other doesn't. The "managed_shared_memory" object returned from the lookup appears to be valid and exactly the same as the pointer I'm caching with the data structure in this example.

I am currently using 1.49 final, but I've observed similar behavior in other 1.4x releases.

=================================BEGIN CODE====================================================
#include <stdint.h>
#include <cstddef>
#include <string>
#include <functional>
#include <iostream>
#include <utility>

using std::cerr;
using std::endl;
using std::pair;

#include <boost/interprocess/managed_shared_memory.hpp>
#include <boost/interprocess/allocators/allocator.hpp>

#include <boost/interprocess/offset_ptr.hpp>
#include <boost/interprocess/containers/string.hpp>
#include <boost/interprocess/containers/list.hpp>
#include <boost/interprocess/containers/map.hpp>
#include <boost/ref.hpp>

using namespace boost::interprocess;

class SharedMemoryDeleter {
public:

    SharedMemoryDeleter(const std::string& name) : mName(name) {
        shared_memory_object::remove(mName.c_str());
    }

    ~SharedMemoryDeleter() {
        shared_memory_object::remove(mName.c_str());
    }

protected:
    std::string mName;
};

class TestStore {
public:
    struct TestData {
        uint16_t commandStatus;
        size_t wordCount;
        uint16_t data[32];
    };

    ///Allocates characters in shared memory
    typedef allocator<char, managed_shared_memory::segment_manager> CharAllocator;

    ///String in shared memory
    typedef basic_string<char, std::char_traits<char>, CharAllocator> SharedMemoryString;

    ///Allocates list in shared memory
    typedef allocator<TestData, managed_shared_memory::segment_manager> ListAllocator;
    ///List of TestData items in shared memory
    typedef list<TestData, ListAllocator> SharedMemoryList;

    ///Key/Value pair for the map (SA, Data List)
    typedef pair<const unsigned, SharedMemoryList> data_map_value_t;

    ///Allocates maps in shared memory
    typedef allocator<data_map_value_t, managed_shared_memory::segment_manager> MapAllocator;
    ///Maps lists to SAs in shared memory
    typedef map<unsigned, SharedMemoryList, std::less<unsigned>, MapAllocator> SharedMemoryMap;

    TestStore(managed_shared_memory& segment, const std::string& name) :
        mSegment(&segment),
        mSegmentName(name.c_str(),
                CharAllocator(mSegment->get_segment_manager())),
        mData(std::less<unsigned>(), MapAllocator(mSegment->get_segment_manager())){
    }

    ///////////////////////////////////////////////////////////////////////////
    /// Destructor
    ///////////////////////////////////////////////////////////////////////////
    virtual ~TestStore() {

    }

    void printData() {
        TestStore::SharedMemoryMap::iterator it = mData.begin();

        while(it != mData.end()) {
            TestStore::SharedMemoryList::iterator lIt = it->second.begin();
            cerr << "SA: " << it->first << endl;
            cerr << it->second.size() << endl;
            while (lIt != it->second.end()) {
                cerr << "\titerating..." << endl;
                cerr << "wc: " << lIt->wordCount << endl;
                cerr << "cs: " << lIt->commandStatus << endl;

                cerr << "\t" << lIt->commandStatus << ", WC: "
                        << lIt->wordCount << endl;
                ++lIt;
            }
            ++it;
        }

        cerr << endl;
    }

    bool addMessage(unsigned key, const TestData& data) {
        TestStore::SharedMemoryMap::iterator it = mData.find(key);

        cerr << "Adding word count " << data.wordCount << endl;

        if(it != mData.end()) {
            it->second.push_back(data);
        }
        else {
            cerr << "Looking for " << mSegmentName.c_str() << endl;
            managed_shared_memory m(open_only, mSegmentName.c_str());
            cerr << "found it" << endl;

            cerr << m.check_sanity() << " - " << m.get_free_memory() << "/" << m.get_size() << endl;
            cerr << mSegment->check_sanity() << " * " << mSegment->get_free_memory() << "/" << mSegment->get_size() << endl;

          ///!!!!!!!!!!!!!!!BROKE!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
          TestStore::SharedMemoryList sList(TestStore::ListAllocator(
                                          m.get_segment_manager()));

          //==========This Works (obviously only for current process)===========
// TestStore::SharedMemoryList sList(TestStore::ListAllocator(
// mSegment->get_segment_manager()));

            sList.push_back(data);
            cerr << "pushed" << endl;
            cerr << sList.front().wordCount << endl;

            mData.insert(TestStore::SharedMemoryMap::value_type(key, sList));

            cerr << "added list" << endl;

        }

        cerr << "====================Data post add===================" << endl;
        printData();

        return true;

    }

private:
    ///Segment housing this class. Only valid in the constructing process
    managed_shared_memory* mSegment;

    ///Name of the segment
    SharedMemoryString mSegmentName;

    SharedMemoryMap mData;
};

int main() {
    std::string name = "MemHere";
    int num_bytes = 645360;

    SharedMemoryDeleter deleter(name);
    managed_shared_memory shm(open_or_create, name.c_str(), num_bytes);

    TestStore store(shm, name);

    TestStore::TestData data;
    data.commandStatus = 10;
    data.wordCount = 14;

    store.addMessage(3, data);

    return 0;
}


Boost-users list run by williamkempf at hotmail.com, kalb at libertysoft.com, bjorn.karlsson at readsoft.com, gregod at cs.rpi.edu, wekempf at cox.net