共享内存中分配tmp_buf结构体后strncpy触发段错误问题
解决共享内存中结构体指针导致的段错误问题
我来帮你分析这个段错误的问题——这是共享内存使用中很常见的一个坑!
问题根源
你把tmp_buf结构体放在了mmap映射的共享内存里,其中的char* data是一个指针类型字段。但这里的关键问题是:
- 刚映射完共享内存时,
buf_ptr->data是一个未初始化的随机值,直接用它来写数据,本质是往一个无效的虚拟内存地址写入,必然触发段错误。 - 就算你在当前进程里手动给
buf_ptr->data赋值为(char*)buf_ptr + sizeof(tmp_buf)(也就是共享内存中预留的数据区域起始地址),这个指针值在其他进程里也是无效的——因为不同进程映射共享内存到虚拟地址空间的位置可能不一样,跨进程直接传递指针是行不通的。
正确解决方案:用偏移量代替指针
要在共享内存中安全地存储指向共享区域内数据的“引用”,应该使用偏移量而不是直接的指针。偏移量记录的是数据区域相对于结构体起始地址的字节数,这样不管共享内存被映射到哪个虚拟地址,都能通过结构体指针加上偏移量计算出正确的数据地址。
修改后的代码示例
1. 重新定义结构体
把char* data替换成偏移量字段:
#include <stdio.h> #include <string.h> #include <sys/mman.h> #include <sys/stat.h> #include <fcntl.h> #include <unistd.h> #define MAX_BUFFERS 10 // 用偏移量代替指针,跨进程共享更安全 typedef struct { int size; off_t data_offset; // 数据区域相对于结构体起始地址的偏移字节数 } tmp_buf;
2. 初始化共享内存并写入数据
int main() { const size_t shm_total_size = sizeof(tmp_buf) + MAX_BUFFERS * 1024; int shm_fd = shm_open("/my_shared_memory", O_CREAT | O_RDWR, 0666); if (shm_fd == -1) { perror("shm_open failed"); return 1; } // 设置共享内存大小 if (ftruncate(shm_fd, shm_total_size) == -1) { perror("ftruncate failed"); close(shm_fd); return 1; } // 映射共享内存到当前进程地址空间 tmp_buf* buf_ptr = mmap(NULL, shm_total_size, PROT_READ | PROT_WRITE, MAP_SHARED, shm_fd, 0); if (buf_ptr == MAP_FAILED) { perror("mmap failed"); close(shm_fd); return 1; } // 初始化偏移量:数据区域紧跟在结构体之后,偏移量就是结构体的大小 buf_ptr->data_offset = sizeof(tmp_buf); // 计算数据区域的实际地址 char* data_addr = (char*)buf_ptr + buf_ptr->data_offset; // 安全写入测试数据 const char* test_content = "Hello from shared memory!"; strncpy(data_addr, test_content, strlen(test_content) + 1); buf_ptr->size = strlen(test_content) + 1; printf("Successfully wrote data: %s\n", data_addr); // 后续操作... // 清理资源 munmap(buf_ptr, shm_total_size); close(shm_fd); shm_unlink("/my_shared_memory"); return 0; }
额外注意事项
- 同步问题:如果是多进程共享这块内存,一定要用信号量、互斥锁等同步机制,避免多个进程同时读写导致数据损坏。
- 偏移量类型:使用
off_t类型是因为它是标准的偏移量类型,能覆盖大多数系统上的内存偏移范围。 - 内存大小检查:确保mmap的总大小确实是
sizeof(tmp_buf) + MAX_BUFFERS*1024,避免越界访问。
内容的提问来源于stack exchange,提问作者Tejas
相关产品推荐
相关产品推荐

