You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

生产者进程写入共享内存:同长字符串不同数组大小为何触发段错误?

问题原因分析与解决方案

核心问题:共享内存段未被重新创建,大小不匹配导致越界

你遇到的段错误根本原因是key为1234的共享内存段已经存在,且大小小于30字节,而shmget的IPC_CREAT标志不会覆盖已存在的共享内存:

  • 当你第一次运行20字节数组的代码时,系统创建了一个20字节的共享内存段(key=1234)。
  • 后续运行30字节数组的代码时,shmget发现该key的共享内存已存在,直接返回现有内存段的ID,不会创建新的30字节内存。
  • 此时你通过shmat获取的共享内存只有20字节,但memcpy(shm_addr, str, sizeof(str))会尝试写入30字节,超出了共享内存的边界,触发段错误。
  • 而再次运行20字节数组的代码时,memcpy的20字节刚好匹配现有共享内存的大小,因此不会越界报错。

验证与解决方案

  1. 验证旧共享内存的存在
    用命令行查看系统中已有的共享内存:

    ipcs -m
    

    你会看到key为1234的共享内存段,其大小为20字节。

  2. 修复方案

    • 方案1:强制创建新的共享内存段
      修改shmget调用,添加IPC_EXCL标志,这样如果该key的共享内存已存在,shmget会直接报错,避免复用旧内存:
      int shm_id = shmget((key_t)1234, sizeof(str), IPC_CREAT | IPC_EXCL | 0666);
      if (shm_id == -1) {
          perror("shmget failed");
          exit(1);
      }
      
    • 方案2:删除已存在的旧共享内存
      用命令行删除:
      ipcrm -M 1234
      
      或者在代码中通过shmctl删除(如果需要自动清理):
      // 在创建前检查并删除旧内存
      int existing_shmid = shmget((key_t)1234, 0, 0);
      if (existing_shmid != -1) {
          shmctl(existing_shmid, IPC_RMID, NULL);
      }
      
    • 额外修复:避免scanf缓冲区溢出
      你的scanf("%[^\n]", str)没有限制输入长度,若输入超过数组大小会导致栈溢出,建议改为:
      // 对应str[30]的情况,限制最多读29个字符(留1个给终止符)
      scanf("%29[^\n]", str);
      // 对应str[20]的情况
      scanf("%19[^\n]", str);
      

内容的提问来源于stack exchange,提问作者Bhavesh Pendyala

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.17 03:52:36