I’ve recently been pointed into one of my C programs that, should the start address of the memory block be low enough, one of my tests would fail as a consequence of wrapping around zero, resulting in a crash.
At first i thought “this is a nasty potential bug”, but then, i wondered : can this case happen ? I’ve never seen that. To be fair, this program has already run millions of times on a myriad of systems, and it never happened so far.
Therefore, my question is :
What is the lowest possible memory address that a call to malloc() may return ? To the best of my knowledge, i’ve never seen addresses such as 0x00000032 for example.
I’m only interested in “modern” environments, such as Linux, BSD and Windows. This code is not meant to run on a C64 nor whatever hobby/research OS.
First of all, since that’s what you asked for, I’m only going to consider modern systems. That means they’re using paged memory and have a faulting page at 0 to handle null pointer dereferences.
Now, the smallest page size I’m aware of on any real system is 4k (4096 bytes). That means you will never have valid addresses below 0x1000; anything lower would be part of the page containing the zero address, and thus would preclude having null pointer dereferences fault.
In the real world, good systems actually keep you from going that low; modern Linux even prevents applications from intentionally mapping pages below a configurable default (64k, I believe). The idea is that you want even moderately large offsets from a null pointer (e.g.
p[n]wherephappens to be a null pointer) to fault (and in the case of Linux, they want code in kernelspace to fault if it tries to access such addresses to avoid kernel null-pointer-dereference bugs which can lead to privilege elevation vulns).With that said, it’s undefined behavior to perform pointer arithmetic outside of the bounds of the array the pointer points into. Even if the address doesn’t wrap, there are all sorts of things a compiler might do (either for hardening your code, or just for optimization) where the undefined behavior could cause your program to break. Good code should follow the rules of the language it’s written in, i.e. not invoke undefined behavior, even if you expect the UB to be harmless.