访问共享内存时出现分段错误

Posted

技术标签:

【中文标题】访问共享内存时出现分段错误【英文标题】:Segmentation Fault while acessing shared memory 【发布时间】:2019-07-31 11:25:25 【问题描述】:

我想为我的应用程序使用共享内存。 我有两个过程。一个将创建共享内存(写入器),另一个将附加到此共享内存以读取它(读取器)。 从作家方面,我能够在共享内存中写入。但是从阅读器代码中,我能够成功获取并附加到内存。 但是当我尝试从这个内存中读取时,它会产生段错误。

编写器代码:

#include<stdio.h>

#include<sys/ipc.h>
#include<sys/shm.h>
#include<sys/types.h>
#include<string.h>
#include<errno.h>
#include<stdlib.h>
#include<unistd.h>
#include<string.h>

#define BUF_SIZE 4096
#define SHM_KEY 0x1239
#define MAX_FIFO_ELEMENTS   100


struct stcomndstruct

    unsigned char status;
    unsigned int command_id;
    unsigned int event_id;
    unsigned int event_subid;
    unsigned int datasize;
    unsigned int offset;
;

struct stcirFIFO

     int head;
     int tail;
    //unsigned int status;
    struct stcomndstruct command[MAX_FIFO_ELEMENTS];
;



int main(int argc, char *argv[]) 
   int shmid, numtimes,i=0;
   struct stcirFIFO *shmp;
   char *bufptr;
   int spaceavailable;
   shmid = shmget(SHM_KEY, sizeof(struct stcirFIFO), 0644|IPC_CREAT);
   if (shmid == -1) 
      perror("Shared memory");
      return 1;
   

   // Attach to the segment to get a pointer to it.
   shmp = shmat(shmid, NULL, 0);
   if (shmp == (void *) -1) 
      perror("Shared memory attach");
      return 1;
   
   printf("\n WRITER ADDRESS %d",shmp);
   /* Transfer blocks of data from buffer to shared memory */
   shmp->head=0;
   for(i=0;i<60;i++)
   
       shmp->head=shmp->head+1;
       sleep(1);
   
   spaceavailable = BUF_SIZE;

   printf("Writing Process: Wrote %d times\n", numtimes);

sleep(10);
   if (shmdt(shmp) == -1) 
      perror("shmdt");
      return 1;
   

   if (shmctl(shmid, IPC_RMID, 0) == -1) 
      perror("shmctl");
      return 1;
   
   printf("Writing Process: Complete\n");
   return 0;

阅读器代码快照:

#define KEY_FIFO_VAR_SH_MEM 0x1239
void reader()

int shmid,i;
    struct stcirFIFO *shmp;
    printf("\n\n*******shared mem init called\n");
    shmid = shmget(KEY_FIFO_VAR_SH_MEM, sizeof(struct stcirFIFO), 0644|IPC_CREAT);
    if (shmid == -1) 
        perror("Shared memory");
        return 1;
    else
    
        printf("\nLocate sucessfull...");
    

    // Attach to the segment to get a pointer to it.
    shmp = shmat(shmid, NULL, 0);
    if (shmp == (void *) -1) 
        perror("Shared memory attach");
        return EXIT_FAILURE;
    else
    


        printf("\nAttach sucessfull...address %d",shmp);
        printf("address of head %d",&(shmp->head));

    
    for(i=0;i<10;i++)
    
        printf("Read Value %d",*shmp);
        sleep(1);
    

追踪日志:

write(1, "\n\n*******shared mem init called", 31

*******shared mem init called) = 31
write(1, "\n", 1
)                       = 1
shmget(0x1239, 2408, IPC_CREAT|0644)    = 13762590
write(1, "\nLocate sucessfull...", 21
Locate sucessfull...)  = 21
shmat(13762590, NULL, 0)                = 0x7f4c22a71000
write(1, "\nAttach sucessfull...address 581"..., 38
Attach sucessfull...address 581373952) = 38
write(1, "address of head 581373952", 25address of head 581373952) = 25
--- SIGSEGV si_signo=SIGSEGV, si_code=SEGV_MAPERR, si_addr=0x22a71000 ---
+++ killed by SIGSEGV (core dumped) +++
Segmentation fault (core dumped)

【问题讨论】:

不要只发布代码sn-ps,发布最小,而是可以编译并且仍然重现错误的完整代码。您当前发布的阅读器代码不会产生 SIGSEGV。 实际上代码太大了大约 50 个文件,因此我只发布导致 seg 错误的部分。从 Strace 帖子中,您可以看到它导致的段错误。 您需要将这 50 个文件修剪为最小但完整的示例。我花了 30 秒将相关部分添加到您的阅读器代码中以使其编译并确保它不会以这种方式崩溃。您也应该这样做并找出导致此段错误的实际原因,而不是在没有上下文的情况下发布您认为会导致段错误但不会导致段错误的代码。 例如。您可能有一个代码,其中printf("Hello world\n"); 导致段错误,但仅发布此行并寻求帮助是没有意义的,因为问题显然依赖于其他地方。而且,对要包含的相关代码进行假设也是毫无意义的,因为您实际上不知道实际问题是什么。这就是为什么我们需要最小但完整的示例。 使用 gcc 版本 5.4.0 20160609 (Ubuntu 5.4.0-6ubuntu1~16.04.10) 会导致 seg 错误,但是当我使用 gcc-linaro-arm-linux-gnueabihf-4.9-2014.09 编译相同的代码时_linux 用于 petalinux 的工具链在我拥有的另一个开发板上工作得非常好.. 【参考方案1】:

当您访问未经授权的内存时会发生分段错误。 shmget() 返回与参数键值关联的 System V 共享内存段的标识符。它可用于获取先前创建的共享内存段的标识符(当 shmflg 为零且 key 不具有值 IPC_PRIVATE 时),或创建新集合。

所以在接收端你应该在 shmget(); 中使用相同的键。 shmid = shmget(KEY_FIFO_VAR_SH_MEM, sizeof(struct stcirFIFO), 0644|IPC_CREAT);

【讨论】:

尊敬的先生,我更新了代码,只是名称不同但键值相同。【参考方案2】:
    struct stcirFIFO *shmp;

    ...

    printf("Read Value %d",*shmp);

由于shmp 属于struct stcrFIFO * 类型,因此您尝试使用%d 格式说明符将struct stcrFIFO 传递给printf。它期待一个int

【讨论】:

以上是关于访问共享内存时出现分段错误的主要内容,如果未能解决你的问题,请参考以下文章

尝试锁定共享内存互斥体时出现分段错误

使用共享内存时出现分段错误

尝试从 docker 容器访问共享内存时出现“权限被拒绝”,即使 --ipc 设置为“主机”

dlclose() 后访问共享库分配的内存

Linux 共享内存分段错误

通过共享内存和管道的 IPC 给出分段错误:C 中的 11