使用POSIX读写结构体到共享内存时遇权限错误与段故障
POSIX共享内存读写结构体时的权限与段错误问题
问题描述
尝试通过POSIX接口将结构体读写至共享内存,但程序因权限问题和段错误崩溃。其中Write.cpp在输入值后会陷入循环,最终提示struct failed: cannot allocate memory并触发段错误。
原始代码
Write.cpp
#include<iostream> #include<fcntl.h> #include<sys/stat.h> #include<sys/mman.h> #include<sys/file.h> #include<unistd.h> #include<sys/types.h> #include<errno.h> #include<dirent.h> #include<string.h> #include"headerfile.h" using namespace std; int main() { int fd; char *pg_addr; int size =10000; int mode = S_IRWXO|S_IRWXG|S_IRWXU; int i=0; while(1) { cout<<"\nenter 1 to read again and 2 to exit : "; cin>>i; if(i==2) break; fd=shm_open("memory_exp1",O_RDONLY, 0666); if (fd == -1) perror("shm_open"); struct shmbuf *shmp = (shmbuf*)mmap(NULL,sizeof(*shmp),PROT_READ|PROT_WRITE,MAP_SHARED,fd,0); if(shmp==MAP_FAILED) perror("MMap error"); cout <<"\n Read data is" << shmp->buf << "\n" << shmp->cnt; } close(fd); return 0; }
Read.cpp
#include<iostream> #include<fcntl.h> #include<sys/stat.h> #include<sys/mman.h> #include<sys/file.h> #include<unistd.h> #include<sys/types.h> #include<errno.h> #include<dirent.h> #include<string.h> #include"headerfile.h" using namespace std; int main() { cout<<"point1"; int fd; char *pg_addr; int size =10000; int i=0; char strTemp[100]=""; int mode = S_IRWXO|S_IRWXG|S_IRWXU; fd=shm_open("memory_exp1",O_CREAT,mode); while(1) { cout<<"\nEnter 2 to exit\nto continue press any other value :"; cin >> i; if(i==2) break; fd=shm_open("memory_exp1",O_RDWR, mode); if (fd == -1) perror("shm_open"); if (ftruncate(fd, size) == -1) perror("ftruncate"); struct shmbuf *shmp=(shmbuf*)mmap(NULL,sizeof(*shmp),PROT_READ|PROT_WRITE,MAP_SHARED,fd,0); if(shmp == MAP_FAILED) perror("Struct failed"); cout<<"\nEnter the value"; cin>>strTemp; shmp->cnt=100; memcpy(&shmp->buf,strTemp,100); close(fd); } return 0; }
错误分析与修复方案
1. 权限冲突与共享内存创建问题
- Read.cpp首次调用
shm_open仅传O_CREAT,缺少O_RDWR标志,导致创建的共享内存无法正常读写,后续ftruncate可能失败。
修复:修改首次shm_open调用:fd=shm_open("memory_exp1",O_CREAT|O_RDWR, mode); - Write.cpp中
shm_open用O_RDONLY打开,但mmap指定PROT_READ|PROT_WRITE,权限不匹配导致映射失败。
修复:要么将shm_open标志改为O_RDWR,要么将mmap保护位改为PROT_READ(读操作无需写权限)。
2. 内存泄漏问题
- 两个程序每次循环都调用
mmap,但从未调用munmap释放映射内存,最终触发内存耗尽错误。
修复:每次使用完映射内存后,调用munmap(shmp, sizeof(*shmp))释放资源。 - Write.cpp中
close(fd)放在循环外,每次循环重新打开fd会覆盖旧文件描述符,导致资源泄漏。
修复:在循环内完成mmap操作后立即close(fd)。
3. 越界访问与逻辑漏洞
- Write.cpp中若输入非1/2的数值,会继续执行后续代码,若此时
shm_open或mmap失败,直接访问shmp会触发段错误。
修复:在shm_open或mmap失败后,跳过后续读写逻辑,避免访问无效指针。 - Read.cpp中用
memcpy复制字符串未考虑缓冲区大小,可能导致越界。
修复:改用strncpy并手动添加字符串结束符,确保安全:strncpy(shmp->buf, strTemp, sizeof(shmp->buf)-1); shmp->buf[sizeof(shmp->buf)-1] = '\0';
修复后的示例代码(关键修改版)
修复后的Read.cpp
#include<iostream> #include<fcntl.h> #include<sys/stat.h> #include<sys/mman.h> #include<unistd.h> #include<errno.h> #include<string.h> #include"headerfile.h" using namespace std; int main() { cout<<"point1"; int fd; struct shmbuf *shmp = nullptr; const int shm_size = sizeof(struct shmbuf); int i=0; char strTemp[100]=""; const int mode = S_IRWXO|S_IRWXG|S_IRWXU; // 首次创建并初始化共享内存 fd=shm_open("memory_exp1",O_CREAT|O_RDWR, mode); if (fd == -1) { perror("shm_open create"); return 1; } if (ftruncate(fd, shm_size) == -1) { perror("ftruncate"); close(fd); return 1; } close(fd); while(1) { cout<<"\nEnter 2 to exit\nto continue press any other value :"; cin >> i; if(i==2) break; fd=shm_open("memory_exp1",O_RDWR, mode); if (fd == -1) { perror("shm_open"); continue; } shmp=(struct shmbuf*)mmap(NULL, shm_size, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0); if(shmp == MAP_FAILED) { perror("Struct failed"); close(fd); continue; } cout<<"\nEnter the value"; cin>>strTemp; shmp->cnt=100; strncpy(shmp->buf, strTemp, sizeof(shmp->buf)-1); shmp->buf[sizeof(shmp->buf)-1] = '\0'; munmap(shmp, shm_size); close(fd); } // 可选:程序退出时清理共享内存 shm_unlink("memory_exp1"); return 0; }
修复后的Write.cpp
#include<iostream> #include<fcntl.h> #include<sys/stat.h> #include<sys/mman.h> #include<unistd.h> #include<errno.h> #include<string.h> #include"headerfile.h" using namespace std; int main() { int fd; struct shmbuf *shmp = nullptr; const int shm_size = sizeof(struct shmbuf); int i=0; while(1) { cout<<"\nenter 1 to read again and 2 to exit : "; cin>>i; if(i==2) break; if(i!=1) { cout<<"Invalid input, please enter 1 or 2\n"; continue; } fd=shm_open("memory_exp1",O_RDONLY, 0666); if (fd == -1) { perror("shm_open"); continue; } shmp = (struct shmbuf*)mmap(NULL, shm_size, PROT_READ, MAP_SHARED, fd, 0); if(shmp==MAP_FAILED) { perror("MMap error"); close(fd); continue; } cout <<"\n Read data is: " << shmp->buf << "\n Count: " << shmp->cnt; munmap(shmp, shm_size); close(fd); } return 0; }
内容的提问来源于stack exchange,提问作者ram
相关产品推荐
相关产品推荐

