I know NULL (0x00000000) is a pointer to nothing because the OS doesn’t allow the process to allocate any memory at this location. But if I use 0x00000001 (Magic number or code-pointer), is it safe to assume as well that the OS wont allow memory to be allocated here?
If so then until where is it safe to assume that?
I know NULL (0x00000000) is a pointer to nothing because the OS doesn’t allow
Share
Standard (first)
The Standard only guarantees that
0is a sentinel value as far as pointers go. The underlying memory representation is no way guaranteed; it’s implementation defined.Using a pointer set to that sentinel value for anything else than reading the pointer state or writing a new state (which includes dereferencing or pointer arithmetic) is undefined behavior.
Virtual Memory
In the days of virtual memory (ie, each process gets its own memory space, independent from the others), a null pointer is most often indeed represented as 0 in the process memory space. I don’t know of any other architectures actually, though I imagine that in mainframes it may not be so.
Unix
In the Unix world, it is typical to reserve all the address space below 0x8000 for null values. The memory is not allocated, really, it is just protected (ie, placed in a special mode), so that the OS will trigger a segmentation fault should you ever try to read it or write to it.
The idea of using such a range is that a null pointer is not necessarily used as is. For example if you use a
std::pair<int, int>* p = 0;which is null, and callp->second, then the compiler will perform the arithmetic necessary to point tosecond(ie+4generally) and attempt to access the memory at0x4directly. The problem is obviously compounded by arrays.In practice, this
0x8000limit should be practical enough to detect most issues (and avoid memory corruption or others). In this case, this means that you avoid the undefined behavior and get a “proper” crash. However, should you be using a large array you could overshoot it, so it’s not a silver bullet.The particular limit of your implementation or compiler/runtime stack can be determined either through documentation or by successive trials. There might even be a way to tweak it.