
Question:
I was wondering if there some way to identify an invalid memory address on a particular platform (x86 64-bit, for my case). I need it to catch a program much before it dereferences the address and throws a SIGILL/SIGSEGV error.
Answer1:In general, you can't. An invalid address looks much the same as a valid one. The only invalid address that is recognizable is NULL
.
So be sure (write your code thus) that your pointers are either valid or NULL
before you use them. <strong><em>Always</em></strong>. There is no way around that.
You can use tools to detect places where your pointers may be invalid (e.g. uninitialized, already freed, etc.), but that is not what you were asking.
Answer2:You can see all the memory mappings of the current process in file /proc/self/maps
. Just open that file and process its content: every line starts with two hexadecimal numbers separated by -
, which are the addresses that can be accessed by the process.
All the memory addresses which are mapped by your process are there, but some of them may not have read, write or execute permissions; if you need to check for them, you will also have to read and parse the next field.
Sample contents of that file:
$ cat /proc/self/maps
00400000-0040c000 r-xp 00000000 08:01 24340229 /bin/cat
0060b000-0060c000 r--p 0000b000 08:01 24340229 /bin/cat
0060c000-0060d000 rw-p 0000c000 08:01 24340229 /bin/cat
0253e000-0255f000 rw-p 00000000 00:00 0 [heap]
[...]
7f050d97e000-7f050d97f000 rw-p 00000000 00:00 0
7fff9509e000-7fff950bf000 rw-p 00000000 00:00 0 [stack]
7fff951fe000-7fff95200000 r-xp 00000000 00:00 0 [vdso]
ffffffffff600000-ffffffffff601000 r-xp 00000000 00:00 0 [vsyscall]
Answer3:If specifically preventing SIGSEGV
is your goal, remember that you can catch segfaults with signal
. You don't need to wait to do this at the point of use (where it's presumably too late) - you could temporarily redefine the SIGSEGV
handler, run all of the addresses you want to check through a simple identity routine (read the target value, write it back), and then - if your handler never detected any errors - restore the original handler and move on to your section of code that needs to know that all addresses it receives are safe ("safe") to dereference. If not, you can raise or return an error of your own to the caller.
However, you can't generally tell whether an address is truly valid or not, because the underlying system will probably have allocated some stuff around the actual objects you requested with malloc
, and accessing into these areas will likely not cause the program to crash - as far as the act of reading memory is concerned these addresses are effectively "valid" too, even though they don't represent a C object. But if all you need to do is e.g. verify that reading an externally-supplied buffer won't make your code crash, that's not your obstacle to overcome.
You can use the mincore
function. See description <a href="http://linux.die.net/man/2/mincore" rel="nofollow">here</a>.
If the address is not mapped to the process virtual address space, mincore
will return an error.
This isn't 100% as memory can be mapped to the process virtual address space but not committed (no physical pages allocated). It will catch the bulk of your garbage pointers if not all.
You can read more on memory mapping with the mmap
function in <a href="http://linux.die.net/man/2/mmap" rel="nofollow">here</a>