Boost logo

Boost Users :

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


Ion,

Terribly sorry, but I goofed when I cobbled that code together. My actual application constructs "TestStore" from the segment, and not on the stack like what I pasted in before. I'm including the full test code again, although only the main function changed. Since the map itself a member of TestStore and TestStore is being constructed from the segment, I would think that should be roughly equivalent to just creating the map by itself from the segment. However, as you'll see if you run it, it still seg faults when accessing the list iterator.

===================================== 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 segName = "MemSegmentHere";
    int num_bytes = 645360;

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

    std::string storeName = "TestStoreHere";
    shm.destroy<TestStore>(storeName.c_str());
    TestStore* store = shm.construct<TestStore>(storeName.c_str())(boost::ref(shm), boost::ref(segName));

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

    store->addMessage(3, data);

    return 0;
}

-----Original Message-----
From: boost-users-bounces_at_[hidden] [mailto:boost-users-bounces_at_[hidden]] On Behalf Of Ion Gaztañaga
Sent: Thursday, March 01, 2012 3:24 PM
To: Boost User List
Subject: EXTERNAL: Re: [Boost-users] Interprocess container segmentation fault (example provided)

El 01/03/2012 19:01, Davidson, Josh escribió:
> 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.

You are storing a *local* map that allocates memory in shared memory (that is, the internal pointers of the map are in the stack, whereas the allocated nodes are in shared memory), which is really a bad idea as once you unmap the segment, as the local map's internal pointers point to segmentation-fault friendly memory.

I know that "managed_shared_memory shm" outlives "TestStore store" but the problem is that you open the shm again in "managed_shared_memory m"
and that maps the shared memory *in another address, different to the address mapped by "managed_shared_memory shm"* (two views of the same shared memory, as you map a file twice). So you end up with a local map pointing to *two different address ranges* (although the share the same underlying shared memory object, just think it's like a file). Then you unmap "managed_shared_memory m" (the second address range disappears) and then when you try to iterate, when the local map tries to read an element through the second address range, you get a segmentation fault.

If you put the map itself in shared memory (e.g. use a named construct) you can avoid the problem. And if you have already mapped the shared memory once, avoid wasting OS resources (the OS must synchronize the two address ranges in the same process with the same underlying device/shm/mapped file) and application address space mapping the same shared memory/file several times.

Sometimes is useful to open the shared memory segment more than once from the same process (say, when you communicate a DLL with an application, or when trying to implement a intermodule singleton type), but in general, try to avoid this.

Best,

Ion
_______________________________________________
Boost-users mailing list
Boost-users_at_[hidden]
http://lists.boost.org/mailman/listinfo.cgi/boost-users


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