Testing for valid pointers
A long time ago on Apple’s carbon-development mailing list, someone asked how to test if a give pointer is valid on Mac OS X. Today, the same question came up on the xcode-users list. I answered the original question, but the answer is buried in the depths of Apple’s mailing list archives. For the benefit of future Web searchers, then, here’s my answer.
I should note that you shouldn’t be doing this in production code. All it’s really telling you is whether the address you pass is mapped into your process’ address space. An uninitialized pointer could just as easily end up in your mapped address space as not. Also, this call is not cheap. It’s less expensive than some other alternatives, but it certainly isn’t free.
#include <stdio.h>
#include <stdlib.h>
#include <mach/mach.h>
int IsPointerValid(const void *ptr) {
kern_return_t result;
vm_address_t address;
vm_size_t size;
struct vm_region_basic_info info;
mach_msg_type_number_t count;
mach_port_t objectName = MACH_PORT_NULL;
address = (vm_address_t) ptr;
count = VM_REGION_BASIC_INFO_COUNT;
result = vm_region(mach_task_self(), &address, &size,
VM_REGION_BASIC_INFO, (vm_region_info_t) &info,
&count, &objectName);
if (objectName != MACH_PORT_NULL) {
mach_port_deallocate(mach_task_self(), objectName);
}
if (result != KERN_SUCCESS || address > (vm_address_t) ptr ||
info.protection == VM_PROT_NONE) {
return 0;
}
return 1;
}
void TestPointer(const void *ptr) {
if (IsPointerValid(ptr)) {
printf("%p is valid!\n", ptr);
} else {
printf("%p is not valid!\n", ptr);
}
}
int main(void) {
int foo;
char *ch;
TestPointer(NULL);
TestPointer(&main);
TestPointer((void *) 0x12345678);
TestPointer(&foo);
TestPointer((void *) 0xffffffff);
ch = (char *) malloc(5);
TestPointer(ch);
return 0;
}
rentzsch Said,
November 12, 2003 @ 9:59 am
One relatively cheap test is to assert that a pointer you’re handed is evenly divisible by four { assert( ((ptr % 4) == 0); }. This simple test invalidates 75% of the possible pointer input values. Nowadays on Mac OS X, I but you could raise it to eight and be alright, catching 87.5% of bogus inputs.
Marc Said,
November 12, 2003 @ 5:29 pm
You can always just try to read the memory at the pointer and catch the resulting exception if it is a bad address.
Eric Said,
November 12, 2003 @ 5:33 pm
Well, you can only do that in a try/catch block when you’re using SEH on Windows. The portable POSIX way is to have a signal handler trap invalid reads, but this method is much faster.
Marc Said,
November 12, 2003 @ 6:06 pm
It’s been a bit since of done any *nix programming…