Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How test if a value is (or is not) a valid pointer? [duplicate]

Is there any way to determine (programatically, of course) if a given pointer is "valid"? Checking for NULL is easy, but what about things like 0x00001234? When trying to dereference this kind of pointer an exception/crash occurs.

A cross-platform method is preferred, but platform-specific (for Windows and Linux) is also ok.

Update for clarification: The problem is not with stale/freed/uninitialized pointers; instead, I'm implementing an API that takes pointers from the caller (like a pointer to a string, a file handle, etc.). The caller can send (in purpose or by mistake) an invalid value as the pointer. How do I prevent a crash?

like image 603
noamtm Avatar asked Feb 15 '09 15:02

noamtm


7 Answers

Update for clarification: The problem is not with stale, freed or uninitialized pointers; instead, I'm implementing an API that takes pointers from the caller (like a pointer to a string, a file handle, etc.). The caller can send (in purpose or by mistake) an invalid value as the pointer. How do I prevent a crash?

You can't make that check. There is simply no way you can check whether a pointer is "valid". You have to trust that when people use a function that takes a pointer, those people know what they are doing. If they pass you 0x4211 as a pointer value, then you have to trust it points to address 0x4211. And if they "accidentally" hit an object, then even if you would use some scary operation system function (IsValidPtr or whatever), you would still slip into a bug and not fail fast.

Start using null pointers for signaling this kind of thing and tell the user of your library that they should not use pointers if they tend to accidentally pass invalid pointers, seriously :)

like image 88
Johannes Schaub - litb Avatar answered Oct 05 '22 23:10

Johannes Schaub - litb


Here are three easy ways for a C program under Linux to get introspective about the status of the memory in which it is running, and why the question has appropriate sophisticated answers in some contexts.

  1. After calling getpagesize() and rounding the pointer to a page boundary, you can call mincore() to find out if a page is valid and if it happens to be part of the process working set. Note that this requires some kernel resources, so you should benchmark it and determine if calling this function is really appropriate in your api. If your api is going to be handling interrupts, or reading from serial ports into memory, it is appropriate to call this to avoid unpredictable behaviors.
  2. After calling stat() to determine if there is a /proc/self directory available, you can fopen and read through /proc/self/maps to find information about the region in which a pointer resides. Study the man page for proc, the process information pseudo-file system. Obviously this is relatively expensive, but you might be able to get away with caching the result of the parse into an array you can efficiently lookup using a binary search. Also consider the /proc/self/smaps. If your api is for high-performance computing then the program will want to know about the /proc/self/numa which is documented under the man page for numa, the non-uniform memory architecture.
  3. The get_mempolicy(MPOL_F_ADDR) call is appropriate for high performance computing api work where there are multiple threads of execution and you are managing your work to have affinity for non-uniform memory as it relates to the cpu cores and socket resources. Such an api will of course also tell you if a pointer is valid.

Under Microsoft Windows there is the function QueryWorkingSetEx that is documented under the Process Status API (also in the NUMA API). As a corollary to sophisticated NUMA API programming this function will also let you do simple "testing pointers for validity (C/C++)" work, as such it is unlikely to be deprecated for at least 15 years.

like image 45
George Carrette Avatar answered Oct 06 '22 00:10

George Carrette


Preventing a crash caused by the caller sending in an invalid pointer is a good way to make silent bugs that are hard to find.

Isn't it better for the programmer using your API to get a clear message that his code is bogus by crashing it rather than hiding it?

like image 42
Nailer Avatar answered Oct 05 '22 23:10

Nailer


On Win32/64 there is a way to do this. Attempt to read the pointer and catch the resulting SEH exeception that will be thrown on failure. If it doesn't throw, then it's a valid pointer.

The problem with this method though is that it just returns whether or not you can read data from the pointer. It makes no guarantee about type safety or any number of other invariants. In general this method is good for little else other than to say "yes, I can read that particular place in memory at a time that has now passed".

In short, Don't do this ;)

Raymond Chen has a blog post on this subject: http://blogs.msdn.com/oldnewthing/archive/2007/06/25/3507294.aspx

like image 29
JaredPar Avatar answered Oct 06 '22 00:10

JaredPar


AFAIK there is no way. You should try to avoid this situation by always setting pointers to NULL after freeing memory.

like image 28
Ferdinand Beyer Avatar answered Oct 06 '22 00:10

Ferdinand Beyer


On Unix you should be able to utilize a kernel syscall that does pointer checking and returns EFAULT, such as:

#include <unistd.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
#include <stdbool.h>

bool isPointerBad( void * p )
{
   int fh = open( p, 0, 0 );
   int e = errno;

   if ( -1 == fh && e == EFAULT )
   {
      printf( "bad pointer: %p\n", p );
      return true;
   }
   else if ( fh != -1 )
   {
      close( fh );
   }

   printf( "good pointer: %p\n", p );
   return false;
}

int main()
{
   int good = 4;
   isPointerBad( (void *)3 );
   isPointerBad( &good );
   isPointerBad( "/tmp/blah" );

   return 0;
}

returning:

bad pointer: 0x3
good pointer: 0x7fff375fd49c
good pointer: 0x400793

There's probably a better syscall to use than open() [perhaps access], since there's a chance that this could lead to actual file creation codepath, and a subsequent close requirement.

like image 31
Peeter Joot Avatar answered Oct 05 '22 23:10

Peeter Joot


Regarding the answer a bit up in this thread:

IsBadReadPtr(), IsBadWritePtr(), IsBadCodePtr(), IsBadStringPtr() for Windows.

My advice is to stay away from them, someone has already posted this one: http://blogs.msdn.com/oldnewthing/archive/2007/06/25/3507294.aspx

Another post on the same topic and by the same author (I think) is this one: http://blogs.msdn.com/oldnewthing/archive/2006/09/27/773741.aspx ("IsBadXxxPtr should really be called CrashProgramRandomly").

If the users of your API sends in bad data, let it crash. If the problem is that the data passed isn't used until later (and that makes it harder to find the cause), add a debug mode where the strings etc. are logged at entry. If they are bad it will be obvious (and probably crash). If it is happening way to often, it might be worth moving your API out of process and let them crash the API process instead of the main process.

like image 44
Fredrik Avatar answered Oct 05 '22 22:10

Fredrik