views:

1398

answers:

11

For C++ development for 32-bit systems (be it Linux, Mac OS or Windows, PowerPC or x86) I have initialised pointers that would otherwise be undefined (e.g. they can not immediately get a proper value) like so:

int *pInt = reinterpret_cast<int *>(0xDEADBEEF);

(To save typing and being DRY the right-hand side would normally be in a constant, e.g. BAD_PTR.)

If pInt is dereferenced before it gets a proper value then it will crash immediately on most systems (instead of crashing much later when some memory is overwritten or going into a very long loop).

Of course the behavior is dependent on the underlying hardware (getting a 4 byte integer from the odd address 0xDEADBEEF from a user process may be perfectly valid), but the crashing has been 100% reliable for all the systems I have developed for so far (Mac OS 68xxx, Mac OS PowerPC, Linux Redhat Pentium, Windows GUI Pentium, Windows console Pentium). For instance on PowerPC it is illegal (bus fault) to fetch a 4 byte integer from an odd address.

What is a good value for this on 64-bit systems?

+10  A: 

Just throwing this out there but would 0xDEADBEEFBAADF00D work?

Joshua
+10  A: 

I'm assuming you've already discounted NULL (i.e. 0 without the typecast). It's definitely the safest choice, as, in theory, a valid pointer could point to the memory address 0xDEADBEEF (Or any other non-NULL memory address).

Mike Koval
I think one of the points of using 0xDEADBEEF or some other known-bad value is that it's quite obvious when debugging the resultant core file (ore equivalent) that you're dealing with an uninitialised pointer, rather than garbage/invalid/incorrect data.I'd suggest the chances of 0xDEADBEEF actually pointing to a valid memory location are small enough to be greatly outweighed by the benefits.
Rodyland
For Pointers, Always NULL/0 should be used. 0xDEADBEEF and other hex-values are used to fill recently-allocated-but-not-initialized , recently-freed-should-not-be-accessed-any-more memory regions handled by the heap-manager functions (this may also be true for the stack)...
Malkocoglu
What you've never seen a memory mapping at NULL?
Joshua
No one has ever seen a memory mapping at NULL as the compiler guarantees that the NULL memory location is never used: "...a null pointer points definitively nowhere; it is not the address of any object or function." See: http://c-faq.com/null/null1.html
Mike Koval
@Mike Koval, well that's just simply not true. I've mapped memory at NULL. In fact it's not that uncommon, a quick Googling of "null pointer dereference exploit" should give you lots of examples. This looks like it probably has some high-level information: http://blog.cr0.org/2009/06/bypassing-linux-null-pointer.html
mrduclaw
@Mike: That is true, however the C specification does not define the behavior of an attempt to dereference a NULL pointer. Thus it is legal (though atypical) for a platform to accept reads from and writes to *NULL.
ephemient
The NULL/0 pointer is not necessarily represented as 0-bytes in memory. Although I wouldn't know of any system where it is anything different.
Thomas
@mrduclaw So qualify it a little - as long as you stay in userland, you're guaranteed that NULL is absolutely invalid.
calmh
Just so you know, mmap() will map NULL if explicitly told to do so (passed flag for exact address with NULL as the address). and in gcc compiling with -fno-delete-null-pointer-checks tells the compiler not to assume that dereferencing NULL is invalid.
Joshua
+39  A: 

0xBADC0FFEE0DDF00D

chaos
This particular one has the advantage that you need yottabytes of memory to actually make this a sane value as kernel heap grows down while user heap grows up.
Joshua
@Joshua: 1. I can map my pages wherever I like. 2. That's a very dangerous assumption to make (perhaps its true with your current os on an x86 setup, but this is implementation dependent), what if the stack starts at 0xBADCOFFEE0DFOOD-0x1000? The stack starts at random places already, it does this to try and make exploitation harder and for just technical reasons aside from that.
Longpoke
Point taken, x64 only.
Joshua
+36  A: 

According to Wikipedia, BADC0FFEE0DDF00D is used on IBM RS/6000 64-bit systems to indicate uninitialized CPU registers.

Thomas Owens
+5  A: 

I don't have a good choice for you, but here's a list of hex words that you can use to make your phrase.

Ned Batchelder
A: 

0x42 could work on both 32bit and 64bit ? (It should still trigger a crash since it is close enough to the NULL pointer, and given that it's rather large, chances are you would not have it within a regular dereference of a structure field with the structure pointer being NULL).

Andrew Y
It's not really that large... there are plenty of structures greater than 66 bytes long.
Jeremy Friesner
+2  A: 

It depends on the OS and the environment, of course. I don't think 0xDEADBEEF is necessarily a bad pointer in an arbitrary 32-bit system, either.

Realistically, any modern OS should be access-protecting the first few pages of process memory, so NULL should be a good invalid pointer value. Conveniently enough, it's already pre-defined for you.

Mark Bessey
Agree that NULL is a very useful choice. 0xDEADBEEF isn't an invalid pointer, but not only is it awfully unlikely in practice, but it's not aligned on a 4- or 2-byte boundary. Except as a char* or possibly bool*, it won't occur naturally unless you've got some seriously messed-up memory semantics.
ChrisV
It's almost always in kernel memory mapping area anyway.
Joshua
+1  A: 

I see several answers claiming NULL is a good choice, but I disagree.

NULL is often used as a valid return value from functions. It indicates a failure return or an unknown value. This is a different meaning than "uninitialized pointer."

Using a debugger on the code and seeing NULL would then leave two possibilities: the pointer was never initialized or it had failed a memory allocation.

Setting the uninitialized pointer to 0xDEADBEEF or the 64-bit equivalent means that a NULL pointer indicates an intentional value.

Zan Lynx
This is only true if you need an uninitialized pointer. And that's where I disagree: Unless you do embedded stuff or other things that are so performance-sensitive, that initializing a pointer to `NULL` is not possible, in the _very_ rare cases where you need a pointer without being able to initialize it to something sensible, initializing it to `NULL` gets you rid of the problem. I don't think I needed an uninitialized pointer in years.
sbi
"That was never initialized" values are very useful when debugging - one doesn't *explicitly* initialize any given memory location this way, one fills entire memory blocks with it (on malloc() and again, with a different pattern, on free()) so as to detect places where the program *should have* initialized a variable but didn't.
Zack
+3  A: 

Two 0xDEADBEEF should be enough i think..

LostMohican
+7  A: 

Generally it doesn't matter exactly what pattern you write, it matters that you can identify the pattern in order to determine where problems are occurring. It just so happens that in the Linux kernel these are often chosen so that they can be trapped if the addresses are dereferenced.

Have a look in the Linux kernel at include/linux/poison.h. This file contains different poison values for many different kernel subsystems. There is no one poison value that is appropriate.

Also, you might check per-architecture include files in the Linux kernel source tree for info on what is used on specific architectures.

include/linux/poison.h

http://git.kernel.org/?p=linux/kernel/git/stable/linux-2.6.33.y.git;a=blob;f=include/linux/poison.h;h=34066ffd893d733b8134da1b57915bec314afb48;hb=HEAD

Noah Watkins
Thanks. done...
Noah Watkins
+6  A: 
Zack
+1. Great answer. Deserves at least 5 more.
Peter Mortensen