2017-04-16 6 views
0

공유 메모리에서 IPC를 시도하는 두 개의 파일이 있습니다. 두 파일에 비슷한 문장을 사용하여 할당합니다. 서버 파일에서 :C 메모리 매핑 된 구조체 배열 누수

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); 

출력이 mindboggling된다 를 서버 단말로부터 I 얻을 :

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 
... 

는 [MAX_LEN 상기 클라이언트 단말 I에서

즉 클라이언트까지의 client_message 어레이 (10 개)의 요소의 변경 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 

그래서 구조체 영역의 항목은 다른 프로세스에서 도달 할 때 혼합됩니다. 이 문제를 어떻게 방지 할 수 있습니까?

+1

struct에 유연한 배열 멤버가 2 개있을 수 없습니다. 기본적으로'rptr-> ptr_client_message'와'rptr-> ptr_server_message' 별칭입니다. –

+0

감사합니다. 개선이 도움이 되셨습니까? 그건 그렇고, 당신은 어떻게 그것을 확실히 알고 있습니까, 나는 어떤 참조를 의미합니까? –

+1

http://port70.net/~nsz/c/c11/n1570.html#6.7.2.1p18 : "특별한 경우로, 둘 이상의 명명 된 멤버가있는 구조의 마지막 요소에 불완전한 배열 유형이있을 수 있습니다. 이것을 유연한 배열 구성원이라고 부릅니다. " –

답변

1

문제는 하나의 구조체에 zero length array trick을 두 번 사용할 수 없다는 것입니다.

struct region에서 사용하는 속임수는 구조체에 가변 길이 배열을 허용하는 GCC 확장입니다. 길이가 0 인 배열은 헤더 역할을하며, 결국 원하는만큼 많은 메모리를 집어 넣었다는 것을 기억할 수 있습니다.

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

문제 rptr->client_message 직후 다른 제로 길이 배열 rptr->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); 

이제 우리는 2 개의 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); 

따라서 하나의 구조체에는 두 개의 길이가 0 인 배열을 사용할 수 없습니다.

+0

감사합니다. ilja Everilä가 말한 것이었지만, 그 과정이 여러 차례 연속적으로 작용 한 이유는 무엇입니까? 그 절차가 왜 5 번 연속으로 작용했는지에 대해서는 설명하지 않았지만 클라이언트 1 클라이언트 3과 클라이언트 5 결과를 혼합했습니다. –

+0

@ b.g. Wonderful World of Undefined Behavior (https://en.wikipedia.org/wiki/Undefined_behavior)에 오신 것을 환영합니다! 모든 종류의 타이밍 문제를 야기하는 다중 프로세스 공유 메모리가 추가되었습니다. 코드를 보지 않고서는 어떤 일이 일어날 지 짐작할 수는 없지만 코드가 이미 쓰레기통에 들어갔 기 때문에 문제가됩니다. 눈을 가린 차를 운전하고 길에서 나와서 "내가 추락하기 전에 왜 3 분 *이 걸렸을까요? 왜 4 명이나 아니면 2 명입니까?"라고 궁금해하는 것과 같습니다. – Schwern