3

I found that trying to debug accidentally uninitialized data in gdb can be annoying. The program will crash when directly executed from the command line, but not while under inspection in gdb. It seems like gdb's heap is often clean (all zeroes), whereas from the command line, clearly not.

Is there a reason for this? If so, can I deliberately tell gdb or gcc to dirty the heap? IE, is there way to specify a "debug" allocator that will always give random data to malloc() and new? I imagine this might involve a special libc? Obviously if there was a way to do this without changing the linker options would be great so that the release version is as similar as possible to the debug version.

I'm currently using MinGW-w64 (gcc 4.7 based), but I'd be interested in a general answer.

Peter M
  • 1,918
  • 16
  • 24
  • valgrind is a painless way to find uninitialised data – kfmfe04 Mar 18 '13 at 16:24
  • @kfmfe04: Trouble with valgrind is getting it to run under Windows (OP is using MinGW-w64). Of course it's possible to use it under Linux with the program running under Wine, but it's not precisely user-friendly or straightforward. – Damon Mar 18 '13 at 17:05
  • @Damon well, I admit that MinGW is kind of ... how do I say this... ugly stepchild of the gcc family, so suggesting valgrind is totally cool (I was able to easily recompile and test on a Linux VM), in any case it points to the type of tool that is used to solve this problem. – Peter M Mar 19 '13 at 15:22
  • If your code is portable enough that you can run and debug on Linux, I'd recommend doing that. Valgrind etc are really quite fantastic. I imagine that there are Windows alternatives (see the link in my answer) but I don't have any experience with them. – robbie_c Mar 19 '13 at 18:09

2 Answers2

1

The Linux way of doing this would be to use valgrind. On Mac OS X there are environment variables that control allocation debugging, see the Mac OS X man page for malloc. Valgrind support for Mac OS X is starting to appear but 10.8 support is not complete as of me writing this.

As you're using MinGW-w64 I am assuming you're using Windows. It seems like this SO question talks about alternatives to valgrind on Windows. One solution would be to run your app in Wine on a Linux box under valgrind.

If your program is running under valgrind, it is not directly running on a CPU. Valgrind is simulating every instruction, hence you can't simply attach a debugger to it. To get this to work you need to use the valgrind GDB server, see this page for more details.

Another approach would be to use calloc instead of malloc, which would zero your heap allocations. This doesn't give you a deliberately dirty heap but at least gives you consistent behaviour with or without a debugger.

Community
  • 1
  • 1
robbie_c
  • 2,428
  • 1
  • 19
  • 28
  • Using `calloc` will only give you consistent behavior on *heap*. Uninitialized stack values will still be "random". – Employed Russian Mar 19 '13 at 03:07
  • 1
    The question asked about a deliberately dirty heap. – robbie_c Mar 19 '13 at 10:45
  • 1
    "... asked about a deliberately dirty heap." -- and your solution achieved the opposite of what's been asked. – Employed Russian Mar 19 '13 at 14:04
  • Obviously if you know where the issue with initialization is, then you can solve it by... initializing it, which is what calloc does. But your comment about valgrind is great. In fact, valgrind can dirty your heap for you! Wouldn't it be great if gdb and valgrind merged in an elegant way?! – Peter M Mar 19 '13 at 15:27
  • @EmployedRussian updated my answer to better explain what calloc actually does for you. – robbie_c Mar 19 '13 at 17:52
  • @PeterM updated my answer with some info about debugging a program under valgrind. I have never tried this via Wine so please let me know if it works out :) – robbie_c Mar 19 '13 at 17:53
0

Yes, GDB zeroes out everything, this is both useful and very annoying. Useful, insofar as everything is guaranteed to be in a well-defined state (no random values in memory, just zero). Which means, in theory, no nasty surprises while debugging.
In practice, and this is where it gets annoying, the theory sometimes fails spectacularly. The infamous "works fine, but crashes in debugger!?!" or "works fine in debugger, but crashes otherwise?!" issues are an example of this. Usually, this is a combination of an uninitialized pointer with a well-intended if(ptr != NULL) somewhere, which totally blows up for "no good reason" because the debugger initializes memory to zero, so the test fails to do what you intended.

About your question on deliberately garbling data allocated by malloc, GCC supports malloc hooks (see docs here and question here on SO).

This lets you, in a very easy and unintrusive manner, redirect all calls to malloc to a function of your own. From there you can call the real malloc and fill the allocated block with garbage (or some invalid-pointer magic value like DEADBEEF), if you wish to do so.

As for operator new, this happens to be a wrapper around malloc (that's an implementation detail, but malloc hooks are non-portable already, so relying on that won't make things worse), therefore malloc hooking should already deal with this, too.

Community
  • 1
  • 1
Damon
  • 67,688
  • 20
  • 135
  • 185
  • "Yes, GDB zeroes out everything". No, it does *not*. Show us the code in GDB that performs this zero-ing, if you still believe it. – Employed Russian Mar 19 '13 at 03:06
  • @EmployedRussian: No. Please feel free to dig through the sources for yourself. I'm not going to waste hours only to prove a point that is well-known and that every programmer who has used GDB has observed a million times, sorry. Even if GDB didn't do this, it would be irrelevant, since the OP experiences this (for whatever reason) and wants to initialize allocated memory with "garbage". – Damon Mar 19 '13 at 12:46
  • Claiming that something is well-known doesn't make it so. You are committing "burden of proof" logical fallacy: https://yourlogicalfallacyis.com/pdf/LogicalFallaciesInfographic_A3.pdf – Employed Russian Mar 19 '13 at 14:22
  • You don't get it, do you? I'm not interested in proving something to you _that is entirely irrelevant to what the OP wants_. You are arguing for the sake of arguing. The OP observes an effect that is well-known, and wants to work around it. It doesn't matter what you want proof for. – Damon Mar 19 '13 at 14:27
  • You don't get, do you? You are claiming something that is false, and as a proof offer that this is a "well known" fact. The OP *does* need to understand in what ways execution under GDB differs from execution outside of it, but "GDB zeroes out everything" is not one of these differences. – Employed Russian Mar 19 '13 at 14:50
  • @EmployedRussian Well, sadly to say sometimes its tricky to show things or prove them (especially if they involve thousands of lines of code) and you have to rely on well known behavioral observations. That's just pragmatism. Even when there is a standard or documentation, you can find that some people don't follow it, but that doesn't mean you should ignore the documentation. It's good to be skeptical, but if you are too skeptical you'll never get any work done! – Peter M Mar 19 '13 at 15:38
  • @EmployedRussian: The way I see this pointless discussion is: Person A says: "I have this problem, whenever I drop my stuff, it falls on the floor, I don't want that to happen. I just observed it." Person B says: "Yeah, things do drop to the floor if you let them go, that just happens, everybody had that problem before. Put your stuff on a table, so it won't land on the floor". Enter Person C: "Things don't fall on the floor. Prove to me that they do by doing a molecular floor analysis. You're totally wrong in everything you say". It just doesn't lead anywhere... – Damon Mar 19 '13 at 15:41
  • Even if Person C is right and things do not fall to the floor, Person A's stuff still is observably on the floor, and he doesn't want that. Putting things on a table will address his issue. Discussing the properties of the floor does not. – Damon Mar 19 '13 at 15:43
  • In particular, obviously you should never rely on any particular behavior for uninitialized segments, so really I think that Damon's comment that gdb often gets a clean memory space is useful. It's a good thing to keep in mind when you see different behavior under the debugger, and as a rule of thumb, is helpful. – Peter M Mar 19 '13 at 15:52
  • @Damon, maybe you can edit your post to reflect this uncertainty and that it's just a good rule of thumb (if you want to add a comment about valgrind that might be helpful) and I'd mark it "done"? – Peter M Mar 19 '13 at 15:55