扫一扫
分享文章到微信
扫一扫
关注官方公众号
至顶头条
RTC 表示运行时检查。RTC 有若干子选项。与 /GS 不同,/RTC 设计用于调试版本,而不用于优化代码。与 /GS 相同的是,如果您不喜欢默认对话框,可以编写自己的处理程序。
使用 Microsoft® Visual Studio® 调试应用程序时,RTC 对话框可以为您提供在错误发生之处调试应用程序的选项。此外,还可以在 Visual Studio 中创建若干个配置,每个配置都包含各种选项的不同组合,例如,对发布版本使用 /GS 选项,而对调试版本使用一个或多个 /RTC 选项。
此选项在保护堆栈不被破坏方面采取了若干措施。
在每次调用函数时,将所有局部变量初始化为非零值。这样可以防止以前的调用对堆栈中的值的无意使用。
验证堆栈指针能够检查到堆栈破坏,例如,在一个位置将函数定义为 __stdcall,而在另一个位置将函数定义为 __cdecl 可导致堆栈破坏。
检测局部变量的溢出和不足。这与 /GS 不同,因为它仅适用于调试版本,并且检测缓冲区的两端以及所有缓冲区是否遭到破坏。
cl /Od /MLd /ZI /EHsc /RTCs GS-RTC.cpp
此命令将关闭优化 (/Od),并设置 _DEBUG 预处理器定义。
使用此命令编译样例后,请再次尝试运行 测试 1。此时它将会捕捉到覆盖操作。
测试 2 说明了不包括返回地址的堆栈溢出:
void Test2() { char buffer1[100]; char buffer2[100]; buffer1[0] = 0; for (int i=0 ; i <= sizeof(buffer2); i++) { buffer2[i] = 'a'; } buffer2[sizeof(buffer2)-1] = 0; cout << buffer2 << '-' << buffer1 << endl; }
此循环使 buffer2 溢出一个字符,因为它使用 <= 代替了 <。它将覆盖 buffer1 的第一个字符。使用 /RTCs 编译器开关进行编译并使用 gs-rtc 2 运行时,系统将显示下面的对话框:
测试 3 对缓冲区不足进行了说明:
void Test3() { char buffer1[100]; char buffer2[100]; memset(buffer1,'a',sizeof(buffer1)-1); buffer1[sizeof(buffer1)-1]=0; memset(buffer2,'b',sizeof(buffer2)-1); buffer2[sizeof(buffer2)-1]=0; *(buffer1-1) = 'c'; cout << buffer1 << endl; cout << buffer2 << endl; }
(要运行测试 3,请使用命令“gs-rtc 3”。)在本例中,buffer2 的最后一个字节被覆盖,并且对话框将显示 buffer1 出现的问题。如果不进行运行时检查,此测试的输出结果为:
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaa bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbcaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
由于这一写入操作破坏了 buffer2 的终止符,因此,所有将 buffer2 用作空结束字符串的操作都将获得一个长度为期望值两倍的字符串。
测试 4 显示了 /RTCs 选项如何将未初始化变量设置为“标志”值:
void Test4() { unsigned int var; cout << hex << var; }
在使用 /RTCs 编译之后运行 测试 4时,将得到十六进制值 cccccccc。如果不使用 /RTCs 进行编译,将得到堆栈中剩余的随机值。
此选项将插入代码,以便在分配导致数据丢失时向您发出警报,这样可以确保在转换为较小类型时从不丢失数据。测试 5 说明以下内容。
void Test5(int value) { unsigned char ch; ch = (unsigned char)value; }
请执行以下命令来编译此代码:
cl /Od /MLd /ZI /EHsc /RTCc GS-RTC.cpp
请在命令提示符处使用其他数字来运行此命令。例如,此命令将触发错误:
gs-rtc 5 300
无符号字符最多可容纳 255 个字符,因此向程序中输入 300 将导致数据丢失。使用 gs-rtc 5 200 再次运行命令,此时将不会出现错误。
如果要转换为较小类型,并要故意丢失上面的数位,则可以使用如下所示的掩码:
ch = (unsigned char)(value & 0xFF);
当访问未初始化的变量时,此选项将会发出警告。测试 6 包含三个子测试,代码如下:
void Test6(int value) { int uninitialized; int var; switch (value) { case 3: uninitialized = 4; case 2: var = 5 * uninitialized; break; case 1: int *var2; var2= &uninitialized; var = 5 * uninitialized; break; } }
(请注意,执行 case 3 中的语句后,程序将直接转到 case 2 中执行。)使用以下命令编译此代码:
cl /Od /MLd /ZI /EHsc /RTCu GS-RTC.cpp
运行 gs-rtc 6 2 时,系统将显示以下对话框:
运行 gs-rtc 6 3 时,系统将不显示对话框,因为变量已被初始化。"但是,即使使用了未初始化的变量,gs-rtc 6 1 也不会出现错误,因为编译器不跟踪可以通过指针来初始化的变量。
查看本文来源如果您非常迫切的想了解IT领域最新产品与技术信息,那么订阅至顶网技术邮件将是您的最佳途径之一。
现场直击|2021世界人工智能大会
直击5G创新地带,就在2021MWC上海
5G已至 转型当时——服务提供商如何把握转型的绝佳时机
寻找自己的Flag
华为开发者大会2020(Cloud)- 科技行者