共享内存元素操作触发段错误,求排查与解决方法
共享内存操作触发段错误的排查与修复
问题描述
编写了一段向共享内存插入结构体的C语言代码,调试发现对共享内存元素操作时触发段错误,甚至shared_pid_atom->dimensione = 0;这类简单赋值都失败。代码如下:
static shared_pid_data *shared_pid_atom; static int shmidA; static int semidA; void atomSharedPidInit(){ key_t key = ftok("shmfileA",65); printf("atomSharedPidInit - key = ftok\n"); shmidA = shmget(key, sizeof(shared_pid_data), 0666|IPC_CREAT); printf("atomSharedPidInit - shmget\n"); shared_pid_atom = (shared_pid_data*) shmat(shmidA, (void*)0, 0); printf("atomSharedPidInit - shmat\n"); key_t sem_key = ftok("semfileA", 75); printf("atomSharedPidInit - sem_key = ftok\n"); semidA = semget(sem_key, 1, 0666 | IPC_CREAT); printf("atomSharedPidInit - semget\n"); semctl(semidA, 0, SETVAL, 1); printf("atomSharedPidInit - semctl\n"); } void lockA() { struct sembuf sba = {(unsigned short) 0, -1, 0}; semop(semidA, &sba, 1); } void unlockA() { struct sembuf sba = {(unsigned short) 0, 1, 0}; semop(semidA, &sba, 1); } void atomSharedPidWrite(pid_t pid) { lockA(); printf("atomSharedPidWrite - lock\n"); int dim = shared_pid_atom->dimensione; printf("atomSharedPidWrite - int dim\n"); if (dim < 1000) { printf("atomSharedPidWrite - if\n"); shared_pid_atom->atomi_pid[shared_pid_atom->dimensione] = pid; shared_pid_atom->dimensione++; printf("pid : %d dimensione : %d ",shared_pid_atom->atomi_pid[shared_pid_atom->dimensione-1],shared_pid_atom->dimensione); } else { fprintf(stderr, "Shared memory is full\n"); } unlockA(); } int main (){ atomSharedPidInit(); printf("simulazione - atomSharedPidInit\n"); alarm((unsigned int)sim_duration); printf("simulazione - alarm\n"); print_statistics(); for (int i = 0; i < n_atomi_init; i++) { atomoPID = fork(); if (atomoPID == 0) { printf("Atomo - fork\n"); srand((unsigned int)(time(NULL) + getpid())); printf("Atomo - srand\n"); atomSharedPidWrite(getpid()); printf("Atomo - atomSharedPidWrite(getpid())\n"); int numero_atomico = rand() % max_num_atomico + min_num_atomico; printf("%d %d %d ", numero_atomico, max_num_atomico, min_num_atomico); char num_atomico_str[10]; sprintf(num_atomico_str, "%d", numero_atomico); execl("./atomo", "./atomo", num_atomico_str, NULL); exit(0); } else if (atomoPID < -1) { kill(getpid(), SIGINT); exit(EXIT_FAILURE); } } }
运行输出:
atomSharedPidInit - key = ftok atomSharedPidInit - shmget atomSharedPidInit - shmat atomSharedPidInit - sem_key = ftok atomSharedPidInit - semget atomSharedPidInit - semctl simulazione - atomSharedPidInit simulazione - alarm Current state: Total energy: 0 Total energy consumed: 0 Total energy available: 0 Total atomi attivi: 0 Total scissions: 0 Total activations: 0 Total scorie: 0 +---------------------------------------------------+ Atomo - fork Atomo - srand atomSharedPidWrite - lock Atomo - fork Atomo - srand Atomo - fork Atomo - srand Atomo - fork Atomo - fork Atomo - srand Atomo - srand atomSharedPidWrite - lock atomSharedPidWrite - lock atomSharedPidWrite - lock atomSharedPidWrite - lock make: *** [Makefile:38: run] Errore di segmentazione (creato dump del core)
问题分析
从输出看,子进程执行到atomSharedPidWrite - lock后触发段错误,核心原因集中在以下几点:
- 共享内存挂载失败未检查:
shmat返回(void*)-1表示挂载失败,但代码未做校验,导致shared_pid_atom是无效指针,后续访问直接触发段错误。 - ftok依赖的文件不存在:
ftok需要依赖的文件(shmfileA、semfileA)必须存在,若文件不存在,ftok返回-1,后续shmget和semget会失败,导致共享内存/信号量ID无效。 - 共享内存结构体初始化缺失:首次创建共享内存时,内存内容是随机值,
dimensione可能是极大值,导致数组越界访问。 - 信号量操作未做错误检查:
semop、semctl可能执行失败,导致锁机制失效,多进程同时操作共享内存引发竞态,进而触发段错误。
修复方案
1. 检查所有IPC调用的返回值
在每个IPC函数调用后添加错误检查,确保操作成功:
// 需提前定义semun联合体(部分系统需手动定义) union semun { int val; struct semid_ds *buf; unsigned short *array; struct seminfo *__buf; }; void atomSharedPidInit(){ // 确保ftok依赖文件存在 int fd = open("shmfileA", O_CREAT | O_RDWR, 0666); if (fd == -1) { perror("open shmfileA failed"); exit(EXIT_FAILURE); } close(fd); fd = open("semfileA", O_CREAT | O_RDWR, 0666); if (fd == -1) { perror("open semfileA failed"); exit(EXIT_FAILURE); } close(fd); key_t key = ftok("shmfileA",65); if (key == -1) { perror("ftok shmfileA failed"); exit(EXIT_FAILURE); } printf("atomSharedPidInit - key = ftok\n"); shmidA = shmget(key, sizeof(shared_pid_data), 0666|IPC_CREAT); if (shmidA == -1) { perror("shmget failed"); exit(EXIT_FAILURE); } printf("atomSharedPidInit - shmget\n"); shared_pid_atom = (shared_pid_data*) shmat(shmidA, (void*)0, 0); if (shared_pid_atom == (void*)-1) { perror("shmat failed"); exit(EXIT_FAILURE); } printf("atomSharedPidInit - shmat\n"); // 首次创建共享内存时初始化结构体 struct shmid_ds shm_info; if (shmctl(shmidA, IPC_STAT, &shm_info) == 0 && shm_info.shm_nattch == 1) { shared_pid_atom->dimensione = 0; memset(shared_pid_atom->atomi_pid, 0, sizeof(shared_pid_atom->atomi_pid)); } key_t sem_key = ftok("semfileA", 75); if (sem_key == -1) { perror("ftok semfileA failed"); exit(EXIT_FAILURE); } printf("atomSharedPidInit - sem_key = ftok\n"); semidA = semget(sem_key, 1, 0666 | IPC_CREAT); if (semidA == -1) { perror("semget failed"); exit(EXIT_FAILURE); } printf("atomSharedPidInit - semget\n"); union semun sem_union; sem_union.val = 1; if (semctl(semidA, 0, SETVAL, sem_union) == -1) { perror("semctl SETVAL failed"); exit(EXIT_FAILURE); } printf("atomSharedPidInit - semctl\n"); }
2. 修复信号量操作的错误检查
修改lockA和unlockA函数,添加错误检查:
void lockA() { struct sembuf sba = {(unsigned short) 0, -1, 0}; if (semop(semidA, &sba, 1) == -1) { perror("semop lock failed"); exit(EXIT_FAILURE); } } void unlockA() { struct sembuf sba = {(unsigned short) 0, 1, 0}; if (semop(semidA, &sba, 1) == -1) { perror("semop unlock failed"); exit(EXIT_FAILURE); } }
3. 确认shared_pid_data结构体定义正确
确保结构体中的atomi_pid数组大小至少为1000:
#define MAX_ATOMI 1000 typedef struct { int dimensione; pid_t atomi_pid[MAX_ATOMI]; } shared_pid_data;
验证修复效果
添加上述检查和初始化后,程序应能正常操作共享内存,不会触发段错误。若仍有问题,可通过gdb调试core文件,定位段错误具体位置进一步排查。
内容的提问来源于stack exchange,提问作者MiusiZ
相关产品推荐
相关产品推荐

