C内存映射结构数组泄漏

时间:2017-04-16 13:37:15

标签: c arrays struct shared-memory

我有两个文件,我通过共享内存尝试IPC。我在两个文件中使用类似语句进行分配。在服务器文件中:

int fd;
int size = MAX_LEN;
int bigSize = sizeof(struct region)+ size * sizeof(struct client_message) + size * sizeof(struct server_message);
    struct region *rptr = (struct region*)malloc(bigSize);
    printf("region size: %d clientMessage size: %d serverMessage size: %d and the total size: %d\n", sizeof(struct region), size * sizeof(struct client_message), size * sizeof(struct server_message), bigSize);
    fd = shm_open("/myregion", O_CREAT | O_RDWR, S_IRUSR | S_IWUSR);

    if (ftruncate(fd, bigSize)  == -1)
        printf("error creating ftruncate\n");

    rptr = mmap(NULL, sizeof(struct region),
                PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);

我已使用以下链接上的示例动态分配共享内存: C Windows - Memory Mapped File - dynamic array within a shared struct

struct client_message {
    pthread_t client_id;
    int question;
};
struct server_message {
    pthread_t client_id;
    pid_t server_id;
    int answer;
};
struct region {        /* Defines "structure" of shared memory */
    int len;
    struct client_message ptr_client_message[0];
    struct server_message ptr_server_message[0];
};

当我在while循环中分配并在此服务器文件中增加j时,

(rptr->ptr_client_message[(j)%size]).question = 30;
(rptr->ptr_server_message[(j)%size]).answer = 20;

我从客户端文件中读取它:

printf("rptr len is %d and question of client %d is: %d, answer of server is %d \n", size, k%size, (rptr->ptr_client_message[(k)%size]).question, (rptr->ptr_server_message[(k)%size]).answer);

输出是令人难以置信的: 从服务器终端我得到:

rptr len is 10 and question of client 0 is: 30, answer of server is 20 
rptr len is 10 and question of client 1 is: 30, answer of server is 20 
rptr len is 10 and question of client 2 is: 30, answer of server is 20 
...

更改client_message数组的10个元素,即最多为client [MAX_LEN]

来自客户端我得到:

rtpr len is 10 and question of client 0 is: 30, answer of server is 20
rptr len is 10 and question of client 1 is: 30, answer of server is 30
rptr len is 10 and question of client 2 is: 30, answer of server is 20
rptr len is 10 and question of client 3 is: 30, answer of server is 30
rptr len is 10 and question of client 4 is: 30, answer of server is 20
rptr len is 10 and question of client 5 is: 30, answer of server is 30
rptr len is 10 and question of client 6 is: 30, answer of server is 20
rptr len is 10 and question of client 7 is: 30, answer of server is 20
rptr len is 10 and question of client 8 is: 30, answer of server is 20
rptr len is 10 and question of client 9 is: 30, answer of server is 20
rptr len is 10 and question of client 0 is: 30, answer of server is 20
rptr len is 10 and question of client 1 is: 30, answer of server is 30
rptr len is 10 and question of client 2 is: 30, answer of server is 20
rptr len is 10 and question of client 3 is: 30, answer of server is 30
rptr len is 10 and question of client 4 is: 30, answer of server is 20
rptr len is 10 and question of client 5 is: 30, answer of server is 30
rptr len is 10 and question of client 6 is: 30, answer of server is 20
rptr len is 10 and question of client 7 is: 30, answer of server is 20
rptr len is 10 and question of client 8 is: 30, answer of server is 20

因此,当从另一个进程到达时,结构区域中的条目是混合的。我该如何防止这种情况?

1 个答案:

答案 0 :(得分:1)

问题是你不能在一个结构中使用zero length array trick两次。

您在struct region中使用的技巧是一个GCC扩展,允许您在结构中使用可变长度数组。零长度数组充当标题,然后你可以记住你在最后添加了尽可能多的内存。

// This starts at rptr->client_message and advances two indexes.
rptr->client_message[2] = ...;

问题是在rptr->client_messagerptr->server_message之后有另一个零长度数组。因此,当您写信至rptr->client_message时,您将覆盖rptr->server_message

让我们简化一下,你会明白为什么。

struct region {
    int len;
    char ptr_client_message[0];
    char ptr_server_message[0];
};

以与您相同的方式初始化它。

size_t size = 4;
struct region *rptr = malloc(sizeof(struct region) + size + size);

现在我们看起来有两个3个字符串的位置。我们加一个。

rptr->ptr_server_message[0] = 'a';
rptr->ptr_server_message[1] = 'b';
rptr->ptr_server_message[2] = 'c';
rptr->ptr_server_message[3] = '\0';

printf("server_message: %s\n", rptr->ptr_server_message);

没关系,打印abc。现在让我们填充rptr->ptr_server_message

rptr->ptr_client_message[0] = '1';
rptr->ptr_client_message[1] = '2';
rptr->ptr_client_message[2] = '3';
rptr->ptr_client_message[3] = '\0';

printf("client_message: %s\n", rptr->ptr_client_message);

没关系,打印123。那么rptr->ptr_server_message呢?

printf("server_message: %s\n", rptr->ptr_server_message);

也打印123!事实证明,他们指向相同的记忆。

// 0x7ff5f1404144 0x7ff5f1404144
printf("%p, %p\n", rptr->ptr_client_message, rptr->ptr_server_message);

因此,在一个结构中不能有两个零长度数组。