views:

2000

answers:

14

As everyone* knows, the Visual C++ runtime marks uninitialized or just freed memory blocks with special non-zero markers. Is there any way to disable this behavior entirely without manually setting all uninitialized memory to zeros? It's causing havoc with my valid not null checks, since 0xFEEEFEEE != 0.

Hrm, perhaps I should explain a bit better. I create and initialize a variable (via new), and that all goes just fine. When I free it (via delete), it sets the pointer to 0xFEEEFEEE instead of NULL. When I insert a proper check for NULL, as all good programs that manage their own memory should, I come up with problems as 0xFEEEFEEE passes a NULL check without problems. Is there any good way, other than manually setting all pointers to NULL when deleting them, to detect when memory has already been freed? I would prefer to not use boost simply because I don't want the overhead, small though it may be, since that's the only thing I'd be using boost for.

+13  A: 

When you create a pointer, explicity initialize it to NULL. Likewise after a delete. Depending on the value of unitialized data (except in a few specific cases) is asking for trouble.

You can save yourself a lot of headaches by using a smart pointer class (such as boost::shared_ptr) which will automatically deal with whether a pointer is initialized or not.

Eclipse
Completely agree. Initialization to of new memory to zero should always be done. As a side, one thing I notice is the unnecessary checking for ptr != NULL prior to deleting. It's always safe to delete a pointer that is NULL. Not the case on an uninitialized ptr.
Scott Saad
A: 

I'm pretty sure you can't disable the visual studio default here, and even if you did, the value would then be just whatever was in memory before the memory was allocated.

Your best off just getting in the habit of setting them to 0 in the first place, it's only 2 extra charecters.

int *ptr=0;

You can also use the NULL macro, which is defined as 0 (but not be default, so be carful with multiple definitions when includeing stuff like windows.h and defining it yourself!

Fire Lancer
+12  A: 

VC++'s behaviour shouldn't cause havoc with any valid check you can do. If you are seeing the 0xfeeefeee then you haven't written to the memory (or have freed it), so you shouldn't be reading from the memory anyway.

Rob Walker
+5  A: 

If you build in Release mode instead of Debug mode, the runtime does not fill uninitialized memory at all, but it will still not be zeros. However, you should not depend on this behavior - you should either explicitly initialize the memory yourself with memset(), ZeroMemory(), or SecureZeroMemory(), or set a flag somewhere indicating that the memory is not yet initialized. Reading uninitialized memory will result in undefined behavior.

Adam Rosenfield
+7  A: 

If you're reading uninitialized memory, your checks are most certainly not "valid". The memory is freed. It might already be in use for something else. You can't make any assumptions about the contents of uninitialized memory in C/C++.

Java (and C#, I believe) will guaranteed that allocated memory is zeroed before use, and of course the garbage collection prevents you from seeing freed memory at all. But that isn't a property of the C heap, which exposes the memory directly.

Andy Ross
+4  A: 

You shouldn't need to change the default memory fill for the windows DEBUG runtime and you should use some thing like boost::shared_ptr for pointers any way.

That said. If you really want to you can.

You can change the default fill for the windows DEBUG runtime by using an allocator hook like this. This will only work on HEAP allocated object!

// Call first to register hook    
_CrtSetAllocHook(&zero_fill);



int zero_fill(int nAllocType, 
              void* pvData, 
              size_t nSize,
              int nBlockUse, 
              long lRequest, 
              const unsigned char *szFileName, 
              int nLine )
  /// Very Importaint !! 
  /// infinite recursion if this is removed !!
  /// _CRT_BLOCK must not do any thing but return TRUE
  /// even calling printf in the _CRT_BLOCK will cause
  /// infinite recursion
  if ( nBlockUse == _CRT_BLOCK )
    return( TRUE );
  switch(nAllocType)
  {
  case _HOOK_ALLOC:
  case _HOOK_REALLOC:
    // zero initialize the allocated space.
    memset(pvData,0,nSize);
    break;
  case _HOOK_FREE:
    break;
  }
  return TRUE;
witkamp
This actually inadvertantly provides me with the solution I want: I can set pvData to NULL on _HOOK_FREE and not run into problems with 0xFEEEFEEE for my pointer address.
Jeff Hubbard
A: 

if you are using malloc, it does not intialize the memory to anything. you get whatever. if you want to allocate a block and initialize it to 0, use 'calloc' which is like malloc only with initialization (an an element size parameter which you set to 1 if you want to emulate malloc). you should read up on calloc before using it as it has some slight differences.

http://wiki.answers.com/Q/What_is_the_difference_between_malloc_and_calloc_functions

+3  A: 

That is actually a very nice feature in VC++ (and I believe other compilers) because it allows you to see un-allocated memory for a pointer in the debugger. I will think twice before disabling that functionality. When you delete an object in C++ you should set the pointer to NULL in case something later tries to delete the object again. This feature will allow you to spot the places where you forgot to set the pointer to NULL.

Curro
A: 

Why not create your own #define and get in the habit of using it?

I.e.

#define SafeDelete(mem) { delete mem; mem = NULL; }
#define SafeDeleteArray(mem) { delete [] mem; mem = NULL; }

Obviously you can name it whatever you like. deleteZ, deletesafe, whatever you're comfortable with.

Cliff Cawley
+4  A: 

You say:

I create and initialize a variable (via new), and that all goes just fine. When I free it (via delete), it sets the pointer to 0xFEEEFEEE instead of NULL. When I insert a proper check for NULL, as all good programs that manage their own memory should, I come up with problems as 0xFEEEFEEE passes a NULL check without problems.

Even the debug heap routines of MSVC will not change the value of the pointer you're deleting - the value of the pointer you're deleting will not change (even to NULL). It sounds like you're accessing a pointer that belongs to the object you've just deleted, which is a bug, plain and simple.

I'm pretty sure that what you're trying to do will simply cover up an invalid memory access. You should post a snippet of code to show us what is really happening.

Michael Burr
+3  A: 

@Jeff Hubbard:

This actually inadvertantly provides me with the solution I want: I can set pvData to NULL on _HOOK_FREE and not run into problems with 0xFEEEFEEE for my pointer address.

If this is working for you, then it means that you are reading freed memory when you're testing for the NULL pointer (ie., the pointer itself resides in the memory you freed).

This is a bug.

The 'solution' you're using is simply hiding, not fixing, the bug. When that freed memory ever gets allocated to something else, suddenly you'll be using the wrong value as a pointer to the wrong thing.

Michael Burr
What's happening is my code crashes under a debug compilation, but succeeds under a release compilation. I've checked it under a debugger and my pointers are getting set to 0xFEEEFEEE after I call delete on them. Again, same code on release doesn't crash and behaves as expected.
Jeff Hubbard
Your code is working under release-compiles by accident. The 0xFEEEFEEE value is *designed* to cause problems if you're accessing memory that's been released, since that's a bug in your code.
Head Geek
A: 

@[Jeff Hubbard]:

What's happening is my code crashes under a debug compilation, but succeeds under a release compilation. I've checked it under a debugger and my pointers are getting set to 0xFEEEFEEE after I call delete on them. Again, same code on release doesn't crash and behaves as expected.

This is very strange behavior - I'm still convinced that there's probably a latent bug that's being hidden by the _CrtSetAllocHook() workaround.

The 0xFEEEFEEE signature is used by the OS heap manager to indicate freed memory (see http://www.nobugs.org/developer/win32/debug_crt_heap.html). By any chance can you post some repro code and indicate exactly which compiler version you're using?

Michael Burr
+3  A: 

If it's working in release mode, it's because of shear luck.

Mike B is right to assume that the debug fix is hiding a bug. In release mode, a pointer is being used that has been freed but not set to NULL, and the memory it points to is still "valid". At some point in the future, memory allocations will change, or the memory image will change, or something will cause the "valid" memory block to become "invalid". At that point, your release build will start failing. Switching to debug mode to find the problem will be useless, because the debug mode has been "fixed".

I think we call all agree that the following code shouldn't work.

char * p = new char[16];     // 16 bytes of random trash
strcpy(p, "StackOverflow");  // 13 characters, a '\0' terminator, and two bytes of trash
delete [] p;                 // return 16 bytes to the heap, but nothing else changes;

if (p != NULL)               // Why would p be NULL?  It was never set to NULL
    ASSERT(p[0] == 'S');     // In debug, this will crash, because p = 0xfeeefeee and 
                             // dereferencing it will cause an error.
                             // Release mode may or may or may not work, depending on
                             // other memory operations

As just about every other poster has said, pointers should be set to NULL after calling delete. Whether you do it yourself or use boost or some other wrapper or even the macro in this thread is up to you.

Dan Shield
+2  A: 

What's happening is my code crashes under a debug compilation, but succeeds under a release compilation.

Release build will crash on customer's machine. It always does.

I've checked it under a debugger and my pointers are getting set to 0xFEEEFEEE after I call delete on them.

Pointers are not changed after you call delete on them. It's the memory they point to that gets set to 0xfeeefeee, 0xfeeefeee, ..., 0xfeeefeee.

If you spot that your program reads data from freed memory (which is conveniently indicated by 0xfeeefeee pattern in DEBUG build), you have a bug.

Constantin