Reputation: 850
I have two files, which I'm trying to IPC by shared memory. I allocate using similar statements in both files. In the server file:
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);
I've used the example on the following link to dynamically allocate shared memory: 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];
};
when I assign in a while loop and increasing j in this server file,
(rptr->ptr_client_message[(j)%size]).question = 30;
(rptr->ptr_server_message[(j)%size]).answer = 20;
I read it from the client file as such:
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);
The outputs are mindboggling: from the server terminal I get:
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
...
changing for 10 elements of the client_message array, i.e. up to client [MAX_LEN]
from the client terminal I get:
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
So, the entries in the struct region are mixed when reached from another process. How can I prevent this?
Upvotes: 0
Views: 193
Reputation: 164919
The problem is you can't use the zero length array trick twice in one struct.
The trick you're using in struct region
is a GCC extension to allow you to have variable length arrays in a struct. The zero length array acts as a header, and then you can just remember that you tacked as much memory on the end as you like.
// This starts at rptr->client_message and advances two indexes.
rptr->client_message[2] = ...;
The problem is there's another zero length array immediately after rptr->client_message
, rptr->server_message
. So when you write to rptr->client_message
you're overwriting rptr->server_message
.
Let's simplify things and you'll see why.
struct region {
int len;
char ptr_client_message[0];
char ptr_server_message[0];
};
Initialize it in the same way you do.
size_t size = 4;
struct region *rptr = malloc(sizeof(struct region) + size + size);
Now we seemingly have place for two 3 character strings. Let's add one.
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);
That's fine, it prints abc
. Now let's populate 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);
That's fine, it prints 123
. What about rptr->ptr_server_message
?
printf("server_message: %s\n", rptr->ptr_server_message);
That prints 123
as well! It turns out they point at the same memory.
// 0x7ff5f1404144 0x7ff5f1404144
printf("%p, %p\n", rptr->ptr_client_message, rptr->ptr_server_message);
So, you can't have two zero length arrays in one struct.
Upvotes: 1