3

I came across an access violation while reading location 0xFEEEFEF6 in Visual Studio 2012 (using Nov 2012 CTP compiler) somewhere deep inside the C++11 concurrency implementation.

Does this value have any special meaning? Looking in Wikipedia I found similar entries (0xFEEEFEEE and 0xFEEDFACE).

Jens Åkerblom
  • 898
  • 8
  • 19
  • Memory addresses don't have any special meaning. Most likely, you are dereferencing an invalid pointer. The only pointer value with special meaning is the null pointer value. – Andy Prowl Jun 12 '13 at 18:16
  • Sounds like someone is reading out of bounds data :) Not sure if that value has any significance though. – Michael Dorgan Jun 12 '13 at 18:16
  • @AndyProwl It might have significance, in debug builds MSVS gives uninitialized/deleted/invalid pointers special values to provide debugging hints. – Luchian Grigore Jun 12 '13 at 18:17
  • 8
    this looks like 0xFEEEFEEE + 8 – John Dvorak Jun 12 '13 at 18:17
  • Those odd values like 0xDEADBEEF are deliberately put into code so that they can be spotted in a core dump, a trace, or in a debugger. In fact I think there is on SO a user named: 0xDEADBEEF. – jim mcnamara Jun 12 '13 at 18:18
  • @LuchianGrigore: Right, that's true, but I would not say that is a "special meaning". But yes, one may use it as a hint to realize that an uninitialized pointer was dereferenced – Andy Prowl Jun 12 '13 at 18:18
  • @JensÅkerblom: If you try to read memory outside of your program's address space (which 0xF...anything likely is), you're going to get an access violation. "Access violation" doesn't imply read-only or read-write, just access (it can be caused by both). – ssube Jun 12 '13 at 18:22
  • @JensÅkerblom depends on if you were trying to write to that address or read from that address. You were trying to read from 0xFEEEFEEE+8. – John Dvorak Jun 12 '13 at 18:22
  • Yea, realized that and deleted the comment :) – Jens Åkerblom Jun 12 '13 at 18:22
  • @AndyProwl: The addresses that MSVC uses to flag actually do have a special meaning. In some of them, the first letter of each octect stands for *C*lean, *D*irty, and *F*ree, IIRC. – ssube Jun 12 '13 at 18:23
  • @peachykeen anything above 0x80000000 or 0xC00000000 is kernel space in windows. Pretty much out of any program's address space. – John Dvorak Jun 12 '13 at 18:23
  • @AndyProwl: See http://www.nobugs.org/developer/win32/debug_crt_heap.html for a good write-up of how the guard codes work. – ssube Jun 12 '13 at 18:24
  • Also see http://stackoverflow.com/a/370362/12711 for information on MSVC debug heap fill values. – Michael Burr Jun 12 '13 at 19:32

1 Answers1

6

0xFEEEFEF6 itself doesn't have a special meaning, but it's likely based on one of the "guard bytes" segments that MSVC likes to put around heap allocations. As Jan Dvorak noted, it's probably 8 bytes past the end of something, quite likely 2 pointers past the end of an array.

The concept is that memory you're likely to accidentally access, but shouldn't, is marked with very obvious patterns. Some of the most common are 0xCDCDCDCD and 0xFDFDFDFD, although 0xDDDDDDDD and 0xFEEEFEEE are also easy to run into. Classic compilers (not sure if any still use it) liked 0xDEADBEEF. Here's a pretty good write-up of the cases and positions you'll see guard bytes in.

The two most common causes of seeing these in a segfault (access violation) are typically accessing memory that's already been freed and over-running your bounds, especially in an array of pointers. Most of the values used for guard data aren't valid if they were to show up in the app otherwise (you're not going to get a block of memory at 0x00000000 or 0xCDCDCDCD, those are well outside of the virtual address space your heap lives in). Knowing the common ones off the top of your head can save a lot of time debugging.

Note that, with very few/no exceptions, these guard bytes only show up in debug builds. Writing memory with special patterns everytime it's allocated/deallocated (in fact, writing significantly more memory than has been allocated, since most of the guard patterns occur on the boundaries of allocated chunks) is fairly expensive and shouldn't be done at runtime. If you have issues like this in your debug builds, you're likely to get seemingly random (undefined) addresses from a release build. You may also get unlucky enough that a legitimate address ends up being grabbed by mistake, which can lead to all sorts of heap corruption.

Because guard bytes don't show up in release builds, you can't check for them as you might NULL and use that as a condition in your code. Instead, smart pointers and containers can help you manage memory correctly and avoid bad access in the first place. While occasionally annoying, smart pointers very much help avoid issues like this. Note that some types of access violation, particularly buffer overruns, are considered an entire class of security vulnerability because of how often they appear.

Without a VM/runtime forcing you to stay within certain memory constraints, if can be very easy to access memory you ought not. For example:

int values[10];
int output = 0;
int length = 10;
while (int i <= length) {
    output += values[++length];
}

The prefix-increment will cause you to run off the end of the array and access values[10], an invalid index. Sometimes that may immediately cause an access violation and halt your program, other times it may be memory you're allowed to access and the value will be added to output, which could cause an overflow on output and unexpected behavior through the rest of the app.

Guard bytes exist so that your segfaults or increments will, while debugging, have repeatable values and be as obvious as possible.

ssube
  • 47,010
  • 7
  • 103
  • 140
  • 1
    In particular, 0xFEEEFEEE is used by Microsoft's debug heap to mark freed memory. Wikipedia has a nice summary of many of these special values: http://en.wikipedia.org/wiki/Magic_number_(programming)#Magic_debug_values – Adrian McCarthy Jun 12 '13 at 19:56
  • Actually, there are two bugs in this example, using `<=` for an index check and using pre-increment. You will actually overrun that buffer by two locations hitting `value[11]` at the end. – penguin359 Jan 03 '23 at 10:06