0

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

我希望我有一种通过修改 CRT 内存初始化的行为来清除此类错误的系统方法。我很清楚 MS 调试 CRT幻数- 至少我希望有一个触发器将 0xCDCDCDCD(初始化新分配的内存的模式)设置为零。我怀疑即使在调试版本中,也可以通过这种方式轻松消除讨厌的初始化害虫。

我是否缺少启用此功能的可用 CRT 挂钩(API、注册表项等)?有人有其他想法可以到达那里吗?

[编辑:]似乎需要澄清。

  1. 通常的幻数确实有很多优点,但它们不提供布尔初始化(始终为真)或针对单个位掩码测试的位字段或类似情况的覆盖范围。一致的零初始化(当然,我可以打开和关闭),将添加一层测试,可以显示不良的初始化行为,否则可能很少见。
  2. 我当然知道CrtSetAllocHook。这样设置的钩子不会接收到分配缓冲区的指针(在分配缓冲区之前调用它),所以它不能覆盖它。重载全局 new 也没有多大好处,因为它会覆盖任何有效的构造函数初始化。

[编辑:] @Michael,不确定覆盖 new 是什么意思。简单的代码,如 -

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

行不通。粘贴和修改整个 ::new 代码可能会起作用,但看起来有点吓人(上帝只知道我必须#include 和链接才能让它运行)。

4

3 回答 3

3

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

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

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

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

话虽如此,MSVC 提供了许多调试钩子/API,您可以使用它们来执行您想要的操作:

针对您更新的问题的一些附加信息:

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

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

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

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

int main(  )
{
    unsigned int x;
    volatile bool a = false;

    if (a) {
        x = 0;
    }

    printf( "Hello world %u\n", x); // VS2010 will break here because x is uninitialized

    return 0;
}

甚至 VC++ 2010 的 Express 版本也支持这一点。

于 2010-05-04T22:24:41.087 回答
1

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

于 2010-05-05T04:46:39.923 回答
1

进入 CRT 显示在 _heap_alloc_dbg 和 realloc_help 中使用了幻数,并且值本身被编码为

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

知道要搜索什么通常会有所帮助。链接的线程确实有一个很好的建议:在 _bCleanLandFill 上设置一个监视并从调试器中修改它。

它确实有效,但我会暂时保留这个问题 - 我仍然希望有人有更好的主意......我希望通过受控初始化运行自动化测试,而不必手动进行(并且只能使用调试器可用)。

于 2010-05-05T05:48:18.220 回答