Run-Time Check Failure #2

本文探讨了Run-Time Check Failure #2错误的原因及其解决办法,详细分析了栈被破坏的情况,尤其是在VC++ .NET编译环境中,通过启用运行时错误检查功能(/RTC1)来帮助开发者定位和修复潜在的数组越界问题。
Run-Time   Check   Failure   #2   

  一般是栈被破坏,你的代码可能有缓冲区溢出一类的问题。


数组越界了,造成崩溃。而vc6并不检查数组越界。


Run-Time Check Failure #2 - Stack around the variable 'var' was corrupted
摘要:
简介VC++.NET编译新功能,运行时错误检查,编译选项 (/RTC1, equiv. to /RTCsu)
最近把一个别人早期在VC 6下编写的一个服务移植到VC 7.1 (.NET 2003)时,突然跳出
好些运行时错误提示。
经过查询编译器和出错说明,发现了编译器的这一新特性,并修正了代码隐患:
//someheadefile.h
typedef struct tarSomeMessagePack
{
     char moibleNumber[20];
     ....
}SomeMessagePack_T,*SomeMessagePack_Ptr;

细心的开发者可能已经发现,这里使用字符串数组下标越界了。即mobileNumber[]有效元素
下标为0到19,mobileNumber[20]是非法的。在VC 6下,编译运行并没有处任何问题,这也结
构体在内存字节对齐也有关系,实际上,mobileNumber[]在默认与8字节对齐的环境下编译链
接的,因此,后4个bit也不会被系统用到,即mobileNumber[20],mobileNumber[21],
mobileNumber[22],mobileNumber[23]系统把它空着。
尽管系统运行同几年都很正常,但
strncpy(pack.mobileNumber," ",20);
这样的代码也是危险的代码,要是有一天,把这个结构体字节对齐方式改为1,那么程序一定
在这里崩溃。
VC7.1为我们提供了一种机制,在编译选项中,增加(/RTC1, equiv. to /RTCsu)项选。当程序
运行到这里的时候,即会向我们报告这一错误。
查看相关文档,了解了这一块代码的真实意图后,我把代码改为
strncpy(pack.mobileNumber," ",19);
这一问题消失。

//someimplement.cpp
strncpy(pack.mobileNumber," ",20);

郑注:这就是一些变量的内存访问出错造成的,而且在错误对话框中明显的提出了是哪个变量访问出错,可以查这个变量得到结果。典型的错误:如定义了一个TCHAR Code[1];,结果在使用中使用到了Code[1],就产生了这个错误 

你遇到的错误: > **Run-Time Check Failure #2 - Stack around the variable &#39;buf12&#39; was corrupted.** 这是一个非常典型的 **栈缓冲区溢出(Stack Buffer Overflow)** 错误,通常由以下原因引起: --- ### 🔍 错误解释 这个错误的意思是: > 在变量 `buf12` 周围的栈内存区域被破坏了。 C 语言会在栈上为局部数组分配空间,并在编译时加入“**栈保护哨兵(canary)**”值。当你写入数据超出数组边界时(比如往一个长度为10的数组写入15个字符),就会覆盖相邻的栈内存——包括这些保护值,从而触发运行时检查失败。 这常见于使用不安全的字符串函数,如: - `strcpy` - `strcat` - `sprintf` - `scanf("%s")` - `gets` --- ### 🧪 示例:导致该错误的代码 ```c #include <stdio.h> #include <string.h> int main() { char buf12[10]; // 只能存9个字符 + &#39;\0&#39; strcpy(buf12, "This string is too long!"); // ❌ 超出 buf12 容量 printf("%s\n", buf12); return 0; } ``` 这段代码会: - 分配 `buf12[10]` → 最多容纳 9 个字符 + 结尾 `\0` - 但 `"This string is too long!"` 长度远大于 10 → 写越界 - 破坏了栈上的其他数据(可能是返回地址、其他变量等) - 触发 **Run-Time Check Failure #2** --- ### ✅ 正确解决方案(防止栈溢出) #### ✅ 方法 1:使用安全版本函数 —— `strncpy`, `strncat`, `snprintf` ```c #include <stdio.h> #include <string.h> int main() { char buf12[10]; // ✅ 使用 strncpy 并手动补 &#39;\0&#39; strncpy(buf12, "This string is too long!", sizeof(buf12) - 1); buf12[sizeof(buf12) - 1] = &#39;\0&#39;; // 确保结尾 printf("buf12: %s\n", buf12); return 0; } ``` #### ✅ 方法 2:使用 `snprintf`(推荐) ```c char buf12[10]; snprintf(buf12, sizeof(buf12), "%s", "This string is too long!"); // 自动截断并保证 &#39;\0&#39; 结尾 printf("buf12: %s\n", buf12); // 输出前9个字符 ``` #### ✅ 方法 3:输入时用 `fgets` 替代 `gets` 或 `scanf` ```c char buf12[10]; printf("Enter string: "); if (fgets(buf12, sizeof(buf12), stdin)) { buf12[strcspn(buf12, "\n")] = &#39;\0&#39;; // 去掉换行符 printf("You entered: %s\n", buf12); } else { printf("Input error.\n"); } ``` --- ### ⚠️ 其他可能导致此问题的情况 | 情况 | 示例 | |------|------| | 数组下标越界 | `buf[10] = &#39;a&#39;;`(当 size=10 时,最大索引是 9) | | 循环写入过长 | `for(i=0; i<20; i++) buf[i]=&#39;a&#39;;` | | 格式化输出失控 | `sprintf(buf, "%d", 123456789);` 但 buf 太小 | | 使用未初始化指针 | `char *p; strcpy(p, "abc");` → 未分配内存 | --- ### 💡 如何调试这类问题? 1. **看报错变量名**:如 `buf12`,定位到声明它的函数和位置。 2. **检查所有对该变量的操作**:尤其是 `strcpy`, `sprintf`, `scanf`, `strcat` 等。 3. **打印长度对比**: ```c printf("String length: %zu, Buffer size: %zu\n", strlen("long_string"), sizeof(buf12)); ``` 4. **使用静态分析工具或编译器警告**: - GCC/Clang 加 `-Wall -Wextra` - MSVC 开启 `/RTC1`(运行时检查) --- ### ✅ 总结:如何避免 Stack Corruption | 措施 | 做法 | |------|------| | ❌ 禁止使用危险函数 | `gets`, `strcpy`, `strcat`, `sprintf`, `scanf("%s")` | | ✅ 使用安全替代品 | `fgets`, `strncpy`, `strncat`, `snprintf` | | ✅ 显式控制长度 | 所有操作都加上 `sizeof(buffer)` 限制 | | ✅ 初始化数组 | `char buf[100] = {0};` | | ✅ 编译时开启检查 | VS 中启用 `/RTC1`,GCC 使用 `-fstack-protector` | ---
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值