调试与发布可执行文件有何不同?

Posted

技术标签:

【中文标题】调试与发布可执行文件有何不同?【英文标题】:How does debug differ from release executable? 【发布时间】:2014-05-04 17:53:39 【问题描述】:

我在 malloc 的大小上遇到了这样的编程错误:

buffer = (char *) malloc(cbHash + 1);
assert(buffer);

代替:

buffer = (char *) malloc(cbHash * 2 + 1);
assert(buffer);

我在缓冲区中写了两次,但在调试模式下它确实运行良好,但在发布时它确实在断言中崩溃,这就是我发现我的错误的方式。我的问题是:为什么我在调试模式下没有出错?

【问题讨论】:

您想使用内存泄漏检测器。在 Linux 上,我知道valgrind,据传此类工具在 Windows 上存在(作为专有工具,可能称为 Purify)。 【参考方案1】:

因为您仍在应用程序的内存空间中写入。在分配的内存之外写入也会导致未定义的行为,不一定是崩溃。在应用程序的内存之外写入会导致崩溃,因为系统看到应用程序违反了其他程序的内存并发出了违反访问错误。但是,如果你停留在应用程序的内存中,系统就什么也说不出来,程序就会进入 UB 状态。

这是一个简短的基本解释。还有一点。如果您有兴趣,我建议您查看地址空间和内存访问权限。

此外,调试模式通常没有任何优化,并且包含调试符号,而不是发布版本。它们可能包含符号,但通常不包含。

只有当malloc 因某种原因失败时,断言才会失败。

【讨论】:

【参考方案2】:

MSVC 调试和发布主要有三种不同

发布使用优化器而调试不使用 Debug 在目标文件中包含符号调试信息,而 release 不包含 运行时库不同。

运行时库的一个不同之处在于 malloc 的实现方式。调试 malloc 在对象的两侧分配额外的内存并将额外的内存设置为位模式。当你释放内存时,如果额外的位被改变了,那么你的程序有一个内存覆盖错误,它会告诉你。

【讨论】:

【参考方案3】:

调试堆分配的内存比请求的多,并用特殊签名填充缓冲区前后的“NoMansLand”区域。这样做是为了检测缓冲区溢出。释放内存后,调试版本会检查签名并在签名发生更改时打印错误。

内存块本身也使用特殊值初始化,例如 msvcpp 0xcccccccc。在发布版本中,内存保持原样,并且可以包含任何值。这是为了尝试检测未能初始化内存的编码错误。也许这可能是调试版本运行而发布版本崩溃的原因:如果 0x00000000 对程序不利,它不会在调试版本中崩溃,但可能会在发布版本中崩溃。

【讨论】:

以上是关于调试与发布可执行文件有何不同?的主要内容,如果未能解决你的问题,请参考以下文章

逆向调试入门-了解PE结构文件

无法解决错误:可执行文件在 xcode 4.2 中使用无效的调试权利签名

调试选项 -g 如何更改二进制可执行文件?

由于调试符号,巨大的可执行文件,为啥?

我的 .net 核心发布的可执行文件提供了与运行代码时不同的目录路径

关于 Windows 中带有调试信息的可执行文件