You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

使用snprintf后输出异常的原因及内存重叠相关疑问

问题分析:缓冲区溢出引发的内存污染

先拆解你的代码执行逻辑和异常的核心原因:

为什么会出现异常输出?

问题的根源是不安全的字符串操作导致缓冲区溢出,进而污染了相邻内存,一步步来看:

  1. sour2缓冲区溢出,覆盖了sour1
    你定义的struct test中,sour2只有30字节的空间,但你用strcpy写入了一个长度远超30的字符串。strcpy是完全不做边界检查的函数——它会一直写入字符,直到遇到源字符串的'\0'为止。这就导致数据直接溢出了sour2的内存边界,覆盖了栈上相邻的内存区域。
    从你的输出结果反推,你的编译器栈上局部变量的布局是:p先被分配在较低的栈地址,随后声明的sour1被分配在p的高地址侧。所以sour2溢出的内容直接覆盖了sour1的内存,把sour1原本的"try to do code"替换成了长字符串的后半部分。

  2. snprintf读取了被污染的sour1
    溢出发生后,你调用snprintf(p.buff, 255, "%s", sour1),此时sour1已经被溢出的字符串污染,所以snprintf实际是把被破坏后的sour1内容(也就是长字符串的后半部分)写入了p.buff

  3. 最终输出污染后的内容
    最后printf输出p.buffsour1,两者都已经被长字符串的后半部分覆盖,所以出现了你看到的异常输出。

如何关联内存重叠概念分析?

你提到sour1p.sour2处于不同内存位置,这确实不是传统意义上的源-目标直接内存重叠(比如用strcpy把数组A的内容复制到A+5这种场景),但本质是缓冲区溢出引发的间接内存污染/广义内存重叠

  • 传统内存重叠指的是复制操作的源地址范围和目标地址范围有重叠,会导致复制过程中数据被覆盖破坏。
  • 你的场景中,p.sour2的溢出相当于一次“非法的越界写入”,意外地将原本无关的sour1内存区域纳入了写入范围,使得sour1p.sour2的内存区域产生了间接的重叠关系——p.sour2的写入操作破坏了sour1的数据,后续读取sour1的操作又把被破坏的数据写入了p.buff,最终导致整个数据流程被污染。

简单来说,虽然两个变量的内存原本不重叠,但溢出操作强行突破了内存边界,让它们的内存区域产生了“写-读”的关联,这属于内存边界被破坏后引发的广义内存重叠问题。

修复建议

要解决这个问题,核心是避免缓冲区溢出:

  • 改用长度受限的字符串函数,比如strncpy(注意手动添加终止符,因为strncpy不会自动补'\0'):
    strncpy(p.sour2, "Create experimental data. Just take the regular simulation data and add some gaussian noise to it.", sizeof(p.sour2)-1);
    p.sour2[sizeof(p.sour2)-1] = '\0'; // 手动添加字符串终止符
    
  • 如果你的平台支持,也可以用更安全的strlcpy函数,它会自动处理终止符并返回实际写入的长度。
  • 始终确保目标缓冲区的大小足够容纳源字符串(包括'\0'),或者在写入时严格限制字节数。

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

火山引擎 最新活动