43

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?

9
  • 5
    I've seen systems where the first 1K of memory is defined to be not valid. So if a NULL pointer is dereferenced, the process will die a quick death. 0xDEADBEEF could be a valid location. Aug 11, 2009 at 1:47
  • 2
    @Robert: I've seen systems where the interrupt vector starts at 0, so dereferencing a NULL function pointer just seems to reboot the system (but doesn't reinitialize the stacks, etc.). Any address could be a valid location for something.
    – bk1e
    Aug 11, 2009 at 4:55
  • 9
    @bk1e: IVT should NEVER be accessible from usermode. But you are correct in that there's no reason why address 0 can't be mapped. In Linux, it's easy to map to address 0 by changing an option in the kernel. In any case, the lesson learned here is not to use stupid patterns to mark pointers as invalid, use null or a separate flag in the struct. Assuming it will just crash is completely irresponsible and ignorant, if you're lucky, you will only get a segfault, it's likely that this can lead to remote code execution, and already has many, many, many, times in the past. Aug 2, 2010 at 20:11
  • 2
    @bk1e, but the C standard guarantees that NULL (and respectively 0 converted to a pointer) will be an invalid pointer which you can't dereference.
    – CMircea
    Apr 26, 2011 at 21:12
  • 2
    @iconiK: What does "can't dereference" mean? You most certainly can dereference NULL, but the result is undefined behavior (according to C99 section 6.5.3.2). A null pointer is guaranteed to compare unequal to any object or function (according to C99 section 6.3.2.3), so if there is a C object or C function at address 0, the compiler ought to convert (void*)0 to point somewhere other than address 0. However, the interrupt vector table isn't a C object or C function, so I don't think compilers are obligated to guarantee that NULL doesn't point to the interrupt vector table.
    – bk1e
    Apr 27, 2011 at 14:56

12 Answers 12

71

0xBADC0FFEE0DDF00D

3
  • 5
    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
    Aug 2, 2010 at 16:14
  • 8
    @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. Aug 2, 2010 at 20:17
  • 1
    How did you arrive at this number?
    – David G
    Apr 29, 2013 at 20:56
55

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

27

Most current 64-bit systems let you use only the lowest 248–252 bits of the address space; higher bits of the address must be all-zero. Some chips (e.g. amd64) also let you use the highest 248–252. Addresses outside these ranges cannot ever be mapped to accessible memory; the hardware simply won't allow it.

I therefore recommend you use a value close to 263, which is nowhere near either of the possibly-usable spaces. If the leading four hex digits are 7ff8, the value will be a double precision floating-point NaN, which is convenient. So my suggested cute hexadecimal phrase is 0x7FF8BADFBADFBADF.

By the way, you really don't want to use a value close to 0, because that makes it hard to tell an offset dereference of NULL — a structure member access, for instance — from a dereference of the poison pattern.

3
  • 1
    That «most current 64-bit system let you use only the lowest 48-52 bits of the address space» and that «the hardware simply won't allow it».
    – nalply
    Dec 19, 2010 at 10:23
  • 3
    The architecture manual for each CPU of interest will tell you how many bits of the address space are usable. For instance, the AMD64 Architecture Programmer's Manual, Volume 2 (System Programming) says in section 1.1.3 that not all 64 bits of the address space are necessarily usable and that unusable high bits must be all-zero or all-one, and then in section 5.3.3 shows you that current implementations only allow use of the low 48 bits.
    – zwol
    Dec 19, 2010 at 17:02
  • 1
    I'm not aware of any overview that lists CPUs with 64-bit addressing and their usable address ranges, but the only exception to my original assertion that I can find is PowerPC in hashed page table mode. With tree-structured page tables, every additional six to eight bits of virtual address space adds a tree level and makes TLB misses slower, so architecture designers are reluctant to make more space usable than people actually need, which right now is 48-52 bits (except for exotic single address space operating systems).
    – zwol
    Dec 19, 2010 at 17:08
25

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.

0
14

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).

9
  • 5
    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
    Aug 11, 2009 at 6:52
  • 2
    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: c-faq.com/null/null1.html Aug 20, 2009 at 16:46
  • 2
    @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: blog.cr0.org/2009/06/bypassing-linux-null-pointer.html
    – mrduclaw
    Oct 14, 2009 at 13:41
  • 2
    @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
    Jan 18, 2010 at 18:04
  • 3
    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
    Aug 2, 2010 at 20:54
13

0xDEADBEEFBAADF00D might work.

0
8

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.

0
5

Two 0xDEADBEEFs should be enough, I think..

3

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.

2
  • 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
    Aug 11, 2009 at 9:05
  • 2
    "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.
    – zwol
    Aug 2, 2010 at 20:34
2

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.

2
  • 1
    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
    Aug 11, 2009 at 1:50
  • 2
    It's almost always in kernel memory mapping area anyway.
    – Joshua
    Aug 17, 2009 at 20:59
1

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).

1
  • 1
    It's not really that large... there are plenty of structures greater than 66 bytes long. Aug 2, 2010 at 21:19
1

As the system I worked on basically runs on x86_64 platform, the value I use is:

0xDEADBEEFDEADBEEF

Reasons are:

  • On x86_64 platform, only the low-order 48 bits are used for virtual memory address in current implementation, meaning any value > 2^48 should work: https://en.wikipedia.org/wiki/X86-64
  • As 0xDEADBEEF is already very well known for this purpose in 32bit, 0xDEADBEEFDEADBEEF in 64bit is just more 'backward compatible'

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.