0

I want to create shared memory from a child process that can be used from other processes. However when I create shared memory with in the child the parent crashes when trying to use a pointer in the shared memory.

#include <stdio.h>
#include <unistd.h>
#include <sys/mman.h>

struct list_node
{
    char *data;
};

static int create_shared(void **pointer, int size)
{
    *pointer = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_ANON | MAP_SHARED, -1, 0);
    if(*pointer == MAP_FAILED)
    {
        perror("mmap:");
        return -1;
    }

    return 0;
}

int main(void)
{
    int rtrn;
    pid_t pid;
    struct list_node *node;

    pid = fork();
    if(pid == 0)
    {
        rtrn = create_shared((void **)&node, sizeof(struct list_node));
        if(rtrn < 0)
        {
            printf("Can't create shared node\n");
            return -1;
        }

        rtrn = asprintf(&node->data, "Test\n");
        if(rtrn < 0)
        {
            perror("asprintf:");
            return -1;
        }

        printf("data_child: %s\n", node->data);
    }
    else if(pid > 0)
    {
        /* Parent. */

        sleep(1); // Make sure child runs first.

        printf("data_parent: %s\n", node->data);
    }
    else
    {
        perror("fork");
        return -1;
    }

    return 0;
}

But when I create the shared memory in the parent process it can be used from the child process and it's not just a copy from fork() because the child can change the pointer and the parent see's it. In the example below the child changes the value of node->data from test to best.

#include <stdio.h>
#include <unistd.h>
#include <sys/mman.h>

struct list_node
{
    char *data;
};

static int create_shared(void **pointer, int size)
{
    *pointer = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_ANON | MAP_SHARED, -1, 0);
    if(*pointer == MAP_FAILED)
    {
        perror("mmap:");
        return -1;
    }

    return 0;
}

int main(void)
{
    int rtrn;
    struct list_node *node;

    rtrn = create_shared((void **)&node, sizeof(struct list_node));
    if(rtrn < 0)
    {
        printf("Can't create shared node\n");
        return -1;
    }

    rtrn = asprintf(&node->data, "Test\n");
    if(rtrn < 0)
    {
        perror("asprintf:");
        return -1;
    }

    pid_t pid;

    pid = fork();
    if(pid == 0)
    {
        printf("data_child: %s\n", node->data);

        node->data = "Best";
    }
    else if(pid > 0)
    {
        /* Parent. */

        sleep(1); // Make sure child runs first.

        printf("data_parent: %s\n", node->data);
    }
    else
    {
        perror("fork");
        return -1;
    }

    return 0;
}

So how can I create shared memory from a child so that the parent or other child process can access it?

Edit

I tried marking the memory that char *data points to as shared memory with create_shared() aka mmap but I still get segfaults when trying to print the string pointed to by char *data. Below is how I tried setting data as shared memory. I also tried memcpy thinking that just setting char *data to test was just setting the pointer to non shared memory but that does not work either.

 rtrn = create_shared((void **)&node->data, 5);
 if(rtrn < 0)
 {
     printf("Can't create shared data\n");
     return -1;
 }

 node->data = "Test";
 //memcpy(node->data, "Test", 4); 
Community
  • 1
  • 1
2trill2spill
  • 1,333
  • 2
  • 20
  • 41
  • @Dmitri I think your right about the duplicate, thanks for pointing out that article. – 2trill2spill Sep 04 '15 at 19:22
  • In addition, the string `node->data` points to needs to be within that (or another) shared memory area or the parent won't have access to it (even though it can access `node` itself). – Dmitri Sep 04 '15 at 19:32

1 Answers1

0
char *data;

You shared a part of the memory, but that only contains a pointer.

Where it points to isn't visible to the other processes.

Share the string. Alternatively, if you know the max length for it, use a character array instead of a pointer.


In your second example, "Best" is a string literal, and will be placed in the executable. You set to pointer to this addresses, and since both processes use the same executable, the address is going to be the same too, and the pointer is going to be valid.

Note: I think this is outside of the scope of the C standard, I'm not sure what the POSIX standard says about this, so it might not be portable...

Karoly Horvath
  • 94,607
  • 11
  • 117
  • 176