Linux共享内存开发时向struct赋值触发Segmentation fault求助
问题分析与修复方案
核心错误
代码中最致命的问题是mmap返回值的赋值对象错误,直接覆盖了函数入参shm指针本身:
// 错误写法 shm = mmap(0,SHMSZ,PROT_WRITE,MAP_SHARED,shm->fd,0);
mmap返回的是共享内存区域的映射起始地址,应该赋值给shm结构体的data成员,而不是覆盖shm指针本身:
// 正确写法 shm->data = mmap(NULL, sizeof(shared_data_t), PROT_READ | PROT_WRITE, MAP_SHARED, shm->fd, 0);
之前的写法会把原本指向调用方栈上shared_memory_t结构体的指针,修改为共享内存的映射地址,后续所有对shm成员的访问都会访问非法地址,这就是段错误的根本原因。感知到段错误发生在shm->fd = shm_fd行,大概率是编译优化导致调试行号偏移,实际错误触发在后续访问shm->data的位置。
其他需要修复的问题
- 统一共享内存大小:
ftruncate用的是sizeof(struct shared_data),但mmap原逻辑用的是SHMSZ宏,两者如果不一致会导致访问越界,建议统一使用sizeof(shared_data_t)避免错误,不需要额外定义SHMSZ宏。 - 增加
mmap返回值校验:mmap失败会返回MAP_FAILED,原逻辑没有做错误判断,建议补充校验逻辑。 - 补充
mmap权限:原逻辑仅设置了PROT_WRITE,后续如果读取共享内存内容会触发权限错误,建议加上PROT_READ。 - 信号量初始化校验:
sem_init失败会返回-1,建议补充错误判断避免异常。 - 增加错误分支的资源清理:创建失败时要及时关闭已打开的文件描述符、解除已建立的映射,避免资源泄漏。
修复后核心代码片段
bool create_shared_object( shared_memory_t* shm, const char* share_name ) { int shm_fd; // 先删除已存在的共享内存对象 shm_unlink(share_name); shm->name = share_name; shm_fd = shm_open(share_name, O_CREAT | O_RDWR, 0666); if(shm_fd == -1){ shm->data = NULL; return false; } shm->fd = shm_fd; if(ftruncate(shm->fd, sizeof(shared_data_t)) == -1){ shm->data = NULL; close(shm->fd); return false; } shm->data = mmap(NULL, sizeof(shared_data_t), PROT_READ | PROT_WRITE, MAP_SHARED, shm->fd, 0); if (shm->data == MAP_FAILED) { shm->data = NULL; close(shm->fd); return false; } if (sem_init(&shm->data->controller_semaphore, 1, 0) != 0 || sem_init(&shm->data->worker_semaphore, 1, 0) != 0) { munmap(shm->data, sizeof(shared_data_t)); close(shm->fd); shm->data = NULL; return false; } return true; }
程序退出前需要做清理操作,避免共享内存对象残留在系统中:
// 清理示例 sem_destroy(&shm.data->controller_semaphore); sem_destroy(&shm.data->worker_semaphore); munmap(shm.data, sizeof(shared_data_t)); close(shm.fd); shm_unlink(shm.name);
内容的提问来源于stack exchange,提问作者RogueTamago
相关产品推荐
相关产品推荐

