Ошибка сегментации с общей памятью System V

Я пытаюсь понять, почему этот простой код приводит к ошибке сегментации, когда я пытаюсь скопировать некоторые символы в общую память, используя strcpy:

#include <stdlib.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#include <string.h>

int main()
{
    key_t key;
    int flag,id;
    char *buf;

    flag=IPC_CREAT|0600;
    if((key=ftok("myfile",12)) == -1 ) {
        perror("key");
        exit(2);
    }   
    printf("%X\n",key);

    if( (id=shmget(key,512,flag)) < 0) exit(1); 

    if( (buf=shmat(id,0,0)) < 0) exit(2);

    printf("PID %d, buf=%p\n",getpid(),buf);
    system("ipcs -m | grep 512");
    sleep(20);

    strcpy(buf,"Hello");
    sleep(100); 
    shmdt(buf);
    exit(0);
}

И вот что я получаю:

C1A0DAB
PID 12063, buf=0xffffffff8bc78000
0x0c1a0dab 271941746  username      600        512        1
Segmentation fault (core dumped)

Кроме того, pmap процесса указывает:

00007f778bc78000      4K rw-s-    [ shmid=0x10358072 ]

Я предполагаю, что что-то не так с указателем buf, но я пока не знаю, как это исправить.

Любые идеи?


person IbliSS    schedule 09.01.2015    source источник
comment
для разделяемой памяти код должен: #include ‹sys/types.h› и #include ‹sys/shm.h›   -  person user3629249    schedule 09.01.2015
comment
это: '#include ‹sys/ipc.h›' предназначен для межпроцессного взаимодействия, а не для общей памяти. это: '#include ‹sys/sem.h›' для семафоров, а не для разделяемой памяти   -  person user3629249    schedule 09.01.2015
comment
без правильных операторов #include этот код заставляет компилятор выдать 17 предупреждений. (и предупреждения должны быть исправлены) Кстати: при компоновке обращаются к правильным библиотекам?   -  person user3629249    schedule 09.01.2015
comment
нужно #include ‹stdio.h› для printf() и т. д. нужно #include ‹unistd.h› для getpid() и sleep()   -  person user3629249    schedule 09.01.2015
comment
один из файлов (sys/shm.h??) включает sys/ipc.h, и при компиляции с использованием этого заголовочного файла перед #include должен быть размещен следующий оператор: '#define _XOPEN_SOURCE' или '#define _SVID_SOURCE'   -  person user3629249    schedule 09.01.2015
comment
эта строка: 'if( (buf=shmat(id,0,0)) ‹ 0) exit(2);' сравнивает указатель с целым числом, и указатель не может быть меньше 0, однако код может использовать: 'if( (buf=shmat(id,0,0)) == (void*)-1) exit(2) ;'   -  person user3629249    schedule 09.01.2015


Ответы (3)


Пожалуйста, скомпилируйте со всеми включенными предупреждениями (например, не менее -Wall для gcc и clang).

Вам не хватает #include <sys/shm.h>, поэтому ваш компилятор предполагает, что smhat возвращает int, тогда как на самом деле он возвращает void*. Если размер int и void* не совпадают, у вас проблема.

Добавьте это, добавьте другие, которые вам не хватает, пока вы это делаете, и это должно работать.

person Mat    schedule 09.01.2015
comment
Большое спасибо, действительно #include ‹sys/shm.h› отсутствовал. - person IbliSS; 09.01.2015

Обратите внимание на предупреждения, которые вы получаете от компилятора. В частности, вы получаете:

file.c:22:5: warning: implicit declaration of function ‘shmat’ [-Wimplicit-function-declaration]
file.c:22:13: warning: assignment makes pointer from integer without a cast

который говорит вам, в чем проблема - компилятор предполагает, что shmat возвращает (32-битное) целое число, хотя на самом деле он возвращает (64-битный) указатель. Таким образом, вы теряете верхние 32 бита указателя...

person Chris Dodd    schedule 09.01.2015

эта информация взята с http://web.cse.ohio-state.edu/~babic/Sem.shmem.new.pdf необходимо учитывать:

важно: семафоры и разделяемые памяти, не удаленные явным образом, остаются в системе после завершения процесса, создавшего их, и даже когда пользователь выходит из системы.

Поскольку UNIX поддерживает ограниченное количество этих ресурсов, перед выходом из системы важно убедиться, что все созданные семафоры и общая память удалены.

Каталог /usr/class/cis660 содержит файл сценария rsm .dat, который обеспечивает удобный способ удаления всех семафоров и всей общей памяти одновременно.

Отдельный семафор или общую память можно удалить с помощью команды UNIX ipcrm –s sem# или ipcrm –m mem# соответственно, где sem# и mem# получаются из команды UNIX ipcs, которая перечисляет все семафоры и общую память.

person user3629249    schedule 09.01.2015