控制CRT内存初始化

时间:2010-05-04 21:56:08

标签: visual-c++ memory-management msvcrt

偶尔您会遇到只能在发布版本中和/或仅在某些计算机上可重现的错误。一个常见的(但绝不是唯一的)原因是未初始化的变量,它们受随机行为的影响。例如,在大多数机器上,未初始化的BOOL大部分时间都可以为TRUE,但随机初始化为FALSE。

我希望我能通过修改CRT内存初始化的行为来系统地清除这些错误。我很清楚MS调试CRT magic numbers - 至少我想要一个触发器将0xCDCDCDCD(初始化新分配的内存的模式)转为零。我怀疑一个人能够轻易地抽出令人讨厌的东西 即使在调试版本中,初始化也会以这种方式进行害虫攻击。

我是否错过了启用此功能的可用CRT挂钩(API,注册表项等)?任何人都有其他想法到达那里?

[编辑:] 似乎有必要进行澄清。

  1. 通常的幻数确实有许多优点,但它们不提供bool初始化(总是为真)的覆盖,或针对单个位掩码或类似情况测试的位字段。一致的零初始化(我当然可以打开和关闭),会添加一层测试,可以表现出错误的初始化行为,否则很少见。
  2. 我当然知道CrtSetAllocHook。这样设置的钩子没有收到指向分配缓冲区的指针(在这样的缓冲区被分配之前称为),所以它不能覆盖它。重载全局new也不会有太大的好处,因为它会覆盖任何有效的构造函数初始化。
  3. [编辑:] @Michael,不确定覆盖新内容是什么意思。简单的代码,如 -

    void* new(...)
    {
       void* res = ::new(...);   // constructors now called!
       if(SomeExternalConditionApplies())
          OverWriteBufferWithMyPetValues(res);
    }
    

    无效。粘贴和修改整个::新代码可能会有效,但看起来有点可怕(上帝只知道我需要#include和链接以使其运行)。

3 个答案:

答案 0 :(得分:3)

我没有关注 - 将未初始化的内存设置为类似0xcdcdcdcd而不是0 更好来清除错误,因为代码更有可能获得'范围'算术或特别处理0.由于值非常无效,错误更有可能“快速失败”,因此可以修复而不是隐藏。

MSVC的调试版本使用的值专门用于帮助导致可以轻松检测到的错误:

  • 它们不是0,因此对未初始化的内存进行NULL指针检查不会隐藏错误
  • 它们不是有效的指针,因此取消引用未初始化的指针会导致访问冲突
  • 它们不是'通常'的整数值,因此涉及未初始化数据的计算通常会导致非常不正确的结果,这些结果往往会导致明显的失败(我认为当处理签名数据时也是负面的,但这对此有所帮助,但不仅仅是不寻常的数字)。

此外,它们在调试器中的数据显示中很容易识别。 Zero几乎没有那么突出。

所有这一切,MSVC提供了许多调试钩子/ API,您可以使用它们来执行您想要的任务:

针对您更新的问题的一些其他信息:

您可以使用像Dmalloc(http://dmalloc.com/)这样的第三方调试分配库,但老实说,我不知道这些库可以轻松地集成到MSVC项目中,尤其是“真实世界”项目。

另外,请注意,这些显然只会处理动态分配(并且可能无法与MSVC的默认new实现很好地集成)。

可以使用operator new()的全局覆盖来处理在C ++中使用new发生的分配 - 覆盖任何有效的构造函数初始化没有问题 - { {1}}分配在构造函数执行任何初始化之前发生(如果你想一下它应该清楚为什么会这样)。

此外,您可能需要考虑迁移到Visual Studio 2010 - 当您使用未初始化的局部变量时,它将进入调试器 - 除了在调试器下运行Debug构建之外,什么都不做。当然,MSCV已经对这些情况中的许多情况进行了一段时间的警告,但VS2010将在调试器中捕获以下内容,这不会产生任何警告(至少使用我当前的编译器设置):

new

即使是VC ++ 2010的Express版本也支持这一点。

答案 1 :(得分:1)

只是一个建议:您可以在编译器中使用静态代码分析工具吗? / analyze会给你一个C6001警告你正在使用未初始化的内存。它有点系统化,这就是你的要求。

答案 2 :(得分:1)

单步进入CRT会显示_heap_alloc_dbg和realloc_help中使用的幻数,并且值本身编码为

static unsigned char _bCleanLandFill  = 0xCD;   /* fill new objects with this */

知道搜索often helps的内容。链接的线程确实有一个很好的建议:在_bCleanLandFill上设置一个监视并从调试器修改它。

它确实有效,但我会暂时保持这个问题 - 我仍然希望有人有更好的想法...我希望能够通过受控初始化来运行自动化测试,而不必手动完成(和只有调试器可用)。