Linux Ubuntu下结构体char*成员共享内存操作内存错误问题
问题排查与解决方法
核心问题根因
你的代码存在三个核心错误点:
- 字符串存储的共享内存段申请大小不足:你申请shmID2时仅分配了4字节的空间,而存储"Alex"、"Romy"这类4个字符的字符串需要额外1字节存储结束符
\0,至少需要5字节空间,字符串溢出触发内存访问错误。 - 共享内存中存储指针的错误用法:指针是进程虚拟地址空间的局部地址,同一个共享内存段在不同进程中映射的虚拟地址可能不同,跨进程传递指针大概率访问到非法地址。你当前代码虽然在SECOND程序中重新对
A->msg赋值了当前进程内的映射地址规避了这个问题,但这种写法本身就有极高的出错风险。 - 缺少系统调用错误校验:所有的
ftok、shmget、shmat等系统调用都没有做返回值校验,出现错误时无法快速定位故障点。
排查步骤
- 给所有系统调用增加返回值判断:每调用一个系统调用后判断返回值是否为错误值(
ftok、shmget失败返回-1,shmat失败返回(void*)-1),出错时调用perror打印错误原因,可快速定位是哪一步调用出现问题。 - 检查共享内存段的大小是否匹配实际存储需求:存储字符串时必须预留结束符
\0的存储空间,申请大小为「最大预期字符串长度 + 1」。 - 检查共享内存的访问权限:确认两个程序运行用户对共享内存段有读写权限,你当前使用的0664权限符可满足同用户、同用户组的读写需求。
修复方案
方案1:最小改动修复现有逻辑
仅修改共享内存段申请大小,增加错误校验:
- 把START程序中
shmID2 = shmget(shmKEY2, sizeof(char)*4, IPC_CREAT | 0664);修改为shmID2 = shmget(shmKEY2, sizeof(char)*16, IPC_CREAT | 0664);(16字节可存储最长15个字符的字符串,可按需调整大小)。 - 为所有系统调用增加错误判断,示例如下:
shmKEY= ftok(".",'a'); if(shmKEY == -1) { perror("ftok失败"); exit(1); } int shmID = shmget(shmKEY,sizeof(struct CHAR),IPC_CREAT | 0664); if(shmID == -1) { perror("shmget失败"); exit(1); } struct CHAR* A = shmat(shmID,NULL,0); if(A == (void*)-1) { perror("shmat失败"); exit(1); }
方案2:更稳定的优化方案
直接修改结构体为定长数组,避免共享内存存储指针的风险,同时减少一次共享内存操作,逻辑更简洁:
- 修改test.h中的结构体定义:
#ifndef _TEST_H #define _TEST_H struct CHAR{ char msg[16]; // 定长数组,直接存在共享内存段中,无需额外分配 }; #endif
- 去掉shmID2相关的所有共享内存操作,仅保留shmID的共享内存段即可,读写
A->msg时直接使用字符串操作函数即可,无需额外赋值指针。
内容的提问来源于stack exchange,提问作者Neku Sakuraba
相关产品推荐
相关产品推荐

