Search code examples
c++classboostsegmentation-faultboost-interprocess

using boost::interprocess in class object segfaults, why?


I'm trying to get some code working that uses a class to set up and manage shared memory, and call an object of that class from my main prog. All the code works when it is directly in my main(), but when I set it up in a class, and instantiate an object of that class, I get a segfault.

I don't know why or how to fix it?

First example here shows the example working without problem in my main() function:

#include <boost/interprocess/managed_shared_memory.hpp>
using namespace boost::interprocess;

typedef struct teststruct {
    int     testint=9;
};

typedef std::pair<teststruct, int> memsh_teststruct;

int main(int argc, char *argv[])
{


    printf("inMain0\n");


    struct shm_remove
    {
        shm_remove() { shared_memory_object::remove("testShare"); }
        ~shm_remove(){ shared_memory_object::remove("testShare"); }
    } remover;

    //Construct managed shared memory
    managed_shared_memory segment(create_only, "testShare", 65536);


    teststruct myTeststruct;
    memsh_teststruct *inst_teststruct;

    inst_teststruct = segment.construct<memsh_teststruct>
        ("name_myTeststruct") 
        (myTeststruct, 0); 

    printf("construct_ptr: %p \n", &inst_teststruct->first);

    inst_teststruct->first.testint = 1234;

    printf("construct_val: %d\n", inst_teststruct->first.testint);




    int mainInt;

    printf("inMain1\n");

    mainInt = inst_teststruct->first.testint;

    printf("mainInt: %d\n", mainInt);

    printf("inMain2\n");
}

The output looks fine, like this:

construct_ptr: 0x7f0d41834118 
construct_val: 1234
inMain0
inMain1
mainInt: 1234
inMain2

Here's the second example that sets up the exact same shared memory, but using a class.

#include <boost/interprocess/managed_shared_memory.hpp>
using namespace boost::interprocess;

typedef struct teststruct {
    int     testint=9;
};


typedef std::pair<teststruct, int> memsh_teststruct;

class testclass{
    public:
        testclass();
        bool something(int in);

        teststruct myTeststruct;
        memsh_teststruct *inst_teststruct;
};



testclass::testclass() 
{
    struct shm_remove
    {
        shm_remove() { shared_memory_object::remove("testShare"); }
        ~shm_remove(){ shared_memory_object::remove("testShare"); }
    } remover;

    //Construct managed shared memory
    managed_shared_memory segment(create_only, "testShare", 65536);

    inst_teststruct = segment.construct<memsh_teststruct>
        ("name_myTeststruct") 
        (myTeststruct, 0); 

    printf("construct_ptr: %p \n", &inst_teststruct->first);

    inst_teststruct->first.testint = 1234;

    printf("construct_val: %d\n", inst_teststruct->first.testint);
}



int main(int argc, char *argv[])
{

    printf("inMain0\n");

    int mainInt;
    testclass testclassObj;

    printf("inMain1\n");

    mainInt = testclassObj.inst_teststruct->first.testint;

    printf("mainInt: %d\n", mainInt);

    printf("inMain2\n");
}

But this second example segfaults, and this is the output:

inMain0
construct_ptr: 0x7fa222d37118 
construct_val: 1234
inMain1
Segmentation fault (core dumped)

... So why does the call to

mainInt = testclassObj.inst_teststruct->first.testint;

from main() cause a segfault?

I've also tried some other variations, such as defining other functions in my class to interact with the shared memory variables, and it also segfaults.

If I had to guess what is going on, I am feeling like the shared memory is getting closed or something before I'm expecting it to, probably after exiting the testclass() constructor. But, I don't know the proper way to avoid this, so that the shared memory instead gets closed when returning from main() when the whole testclassObj object is cleaned up.

On the other hand, maybe I'm wrong altogether?

Thanks, B

EDIT: EDIT2: last edit removed, my error was irrelevant and due to something dumb i did in regard to comment thread with Sean in his answer.


Solution

  • You are absolutely correct in your guess that the shared memory is getting closed before you expect it to.

    The managed_shared_memory is constructed in testclass::testclass and goes out of scope at the end of the constructor, closing the shared memory, but leaving inst_teststruct pointing to where the shared memory used to be.

    You'll have to keep segment around as long as there are pointers into it. The easiest way to do that is probably to lift segment to be a class member of testclass like so:

    class testclass {
    public:
        testclass();
    
        managed_shared_memory segment;
        teststruct myTeststruct;
        memsh_teststruct *inst_teststruct;
    };
    
    testclass::testclass()
        : segment(create_only, "testShare", 65536) //< Construct managed shared memory
    {
        struct shm_remove {
            shm_remove() { shared_memory_object::remove("testShare"); }
            ~shm_remove() { shared_memory_object::remove("testShare"); }
        } remover;
    
        inst_teststruct = segment.construct<memsh_teststruct>
            ("name_myTeststruct")
            (myTeststruct, 0);
    
        printf("construct_ptr: %p \n", &inst_teststruct->first);
    
        inst_teststruct->first.testint = 1234;
    
        printf("construct_val: %d\n", inst_teststruct->first.testint);
    }
    

    But, you'll have to give some thought to how best to manage the lifetime of the shared memory, especially given that there will be another process involved.