C ++ Builder 2010奇怪的访问冲突 [英] C++ Builder 2010 Strange Access Violations

查看:104
本文介绍了C ++ Builder 2010奇怪的访问冲突的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个程序要成为使用C ++ Builder 2010构建的现有较大产品的一部分。

I've got a program that is to become part of an already existing, larger product which is built using C++ Builder 2010.

较小的程序不会(但是)取决于C ++ Builder。在MS Visual Studio中它可以正常工作,但是在C ++ Builder中,它会产生奇怪的访问冲突。

The smaller program does not (yet) depend on C++ Builder. It works fine in MS Visual Studio, but with C++ Builder it produces strange access violations.

请让我解释一下。

取决于代码和编译器设置,是否发生访问冲突。访问冲突是可重现的:构建程序时,访问冲突永远不会发生,或者总是在同一位置发生。如果使用相同的设置重建程序,它将显示相同的行为。 (我对此感到非常高兴。)

Depending on the code and on compiler settings, access violations happen or do not happen. The access violations are reproducible: When the program is built then the access violation does never occur or it does always occur at the same place. If the program is rebuilt with the same settings, it will show the same behavior. (I'm really glad about that).

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

The access violation happens at places where the delete operator is called. This can happen (depending on compiler settings and exact code) inside certain destructors, including destructors of own classes and inside the destructor of std::string.


  • 使用调试设置(而不是发布)进行构建。

  • 没有编译器优化。

  • 编译器开关慢速例外结尾。

  • 静态RTL而非动态。

  • 从std :: exception派生异常,而不是Borland的Exception类。

  • 使用较少的复杂表达式(例如,使用 string s = ... +.。 。; throw SomeException(s);而不是 throw
    SomeException(string( ...)+ ...);)

  • 使用尝试... __最终使用手动清除,而不是使用析构函数的自动变量。

  • 使用小型控制台应用程序代替VCL Windows应用程序。

  • Build with "Debug" settings (instead of "Release").
  • No compiler optimizations.
  • Compiler switch "Slow exception epilogues".
  • Static RTL instead of dynamic.
  • Derive exceptions from std::exception instead of Borland's Exception class.
  • Use less "complicated" expressions (e.g. use "string s = "..." + "..."; throw SomeException(s);" instead of "throw SomeException(string("...") + "...");")
  • Use try... __finally with manual cleanup instead of automatic variables with destructors.
  • Use a small console application instead a VCL windows application.

该程序利用了几种C ++功能,

The program makes use of several C++ features, including exceptions, STL, move constructors etc. and it of course uses the heap.

我已经尝试了一些工具,但没有一个报告问题:

I already tried some tools, none of them reported problems:


  • Borland的CodeGuard。

  • Microsoft应用程序验证器。

  • pageheap / gflags。

  • 如前所述,使用MS Visual Studio进行构建绝对没有问题。

  • Borland's CodeGuard.
  • Microsoft Application Verifyer.
  • pageheap/gflags.
  • As already mentioned, there is absolutely no problem when building with MS Visual Studio.

使用

C ++ Builder编译器(启用所有警告)和一个都不会被禁用。 Visual Studio(/ W4)发出的警告可能与此问题有关。

Neither the C++ Builder compiler ("enable all warnings") nor the one of Visual Studio (/W4) produces a warning that might be related to this issue.

我无权访问其他版本的C ++ Builder。

I do not have access to another version of C++ Builder.

由于该程序将成为更大产品的一部分,因此,切换到其他编译器不是一种选择,并且在访问冲突没有发生之前,也不能调整编译器设置。不再发生。 (我担心这是否真的应该是编译器错误,该错误可能会再次出现。)

As the program will become part of a larger product, it is not an option to switch to a different compiler, and it is not an option to tune the compiler settings until the access violation does no longer happen. (I fear if this really should a compiler bug, the bug might show up again.)

将其放在一起,我猜想这可能是由于堆损坏导致的。与某些编译器错误有关。但是,我在qc.embarcadero.com上找不到错误。我进一步猜测这与清理代码有关,清理代码是在引发异常时在堆栈倒带时执行的。但是,也许这只是一个愚蠢的代码错误。

Putting this together, I'm guessing this might result from heap corruption that is related to some compiler bug. However, I was not able to find a bug on qc.embarcadero.com. I'm guessing further this is related to cleanup code that is executed upon stack rewinding when an exception has been thrown. But, well, maybe it's only a stupid code bug.

目前,我不知道如何进行。任何帮助表示赞赏。预先谢谢您!

Currently, I do not have any idea how to proceed. Any help appreciated. Thank you in advance!

推荐答案

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

tl;dr I believe the bug is that code is generated to delete the std::string from both branches of the ternary operator during stack unwinding, however only one of them was actually created of course.

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

Here is a simpler MCVE, which shows the problem via outputs in 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;
}

此版本通过控制台上的输出字符串显示问题。检查此帖子的编辑历史记录,以查看使用 std :: string 的版本并导致段错误的情况。

This version shows the problem via output strings on the console. Check the edit history for this post to see a version that uses std::string and causes the segfault instead.

我的输出是:

 Create: 0018FF38
Destroy: 0018FF2C
Destroy: 0018FF38

在原始代码中,segfault来自伪造的Destroy,最终调用了 delete 通过尝试获取 std :: string 的内部数据指针而获得的虚假值,该指针实际上从未在该位置创建。

In the original code, the segfault comes from the bogus Destroy ending up calling delete on the bogus value it obtains by trying to retrieve the internal data pointer for a std::string which was actually never created at that location.

我的猜测是堆栈展开的代码生成有问题,并试图从三元运算符的两个分支中删除临时字符串。临时 UnicodeString 的存在确实与它有关。

My conjecture is that the code generation for stack unwinding is bugged and tries to delete the temporary string from both branches of the ternary operator. The presence of the temporary UnicodeString does have something to do with it; as the bug did not occur in any variations where I tried to avoid that temporary.

在调试器中,您可以看到调用堆栈,而这是在全局堆栈展开期间发现的发生。

In the debugger you can see the call stack and it is during global stack unwinding that this happens.

这篇关于C ++ Builder 2010奇怪的访问冲突的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆