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.