Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/visual-studio-2012/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ VS2012中sqrt内在的堆栈运行时检查失败_C++_Visual Studio 2012 - Fatal编程技术网

C++ VS2012中sqrt内在的堆栈运行时检查失败

C++ VS2012中sqrt内在的堆栈运行时检查失败,c++,visual-studio-2012,C++,Visual Studio 2012,在调试一些崩溃时,我遇到了一些代码,这些代码简化为以下情况: #include <cmath> #pragma intrinsic (sqrt) class MyClass { public: MyClass() { m[0] = 0; } double& x() { return m[0]; } private: double m[1]; }; void function() { MyClass obj; obj.x() = -sqrt(2.0);

在调试一些崩溃时,我遇到了一些代码,这些代码简化为以下情况:

#include <cmath>
#pragma intrinsic (sqrt) 

class MyClass
{
public:
  MyClass() { m[0] = 0; }
  double& x() { return m[0]; }
private:
  double m[1];
};
void function()
{
  MyClass obj;
  obj.x() = -sqrt(2.0);
}

int main()
{
  function();
  return 0;
}
这实际上使
obj
在8字节边界上对齐。具体地说,每当以
ESP
的初始值调用函数,该值以
0
8
半字节结束时,
obj
将从相对于
ESP
初始值的-24字节偏移量开始存储。 问题是
\u RTC\u CheckStackVars
仍在与上述“工作版本”中所述的原始
ESP
值相同的位置(即-24和-12字节的偏移量)查找那些
0xcccc
魔法cookies。在本例中,
obj
的前4个字节实际上与一个神奇的cookie位置重叠。这显示在下面“失败版本”开头的屏幕截图中:

然后就在调用
\u RTC\u CheckStackVars
之前:

我们可以注意到,在传递过程中,对应于
obj.m[0]
的实际数据在“工作版本”和“故障版本”之间是相同的(“cd 3b 7f 66 9e a0 f6 bf”,或者当解释为
双精度
时,预期值为-1.4142135623730951)

顺便说一句,只要
ESP
的初始值以
4
C
半字节结束(
obj
开始于-20字节的偏移量,就像在“工作版本”中一样,
\u RTC\u CheckStackVars
检查实际上通过了

\u RTC\u CheckStackVars
检查完成(假设通过)后,还需要检查
ESP
的还原值是否与原始值相对应。此检查失败时,会导致“缓冲区溢出发生在…”消息

在“工作版本”中,原始的
ESP
被复制到序言(第3415行)的早期的
EBP
,该值通过与
\uuuuuuu security\uCookie
(第3425行)异或来计算校验和。在“失败版本”中,校验和计算基于
ESP
(第3425行),在推送一些寄存器(第3417-3419行)时
ESP
已减12,但对已恢复的
ESP
的相应检查是在这些寄存器已恢复的同一点进行的

因此,简而言之,除非我没有正确理解这一点,否则“工作版本”似乎遵循标准教科书和堆栈处理教程,而“失败版本”则会打乱运行时检查


备注:“调试版本”指的是“Win32 Console应用程序”新项目模板中“调试”配置的标准编译器选项集。

正如Hans在评论中指出的那样,Visual Studio 2013无法再复制该问题。 同样,官方对这一问题的回答是:

我们无法使用VS2013更新4 RTM复制它。产品团队本身不再直接接受Microsoft Visual Studio 2012及更早版本产品的反馈。通过访问以下链接中的一个资源,您可以获得对Visual Studio 2012及更早版本问题的支持:

因此,鉴于问题仅在VS2012上通过函数intrinsics(/Oi compiler option)、运行时检查(或/RTCs或/RTC1 compiler option)和一元减号运算符的使用触发,消除任何一个(或多个)这些条件都可以解决问题

因此,可用的选项似乎是:

  • 升级到最新的Visual Studio(如果项目允许)
  • 通过使用
    #pragma runtime_check
    包围受影响的函数,禁用它们的运行时检查,如以下示例中所示:
  • 通过删除
    #pragma intrinsics(sqrt)
    行并添加
    #pragma函数(sqrt)
    (有关更多信息,请参阅)来禁用内部函数。
    如果已通过“启用内部函数”项目属性(/Oi compiler选项)为所有文件激活了内部函数,则需要停用该项目属性。然后,您可以逐个启用特定函数的intrinsic,同时检查它们是否受bug影响(对于每个必需的内在函数,使用
    #pragma intrinsic
    指令)
  • 使用变通方法调整代码,例如
    0-sqrt(2.0)
    -1*sqrt(2.0)
    (删除一元减号运算符),试图欺骗编译器使用不同的代码生成路径。请注意,这很可能会因为看似很小的代码更改而中断

  • +1这听起来像是一个有很好文档记录的编译器错误。将其提交给microsoft connect。除非有人能够解释此代码可能是如何错误的,否则这就是我打算做的(只要我能够连接)。在VS2013中没有重新编程,此错误可能已修复。请记住,VS2012是一次重要的代码生成器重写的培训。我看到的一件奇怪的事情是,它使用esp访问局部变量,在VS2013中使用ebp。我不记得VS2012是这样做的,也没有安装过它来检查。如果您更改了编译器的默认设置,请务必提及。@Hans是的,我注意到了esp的问题。我尝试的所有调整都对局部变量使用ebp。为了澄清,我没有更改编译器的默认设置(这就是我所说的“调试构建”指的是标准的编译器选项集)。@Cheersandhth.-Alf最终成功连接,因此这里是问题的链接,尽管正如Hans所指出的,问题没有出现在VS2013中(至少对于我刚刚安装的Express版本)。
    and         esp,0FFFFFFF8h
    
        #pragma runtime_check ("s", off)
        void function()
        {
          MyClass obj;
          obj.x() = -sqrt(2.0);
        }
        #pragma runtime_check ("s", restore)