C++builder C++;Builder 2010奇怪的访问违规 我有一个程序,它是一个已经存在的,更大的产品的一部分,它是用C++ Builder 2010构建的。 较小的程序不依赖于C++ Builder。它在MS VisualStudio中运行良好,但是使用C++ Builder会产生奇怪的访问违规。

C++builder C++;Builder 2010奇怪的访问违规 我有一个程序,它是一个已经存在的,更大的产品的一部分,它是用C++ Builder 2010构建的。 较小的程序不依赖于C++ Builder。它在MS VisualStudio中运行良好,但是使用C++ Builder会产生奇怪的访问违规。,c++builder,c++builder-2010,C++builder,C++builder 2010,请让我解释一下 根据代码和编译器设置,会发生或不会发生访问冲突。访问冲突是可复制的:当程序构建时,访问冲突永远不会发生,或者总是发生在同一个地方。如果使用相同的设置重建程序,它将显示相同的行为。(我真的很高兴) 访问冲突发生在调用delete运算符的位置。这可能发生在某些析构函数内部(取决于编译器设置和确切的代码),包括自己类的析构函数和std::string的析构函数内部 以下事项降低了访问冲突的可能性: 使用“调试”设置生成(而不是“发布”) 没有编译器优化 编译器开关“慢速异常结束语”

请让我解释一下

根据代码和编译器设置,会发生或不会发生访问冲突。访问冲突是可复制的:当程序构建时,访问冲突永远不会发生,或者总是发生在同一个地方。如果使用相同的设置重建程序,它将显示相同的行为。(我真的很高兴)

访问冲突发生在调用delete运算符的位置。这可能发生在某些析构函数内部(取决于编译器设置和确切的代码),包括自己类的析构函数和std::string的析构函数内部

以下事项降低了访问冲突的可能性:

  • 使用“调试”设置生成(而不是“发布”)
  • 没有编译器优化
  • 编译器开关“慢速异常结束语”
  • 静态RTL而不是动态RTL
  • 从std::exception而不是Borland的exception类派生异常
  • 使用不太“复杂”的表达式(例如,使用“string s=”…“+”…;throw SomeException;而不是“throw SomeException(字符串(“…”+“…”;”)
  • 使用try__最后使用手动清理,而不是使用析构函数的自动变量
  • 使用小型控制台应用程序代替VCL windows应用程序

程序使用了几个C++的特性,包括异常、STL、移动构造函数等,当然它使用堆。 我已经尝试了一些工具,但没有一个报告出现问题:

  • 伯兰的密码守卫
  • 微软应用程序验证
  • 页面堆/gflags
  • 如前所述,使用MS Visual Studio构建时绝对没有问题
禁用了使用预编译头和增量链接(在我看来,这两种链接都容易出错)

< C++ > Builder编译器(“启用所有警告”)和VisualStudio(/W4)都不会产生与此问题相关的警告。

我没有访问另一个版本的C++ Builder。< /P> 由于该程序将成为更大产品的一部分,因此不能选择切换到其他编译器,也不能选择在访问冲突不再发生之前调整编译器设置。(我担心如果这真的是一个编译器错误,那么这个错误可能会再次出现。)

综上所述,我猜这可能是由于与某些编译器错误相关的堆损坏造成的。但是,我在qc.embarcadero.com上找不到bug。我进一步猜测,这与抛出异常时在堆栈倒带时执行的清理代码有关。但是,也许这只是一个愚蠢的代码错误


目前,我不知道如何进行。谢谢你的帮助。提前谢谢你

这太简单了,我花了一些时间:

#include <vcl.h>
#include <tchar.h>
#include <string>
using namespace std;

struct B
{
   B(const char* c) { }
   string X() const { return "xx"; }
   int Length() const { return 2; }
};

struct C
{
   void ViolateAccess(const B& r)
   {
      try
      {
         throw Exception(string("aoei").c_str());
      }
      catch (const Exception&) { }

      throw Exception(((string) "a" + (r.Length() < 10 ? r.X() : r.X() + "...") + "b").c_str());
   }
};

#pragma argsused
int _tmain(int argc, _TCHAR* argv[])
{
   try
   {
      C c;
      c.ViolateAccess("11");
   }
   catch (const Exception& e) { }
   return 0;
}
#包括
#包括
#包括
使用名称空间std;
结构B
{
B(const char*c){}
字符串X()常量{返回“xx”;}
int Length()常量{return 2;}
};
结构C
{
无效违规通行证(康斯特B&r)
{
尝试
{
抛出异常(字符串(“aoei”).c_str();
}
捕获(常量异常&){}
抛出异常(((string)“a”+(r.Length()<10?r.X():r.X()+“…”)+“b”).c_str();
}
};
#布拉格语
int _tmain(int argc,_TCHAR*argv[]
{
尝试
{
C C;
c、 ViolateAccess(“11”);
}
捕获(常量异常&e){}
返回0;
}
(先发制人的评论:不,这段代码没有任何意义。)

创建一个新的控制台应用程序,并确保使用VCL。这可能取决于项目设置是否存在访问冲突;我的调试版本总是崩溃,发布版本却没有

用C++ Builder 2010和XE3试用。


因此,编译器、VCL、STL或任何东西中都存在bug。

tl;dr我相信错误在于生成代码是为了在堆栈展开期间从三元运算符的两个分支中删除
std::string
,但是实际上只创建了其中一个


下面是一个更简单的MCVE,它通过XE5中的输出显示问题:

#include <vcl.h>
#include <tchar.h>
#include <stdio.h>
using namespace std;

struct S
{
    S() { printf("Create: %p\n", this); }
    S(S const &) { printf("Copy: %p\n", this); }
    void operator=(S const &) { printf("Assign: %p\n", this); }
    ~S() { printf("Destroy: %p\n", this); }

    char const *c_str() { return "xx"; }
};

S rX() { return S(); }
int foo() { return 2; }

#pragma argsused
int _tmain(int argc, _TCHAR* argv[])
{
   try
   {
      throw Exception( (foo() ? rX() : rX()).c_str() );
   }
   catch (const Exception& e)
   {
   }

   getchar();
   return 0;
}
在原始代码中,segfault来自伪Destroy,它通过尝试检索实际上从未在该位置创建的
std::string
的内部数据指针,对伪值调用
delete

我的猜测是,堆栈展开的代码生成出现错误,并试图从三元运算符的两个分支中删除临时字符串。临时的破坏的存在确实与此有关;因为这个bug没有出现在我试图避免的任何变体中


在调试器中,您可以看到调用堆栈,并且在全局堆栈展开过程中会发生这种情况。

能否显示一个示例应用程序来演示这些问题?我们可以建造一些东西。还没有,我正在做这个。但我想,当我有一个小样本应用程序时,我可能已经知道问题出在哪里了。请在您知道问题出在哪里时填写我们。我每天都在C++ Builder中工作,以及Visual C++,我没有看到这个问题。(我有两条编译代码,我编译了20000行代码)。@格奥尔:我用C++ Builder已经好几年了,因为它一直在用奇怪的bug来烦我(类似于这个bug,但没有这么奇怪)。我下定决心,我开始相信C++ Builder不是C++编译器,而是一个用C语法编写的Delphi编译器。德尔菲特性与C++ BUI
 Create: 0018FF38
Destroy: 0018FF2C
Destroy: 0018FF38