GDB可以防止错误 [英] GDB prevents errors

查看:104
本文介绍了GDB可以防止错误的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

使用 gdb 时,我在不同的C项目中遇到了这个问题。
如果我在没有它的情况下运行我的程序,它可能会在给定的事件中一直崩溃,可能是因为无法读取内存。我尝试使用 gdb 进行调试,但是当我这样做时,崩溃似乎永远不会发生!



这可能发生?

我在Windows上使用 mingw toolchain。

解决方案

是的,这听起来像是一种竞争条件或堆腐败或其他通常是造成Heisenbugs负责的事情。问题在于你的代码在某些地方可能不正确,但即使被调试的应用程序做了有趣的事情,调试器也必须运行。这样调试器下的问题就会消失。而对于竞态条件,它们通常不会出现在第一位,因为一些调试器一次只能处理一个线程,统一的所有调试器都会导致代码运行速度变慢,这可能已经导致竞争条件消失。



在应用程序上尝试 Valgrind 。由于您使用的是MinGW,因此您的应用程序可能会在Valgrind可以运行的环境下编译(即使它不直接在Windows上运行)。我已经使用了Valgrind大约三年了,它已经很快解决了很多谜团。当我得到关于我正在使用的代码(在AIX,Solaris,BSD,Linux,Windows上运行)的崩溃报告时,我首先要对x64和x86 Linux中的Valgrind下的代码进行一次测试运行分别。

Valgrind,在你的特定情况下,它的默认工具Memcheck将通过代码模拟。无论何时你分配内存,它都会将该内存中的所有字节标记为被感染,直到你明确地初始化它为止。内存字节的受污染状态将被 memcpy -ing未初始化的内存继承,并且一旦使用未初始化的字节做出决定,将导致来自Valgrind的报告( if for while ...)。此外,它会跟踪孤立的内存块,并在运行结束时报告泄漏。但这还不是全部,更多的工具是Valgrind系列的一部分,它测试代码的各个方面,包括线程之间的竞争条件(Helgrind,DRD)。现在假设Linux :确保安装了支持库的所有调试符号。通常来自 * - debug 版本的软件包或 * - devel 。另外,请确保关闭代码中的优化并包含调试符号。对于GCC,这是 -ggdb -g3 -O0



另一个提示:我已经知道指针别名有引起了一些悲伤。尽管Valgrind能够帮助我追踪它,但实际上我必须做最后一步并在反汇编中验证创建的代码。事实证明,在 -O3 GCC优化器领先于它本身,并将一个循环复制字节转换为一系列指令,以立即复制8个字节,但假设 对齐。最后一部分是问题。关于对齐的假设是错误的。从那以后,我们采取了在 -O2 的基础上建设 - 正如你将在这篇Gentoo Wiki文章并不是最糟糕的主意。引用相关部分:


<-O>:这是可能达到的最高级别的优化,也是风险最高的。用这个
选项编译你的代码需要更长的时间,事实上它不应该用gcc 4.x来在系统范围内使用。
自3.x版以来,gcc的行为发生了显着变化。在
3.x中,-O3已经显示比-O2更快的执行速度,但gcc 4.x不再是这种情况。使用-O3编译所有
包,将导致需要
多内存的较大二进制文件,并且会显着增加编译
失败或意外程序行为(包括错误)的几率。
的缺点大于好处;请记住减去
回报的原则。使用-O3不推荐用于gcc 4.x。


由于您在MinGW中使用GCC,我认为这很适用于你的情况也是如此。


I got this problem on different C projects when using gdb. If I run my program without it, it crashes consistently at a given event probably because of a invalid read of the memory. I try debugging it with gdb but when I do so, the crash seems to never occur !

Any idea why this could happen ?

I'm using mingw toolchain on Windows.

解决方案

Yes, it sounds like a race condition or heap corruption or something else that is usually responsible for Heisenbugs. The problem is that your code is likely not correct at some place, but that the debugger will have to behave even if the debugged application does funny things. This way problems tend to disappear under the debugger. And for race conditions they often won't appear in the first place because some debuggers can only handle one thread at a time and uniformly all debuggers will cause the code to run slower, which may already make race conditions go away.

Try Valgrind on the application. Since you are using MinGW, chances are that your application will compile in an environment where Valgrind can run (even though it doesn't run directly on Windows). I've been using Valgrind for about three years now and it has solved a lot of mysteries quickly. The first thing when I get a crash report on the code I'm working with (which runs on AIX, Solaris, BSDs, Linux, Windows) I'm going to make one test run of the code under Valgrind in x64 and x86 Linux respectively.

Valgrind, and in your particular case its default tool Memcheck, is going to emulate through the code. Whenever you allocate memory it will mark all bytes in that memory as "tainted" until you actually initialize it explicitly. The tainted status of memory bytes will get inherited by memcpy-ing uninitialized memory and will lead to a report from Valgrind as soon as an uninitialized byte is used to make a decision (if, for, while ...). Also, it keeps track of orphaned memory blocks and will report leaks at the end of the run. But that's not all, more tools are part of the Valgrind family and test various aspects of your code, including race conditions between threads (Helgrind, DRD).

Assuming Linux now: make sure that you have all the debug symbols of your supporting libraries installed. Usually those come in the *-debug version of packages or in *-devel. Also, make sure to turn off optimization in your code and include debug symbols. For GCC that's -ggdb -g3 -O0.

Another hint: I've had it that pointer aliasing has caused some grief. Although Valgrind was able to help me track it down, I actually had to do the last step and verify the created code in its disassembly. It turned out that at -O3 the GCC optimizer got ahead of itself and turned a loop copying bytes into a sequence of instructions to copy 8 bytes at once, but assumed alignment. The last part was the problem. The assumption about alignment was wrong. Ever since, we've resorted to building at -O2 - which, as you will see in this Gentoo Wiki article, is not the worst idea. To quote the relevant partÖ

-O3: This is the highest level of optimization possible, and also the riskiest. It will take a longer time to compile your code with this option, and in fact it should not be used system-wide with gcc 4.x. The behavior of gcc has changed significantly since version 3.x. In 3.x, -O3 has been shown to lead to marginally faster execution times over -O2, but this is no longer the case with gcc 4.x. Compiling all your packages with -O3 will result in larger binaries that require more memory, and will significantly increase the odds of compilation failure or unexpected program behavior (including errors). The downsides outweigh the benefits; remember the principle of diminishing returns. Using -O3 is not recommended for gcc 4.x.

Since you are using GCC in MinGW, I reckon this could well apply to your case as well.

这篇关于GDB可以防止错误的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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