103

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?

starblue
  • 55,348
  • 14
  • 97
  • 151
noamtm
  • 12,435
  • 15
  • 71
  • 107
  • See also http://stackoverflow.com/questions/496034/most-efficient-replacement-for-isbadreadptr – ChrisW Feb 15 '09 at 20:23
  • I think the best positive answer for linux is given by George Carrette. If that is not enough, consider building the function symbol table into the library, or even another level of table of available libraries with their own function tables. Then check against those exact tables. Of course, those negative answers are also correct: you can't really be 100% sure whether a function pointer is valid or not unless you put up many additional restrictions to the user application. – minghua Nov 30 '15 at 20:45
  • Does the API Specification actually specify such an obligation to meet by the implementation? By the way, I pretend having not been assumed that you are both the developer and the designer. My point being, I don't think an API would specify something like "In case of an invalid pointer being passed as an argument, the function must handle the problem and returns NULL.". An API undertakes an obligation to provide a service under proper usage conditions, not by hacks. Nevertheless, it does no harm to be a bit stupidproof. Using a reference makes such cases being less havoc spreading. :) – Poniros Apr 29 '19 at 05:57

30 Answers30

76

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 :)

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Johannes Schaub - litb
  • 496,577
  • 130
  • 894
  • 1,212
  • This is probably the right answer but I think a simple function that checks common hexspeak memory locations would be useful for general debugging... Right now I've got a pointer that sometimes points to 0xfeeefeee and if I had a simple function that I could use to pepper asserts around It would make it much easier to find the culprit... EDIT: Although it wouldn't be hard to write one yourself I guess.. – quant Jun 23 '13 at 23:17
  • @quant the issue is that some C and C++ code could do pointer arithmetic on an invalid address without checking (based on the garbage-in, garbage-out tenet) and will thus pass in a "arithmetically modified" pointer from one of those well-known invalid addresses. Common cases being looking up a method from a non-existent vtable based on an invalid object address or one of a wrong type, or simply reading fields from a pointer to a struct that doesn't point to one. – rwong Dec 23 '14 at 21:49
  • This basically means that you can only take array indices from the outside world. An API that must defend itself from the caller just can't have pointers in the interface. However, it would still be good to have macros to use in assertions about the validity of pointers (which you are bound to have internally). If a pointer is guaranteed to point inside of an array whose starting point and length are known, that can be checked explicitly. It's better to die of an assert violation (documented error) than a deref (undocumented error). – Rob Jan 23 '15 at 21:18
51

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.

George Carrette
  • 681
  • 5
  • 5
  • 23
    First answer that does not try to be moralic about the question itself and actually perfectly answers it. People sometimes don't realize that one really needs this kind of debugging approach to find bugs in e.g. 3rd party libraries or in legacy code because even valgrind only finds wild pointers when actually accessing them, not e.g. if you want to regularly check pointers for validity in a cache table that have been overwritten from some other place in your code ... – lumpidu Jun 17 '15 at 13:52
  • This should be the accepted answer. I did it simliarly on a non-linux platform. Fundamentally it is exposing the process information to the process itself. With this aspect, it looks windows does a better job than linux by exposing the more meaningful information through the process status API. – minghua Nov 30 '15 at 20:39
  • 2
    The only thing this tests is the pointer is dereferenceable. What if its a pointer to a C string (read: block of memory of unknown size), the string was released without setting the pointer to null (free doesn't necessarily do that), and malloc allocated a shorter block of memory for an array of integers? Its still pointing to garbage, and one might get a segmentation fault looking for the zero at the end of the string. – Uri Raz Aug 13 '21 at 00:01
30

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?

Nailer
  • 2,446
  • 1
  • 24
  • 34
  • 11
    In some cases though, checking for a bad pointer immediately when the API is called _is_ how you fail early. For example, what if the API stores the pointer in a data structure where it would only be deferenced later? Then passing the API a bad pointer will cause a crash at some random later point. In that case it would be better to fail sooner, at the API call where the bad value was originally introduced. – peterflynn Sep 11 '15 at 02:22
29

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

Adam Rosenfield
  • 390,455
  • 97
  • 512
  • 589
JaredPar
  • 733,204
  • 149
  • 1,241
  • 1,454
  • 3
    @Tim, there is no way to do that in C++. – JaredPar Feb 15 '09 at 16:14
  • 7
    It's only the "right answer" if you define "valid pointer" as "doesn't cause an access violation/segfault". I'd prefer to define it as "points to meaningful data allocated for the purpose you're going to use it". I'd argue that's a better definition of pointer validity... ;) – jalf Feb 15 '09 at 16:22
  • Even if the pointer is valid cannot be checked this way. Think of thread1() { .. if( IsValidPtr( p ) ) *p = 7; ... } thread2() { sleep( 1 ); delete p; ...} – Christopher Feb 15 '09 at 16:40
  • 2
    @Christopher, very true. I should have said "I can read that particular place in memory at a time that has now passed" – JaredPar Feb 15 '09 at 16:42
  • @JaredPar: Really Bad suggestion. Can trigger a guard-page, so the stack won't be expanded later or something equally nice. – Deduplicator Jul 02 '14 at 16:16
  • @Deduplicator: You know how guard pages work? They attempt to read a place in memory and catch the resulting SEH exception that will be thrown on failure. If it doesn't throw, then it's a valid place in memory. – Mooing Duck May 17 '15 at 19:34
16

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

Ferdinand Beyer
  • 64,979
  • 15
  • 154
  • 145
  • 4
    Setting a pointer to null gives you nothing, except maybe a false sense of security. –  Feb 15 '09 at 15:51
  • That is not true. Especially in C++ you can determine whether to delete member objects by checking for null. Also note that, in C++, it is valid to delete null-pointers, therefore unconditionally deleting objects in destructors is popular. – Ferdinand Beyer Feb 15 '09 at 15:58
  • 4
    int * p = new int(0); int * p2 = p; delete p; p = NULL; delete p2; // crash –  Feb 15 '09 at 16:01
  • 1
    zabzonk, and?? what he said is that you can delete a null pointer. p2 is not a null pointer, but is an invalid pointer. you have to set it to null before. – Johannes Schaub - litb Feb 15 '09 at 16:03
  • 2
    If you have aliases to the memory pointed to, only one of them would be set to NULL, other aliases are dangling around. – jdehaan Feb 11 '11 at 05:51
  • @JohannesSchaub-litb 'and?? what he said is that you can delete a null pointer. ' -- What **anon** said is that setting a pointer to null gives you nothing except maybe a false sense of security. The example with p2 illustrates that. – Jim Balter Feb 25 '13 at 08:11
  • What @Ferdinand wrote about always setting pointers to NULL - great advice. Helped me with a problem for a list implementation. Using recursion I was traversing the list by using the previous/next-pointers in each node to get the previous/next. I was getting a segmentation fault after a recursive call right after the last node in my list. I found out that the recursion keeps calling previous/next and since the pointer is not set to NULL, I was getting garbage data and passing it again and again to my recursive function. Again: A really helpful advice! – rbaleksandar Nov 05 '13 at 22:29
10

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.

Peeter Joot
  • 7,848
  • 7
  • 48
  • 82
  • 2
    This is a brilliant hack. I would love to see advice on different syscalls to validate memory ranges, especially if they can be guaranteed not to have side effects. You could keep a file descriptor open to write to /dev/null to test if buffers are in readable memory, but there are probably simpler solutions. The best I can find is symlink(ptr,"") which will set errno to 14 on a bad address or 2 on a good address, but kernel changes could swap the order of verification. – Preston Crow Feb 21 '20 at 18:55
  • 1
    @Preston In DB2 I think we used to use unistd.h's access(). I used open() above because it's a bit less obscure, but you are probably right that there are a lot of possible syscalls to use. Windows used to have an explicit pointer check API, but it turned out to not be thread safe (I think it used SEH to try to write and then restore the bounds of the memory range.) – Peeter Joot Feb 22 '20 at 02:46
  • I've compiled your code with both open() and access(). Both work, and access() should indeed be faster. – Michał Leon Jun 06 '21 at 12:07
  • This only checks to see if the pointer is an addressable `char*`. It won't check if it is a valid `double*`, because of alignment issues. If you did `char good[13]; double* f = (double)&good; if (!isPointerBad(f)) *f = 3.1415`, I think you will still get a SIGBUS on many systems. The alignment of the double pointer may need to be aligned to an address modulo 8. – Mark Lakata May 25 '23 at 18:01
7

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.

Fredrik
  • 5,759
  • 2
  • 26
  • 32
  • Probably another way is to use [_CrtIsValidHeapPointer](http://msdn.microsoft.com/en-US/library/ys6cfhhh%28v=VS.80%29.aspx). This function will return TRUE if the pointer is valid, and throw an exception when the pointer is freed. As documented, this function is only available in debug CRT. – Reci Nov 23 '11 at 15:01
5

I've got a lot of sympathy with your question, as I'm in an almost identical position myself. I appreciate what a lot of the replies are saying, and they are correct - the routine supplying the pointer should be providing a valid pointer. In my case, it is almost inconceivable that they could have corrupted the pointer - but if they had managed, it would be MY software that crashes, and ME that would get the blame :-(

My requirement isn't that I continue after a segmentation fault - that would be dangerous - I just want to report what happened to the customer before terminating so that they can fix their code rather than blaming me!

This is how I've found to do it (on Windows): http://www.cplusplus.com/reference/clibrary/csignal/signal/

To give a synopsis:

#include <signal.h>

using namespace std;

void terminate(int param)
/// Function executed if a segmentation fault is encountered during the cast to an instance.
{
  cerr << "\nThe function received a corrupted reference - please check the user-supplied  dll.\n";
  cerr << "Terminating program...\n";
  exit(1);
}

...
void MyFunction()
{
    void (*previous_sigsegv_function)(int);
    previous_sigsegv_function = signal(SIGSEGV, terminate);

    <-- insert risky stuff here -->

    signal(SIGSEGV, previous_sigsegv_function);
}

Now this appears to behave as I would hope (it prints the error message, then terminates the program) - but if someone can spot a flaw, please let me know!

Sebastian Mach
  • 38,570
  • 8
  • 95
  • 130
Mike Sadler
  • 1,750
  • 1
  • 20
  • 37
  • Do not use `exit()`, it circumvents RAII and thus may cause resource leaks. – Sebastian Mach May 09 '12 at 11:30
  • Interesting - is there another way of terminating neatly in this situation? And is the exit statement the only problem with doing it like this? I notice I've acquired a "-1" - is that just because of the 'exit'? – Mike Sadler May 09 '12 at 11:46
  • Oops, I realise this is for a pretty exceptional situation. I just saw `exit()` and my Portable C++ Alarm Bell began ringing. It should be okay in this Linux specific situation, where your program would exit anyways, sorry for the noise. – Sebastian Mach May 09 '12 at 12:15
  • Thanks, phresnel - that gets me back up to 0! I'm now using this approach in code that is intended to go into production code, so if there is a problem with it, I definitely need to have it pointed out! – Mike Sadler May 09 '12 at 13:47
  • 1
    signal(2) isn't portable. Use sigaction(2). `man 2 signal` on Linux has a paragraph explaining why. – rptb1 Oct 22 '15 at 13:22
  • 1
    In this situation I'd usually call abort(3) rather than exit(3) because it is more likely to produce some kind of debugging backtrace that you can use to diagnose the problem post-mortem. On most Unixen, abort(3) will dump core (if core dumps are allowed) and on Windows it will offer to launch a debugger if installed. – rptb1 Oct 22 '15 at 13:24
  • We are actually now using _controlfp_s on Windows, and sigaction on Linux. We've added a lot of whistles and bells to this, so that it can catch and identify a specified range of errors, such as floating point errors. – Mike Sadler Nov 22 '21 at 09:46
5

Firstly, I don't see any point in trying to protect yourself from the caller deliberately trying to cause a crash. They could easily do this by trying to access through an invalid pointer themselves. There are many other ways - they could just overwrite your memory or the stack. If you need to protect against this sort of thing then you need to be running in a separate process using sockets or some other IPC for communication.

We write quite a lot of software that allows partners/customers/users to extend functionality. Inevitably any bug gets reported to us first so it is useful to be able to easily show that the problem is in the plug-in code. Additionally there are security concerns and some users are more trusted than others.

We use a number of different methods depending on performance/throughput requirements and trustworthyness. From most preferred:

  • separate processes using sockets (often passing data as text).

  • separate processes using shared memory (if large amounts of data to pass).

  • same process separate threads via message queue (if frequent short messages).

  • same process separate threads all passed data allocated from a memory pool.

  • same process via direct procedure call - all passed data allocated from a memory pool.

We try never to resort to what you are trying to do when dealing with third party software - especially when we are given the plug-ins/library as binary rather than source code.

Use of a memory pool is quite easy in most circumstances and needn't be inefficient. If YOU allocate the data in the first place then it is trivial to check the pointers against the values you allocated. You could also store the length allocated and add "magic" values before and after the data to check for valid data type and data overruns.

Dipstick
  • 9,854
  • 2
  • 30
  • 30
2

Indeed, something could be done under specific occasion: for example if you want to check whether a string pointer string is valid, using write(fd, buf, szie) syscall can help you do the magic: let fd be a file descriptor of temporary file you create for test, and buf pointing to the string you are tesing, if the pointer is invalid write() would return -1 and errno set to EFAULT which indicating that buf is outside your accessible address space.

Vince.Wu
  • 870
  • 1
  • 10
  • 17
2

There are no provisions in C++ to test for the validity of a pointer as a general case. One can obviously assume that NULL (0x00000000) is bad, and various compilers and libraries like to use "special values" here and there to make debugging easier (For example, if I ever see a pointer show up as 0xCECECECE in visual studio I know I did something wrong) but the truth is that since a pointer is just an index into memory it's near impossible to tell just by looking at the pointer if it's the "right" index.

There are various tricks that you can do with dynamic_cast and RTTI such to ensure that the object pointed to is of the type that you want, but they all require that you are pointing to something valid in the first place.

If you want to ensure that you program can detect "invalid" pointers then my advice is this: Set every pointer you declare either to NULL or a valid address immediately upon creation and set it to NULL immediately after freeing the memory that it points to. If you are diligent about this practice, then checking for NULL is all you ever need.

Toji
  • 33,927
  • 22
  • 105
  • 115
  • 1
    A null pointer constant in C++ (or C, for that matter), is represented by a constant integral zero. Lots of implementations use all-binary-zeros to represent it, but it's not something to count on. – David Thornley Feb 18 '09 at 20:13
2

Setting the pointer to NULL before and after using is a good technique. This is easy to do in C++ if you manage pointers within a class for example (a string):

class SomeClass
{
public:
    SomeClass();
    ~SomeClass();

    void SetText( const char *text);
    char *GetText() const { return MyText; }
    void Clear();

private:
    char * MyText;
};


SomeClass::SomeClass()
{
    MyText = NULL;
}


SomeClass::~SomeClass()
{
    Clear();
}

void SomeClass::Clear()
{
    if (MyText)
        free( MyText);

    MyText = NULL;
}



void SomeClass::Settext( const char *text)
{
    Clear();

    MyText = malloc( strlen(text));

    if (MyText)
        strcpy( MyText, text);
}
Tim Ring
  • 1,845
  • 1
  • 20
  • 27
  • Updated question makes my answer wrong, of course (or at least an answer to another question). I agree with the answers that basically say, let them crash if they abuse th api. You can't stop people hitting themselves in the thumb with a hammer... – Tim Ring Feb 15 '09 at 23:02
2

Peeter Joos answer is pretty good. Here is an "official" way to do it:

#include <sys/mman.h>
#include <stdbool.h>
#include <unistd.h>

bool is_pointer_valid(void *p) {
    /* get the page size */
    size_t page_size = sysconf(_SC_PAGESIZE);
    /* find the address of the page that contains p */
    void *base = (void *)((((size_t)p) / page_size) * page_size);
    /* call msync, if it returns non-zero, return false */
    int ret = msync(base, page_size, MS_ASYNC) != -1;
    return ret ? ret : errno != ENOMEM;
}
Tyler Durden
  • 11,156
  • 9
  • 64
  • 126
1

The SEI CERT C Coding Standard recommendation MEM10-C. Define and use a pointer validation function says it is possible to do a check to some degree, especially under Linux OS.

The method described in the link is to keep track of the highest memory address returned by malloc and add a function that tests if someone tries to use a pointer greater than that value. It is probably of limited use.

Simon Kissane
  • 4,373
  • 3
  • 34
  • 59
Marek Szanyi
  • 2,348
  • 2
  • 22
  • 28
1

It's unbelievable how much misleading information you can read in articles above...

And even in microsoft msdn documentation IsBadPtr is claimed to be banned. Oh well - I prefer working application rather than crashing. Even if term working might be working incorrectly (as long as end-user can continue with application).

By googling I haven't found any useful example for windows - found a solution for 32-bit apps,

http://www.codeproject.com/script/Content/ViewAssociatedFile.aspx?rzp=%2FKB%2Fsystem%2Fdetect-driver%2F%2FDetectDriverSrc.zip&zep=DetectDriverSrc%2FDetectDriver%2Fsrc%2FdrvCppLib%2Frtti.cpp&obid=58895&obtid=2&ovid=2

but I need also to support 64-bit apps, so this solution did not work for me.

But I've harvested wine's source codes, and managed to cook similar kind of code which would work for 64-bit apps as well - attaching code here:

#include <typeinfo.h>   

typedef void (*v_table_ptr)();   

typedef struct _cpp_object   
{   
    v_table_ptr*    vtable;   
} cpp_object;   



#ifndef _WIN64
typedef struct _rtti_object_locator
{
    unsigned int signature;
    int base_class_offset;
    unsigned int flags;
    const type_info *type_descriptor;
    //const rtti_object_hierarchy *type_hierarchy;
} rtti_object_locator;
#else

typedef struct
{
    unsigned int signature;
    int base_class_offset;
    unsigned int flags;
    unsigned int type_descriptor;
    unsigned int type_hierarchy;
    unsigned int object_locator;
} rtti_object_locator;  

#endif

/* Get type info from an object (internal) */  
static const rtti_object_locator* RTTI_GetObjectLocator(void* inptr)  
{   
    cpp_object* cppobj = (cpp_object*) inptr;  
    const rtti_object_locator* obj_locator = 0;   

    if (!IsBadReadPtr(cppobj, sizeof(void*)) &&   
        !IsBadReadPtr(cppobj->vtable - 1, sizeof(void*)) &&   
        !IsBadReadPtr((void*)cppobj->vtable[-1], sizeof(rtti_object_locator)))  
    {  
        obj_locator = (rtti_object_locator*) cppobj->vtable[-1];  
    }  

    return obj_locator;  
}  

And following code can detect whether pointer is valid or not, you need probably to add some NULL checking:

    CTest* t = new CTest();
    //t = (CTest*) 0;
    //t = (CTest*) 0x12345678;

    const rtti_object_locator* ptr = RTTI_GetObjectLocator(t);  

#ifdef _WIN64
    char *base = ptr->signature == 0 ? (char*)RtlPcToFileHeader((void*)ptr, (void**)&base) : (char*)ptr - ptr->object_locator;
    const type_info *td = (const type_info*)(base + ptr->type_descriptor);
#else
    const type_info *td = ptr->type_descriptor;
#endif
    const char* n =td->name();

This gets class name from pointer - I think it should be enough for your needs.

One thing which I'm still afraid is performance of pointer checking - in code snipet above there is already 3-4 API calls being made - might be overkill for time critical applications.

It would be good if someone could measure overhead of pointer checking compared for example to C#/managed c++ calls.

TarmoPikaro
  • 4,723
  • 2
  • 50
  • 62
1

these links may be helpful

_CrtIsValidPointer Verifies that a specified memory range is valid for reading and writing (debug version only). http://msdn.microsoft.com/en-us/library/0w1ekd5e.aspx

_CrtCheckMemory Confirms the integrity of the memory blocks allocated in the debug heap (debug version only). http://msdn.microsoft.com/en-us/library/e73x0s4b.aspx

Khachatur
  • 921
  • 1
  • 12
  • 30
1

Following does work in Windows (somebody suggested it before):

 static void copy(void * target, const void* source, int size)
 {
     __try
     {
         CopyMemory(target, source, size);
     }
     __except(EXCEPTION_EXECUTE_HANDLER)
     {
         doSomething(--whatever--);
     }
 }

The function has to be static, standalone or static method of some class. To test on read-only, copy data in the local buffer. To test on write without modifying contents, write them over. You can test first/last addresses only. If pointer is invalid, control will be passed to 'doSomething', and then outside the brackets. Just do not use anything requiring destructors, like CString.

melpomene
  • 84,125
  • 8
  • 85
  • 148
1

There isn't any portable way of doing this, and doing it for specific platforms can be anywhere between hard and impossible. In any case, you should never write code that depends on such a check - don't let the pointers take on invalid values in the first place.

1

In general, it's impossible to do. Here's one particularly nasty case:

struct Point2d {
    int x;
    int y;
};

struct Point3d {
    int x;
    int y;
    int z;
};

void dump(Point3 *p)
{
    printf("[%d %d %d]\n", p->x, p->y, p->z);
}

Point2d points[2] = { {0, 1}, {2, 3} };
Point3d *p3 = reinterpret_cast<Point3d *>(&points[0]);
dump(p3);

On many platforms, this will print out:

[0 1 2]

You're forcing the runtime system to incorrectly interpret bits of memory, but in this case it's not going to crash, because the bits all make sense. This is part of the design of the language (look at C-style polymorphism with struct inaddr, inaddr_in, inaddr_in6), so you can't reliably protect against it on any platform.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Tom
  • 10,689
  • 4
  • 41
  • 50
1

It is not a very good policy to accept arbitrary pointers as input parameters in a public API. It's better to have "plain data" types like an integer, a string or a struct (I mean a classical struct with plain data inside, of course; officially anything can be a struct).

Why? Well because as others say there is no standard way to know whether you've been given a valid pointer or one that points to junk.

But sometimes you don't have the choice - your API must accept a pointer.

In these cases, it is the duty of the caller to pass a good pointer. NULL may be accepted as a value, but not a pointer to junk.

Can you double-check in any way? Well, what I did in a case like that was to define an invariant for the type the pointer points to, and call it when you get it (in debug mode). At least if the invariant fails (or crashes) you know that you were passed a bad value.

// API that does not allow NULL
void PublicApiFunction1(Person* in_person)
{
  assert(in_person != NULL);
  assert(in_person->Invariant());

  // Actual code...
}

// API that allows NULL
void PublicApiFunction2(Person* in_person)
{
  assert(in_person == NULL || in_person->Invariant());

  // Actual code (must keep in mind that in_person may be NULL)
}
Daniel Daranas
  • 22,454
  • 9
  • 63
  • 116
  • 1
    re: "pass a plain data type ... like a string" But in C++ strings are most often passed as pointers to characters, (char*) or (const char*), so you are back to passing pointers. And your example passes in_person as a reference, not as a pointer, so the comparison (in_person != NULL) implies there is some object/pointer comparisons defined in the Person class. – Jesse Chisholm Apr 24 '14 at 14:43
  • @JesseChisholm By string I meant a string, i.e. an std::string. In no way am I recommending using char * as a way to store strings or pass them around. Don't do that. – Daniel Daranas Apr 24 '14 at 14:50
  • @JesseChisholm For some reason, I made a mistake when I answered this question five years ago. Clearly, it doesn't make sense to check if a Person& is NULL. That wouldn't even compile. I was meaning to use pointers, not references. I fixed it now. – Daniel Daranas Apr 24 '14 at 14:51
1

As others have said, you can't reliably detect an invalid pointer. Consider some of the forms an invalid pointer might take:

You could have a null pointer. That's one you could easily check for and do something about.

You could have a pointer to somewhere outside of valid memory. What constitutes valid memory varies depending on how the run-time environment of your system sets up the address space. On Unix systems, it is usually a virtual address space starting at 0 and going to some large number of megabytes. On embedded systems, it could be quite small. It might not start at 0, in any case. If your app happens to be running in supervisor mode or the equivalent, then your pointer might reference a real address, which may or may not be backed up with real memory.

You could have a pointer to somewhere inside your valid memory, even inside your data segment, bss, stack or heap, but not pointing at a valid object. A variant of this is a pointer that used to point to a valid object, before something bad happened to the object. Bad things in this context include deallocation, memory corruption, or pointer corruption.

You could have a flat-out illegal pointer, such as a pointer with illegal alignment for the thing being referenced.

The problem gets even worse when you consider segment/offset based architectures and other odd pointer implementations. This sort of thing is normally hidden from the developer by good compilers and judicious use of types, but if you want to pierce the veil and try to outsmart the operating system and compiler developers, well, you can, but there is not one generic way to do it that will handle all of the issues you might run into.

The best thing you can do is allow the crash and put out some good diagnostic information.

John Grieggs
  • 226
  • 2
  • 2
  • re: "put out some good diagnostic information", there's the rub. Since you can't check for pointer validity, the information you have to fuss about is minimal. "An exception happened here," may be all you get. The entire call stack is nice, but requires a better framework than most C++ run time libraries provide. – Jesse Chisholm Apr 24 '14 at 14:34
  • "you can't reliably detect an invalid pointer" => this really depends on how you define "valid pointer". For some purposes, a "valid pointer" is "a pointer I can read from without crashing". Imagine you have a scripting language, and it has an FFI module, and as part of that module, you have a `read_arbitrary_memory_address` function. You would like to detect addresses which will make that function crash, so you can return a nice error message instead of crashing, and that may be easier than catching `SIGSEGV`/etc. Whether the data at the address is "valid" is the caller's problem – Simon Kissane Jan 02 '23 at 22:09
1

On Windows I use this code:

void * G_pPointer = NULL;
const char * G_szPointerName = NULL;
void CheckPointerIternal()
{
    char cTest = *((char *)G_pPointer);
}
bool CheckPointerIternalExt()
{
    bool bRet = false;

    __try
    {
        CheckPointerIternal();
        bRet = true;
    }
    __except (EXCEPTION_EXECUTE_HANDLER)
    {
    }

    return  bRet;
}
void CheckPointer(void * A_pPointer, const char * A_szPointerName)
{
    G_pPointer = A_pPointer;
    G_szPointerName = A_szPointerName;
    if (!CheckPointerIternalExt())
        throw std::runtime_error("Invalid pointer " + std::string(G_szPointerName) + "!");
}

Usage:

unsigned long * pTest = (unsigned long *) 0x12345;
CheckPointer(pTest, "pTest"); //throws exception
Artkov
  • 11
  • 2
1

On macOS, you can do this with mach_vm_region, which as well as telling you if a pointer is valid, also lets you validate what access you have to the memory to which the pointer points (read/write/execute). I provided sample code to do this in my answer to another question:

#include <mach/mach.h>
#include <mach/mach_vm.h>
#include <stdio.h>
#include <stdbool.h>

bool ptr_is_valid(void *ptr, vm_prot_t needs_access) {
    vm_map_t task = mach_task_self();
    mach_vm_address_t address = (mach_vm_address_t)ptr;
    mach_vm_size_t size = 0;
    vm_region_basic_info_data_64_t info;
    mach_msg_type_number_t count = VM_REGION_BASIC_INFO_COUNT_64;
    mach_port_t object_name;
    kern_return_t ret = mach_vm_region(task, &address, &size, VM_REGION_BASIC_INFO_64, (vm_region_info_t)&info, &count, &object_name);
    if (ret != KERN_SUCCESS) return false;
    return ((mach_vm_address_t)ptr) >= address && ((info.protection & needs_access) == needs_access);
}

#define TEST(ptr,acc) printf("ptr_is_valid(%p,access=%d)=%d\n", (void*)(ptr), (acc), ptr_is_valid((void*)(ptr),(acc)))

int main(int argc, char**argv) {
    TEST(0,0);
    TEST(0,VM_PROT_READ);
    TEST(123456789,VM_PROT_READ);
    TEST(main,0);
    TEST(main,VM_PROT_READ);
    TEST(main,VM_PROT_READ|VM_PROT_EXECUTE);
    TEST(main,VM_PROT_EXECUTE);
    TEST(main,VM_PROT_WRITE);
    TEST((void*)(-1),0);
    return 0;
}
Simon Kissane
  • 4,373
  • 3
  • 34
  • 59
0

IsBadReadPtr(), IsBadWritePtr(), IsBadCodePtr(), IsBadStringPtr() for Windows.
These take time proportional to the length of the block, so for sanity check I just check the starting address.

pngaz
  • 377
  • 2
  • 10
  • 3
    you should avoid these methods because they do not work. http://blogs.msdn.com/oldnewthing/archive/2006/09/27/773741.aspx – JaredPar Feb 15 '09 at 16:02
  • Sometimes their might be work-arounds to their not working: http://stackoverflow.com/questions/496034/most-efficient-replacement-for-isbadreadptr – ChrisW Feb 15 '09 at 17:22
0

I have seen various libraries use some method to check for unreferenced memory and such. I believe they simply "override" the memory allocation and deallocation methods (malloc/free), which has some logic that keeps track of the pointers. I suppose this is overkill for your use case, but it would be one way to do it.

sebnow
  • 1,380
  • 12
  • 11
0

Technically you can override operator new (and delete) and collect information about all allocated memory, so you can have a method to check if heap memory is valid. but:

  1. you still need a way to check if pointer is allocated on stack ()

  2. you will need to define what is 'valid' pointer:

a) memory on that address is allocated

b) memory at that address is start address of object (e.g. address not in the middle of huge array)

c) memory at that address is start address of object of expected type

Bottom line: approach in question is not C++ way, you need to define some rules which ensure that function receives valid pointers.

0

There is no way to make that check in C++. What should you do if other code passes you an invalid pointer? You should crash. Why? Check out this link: http://blogs.msdn.com/oldnewthing/archive/2006/09/27/773741.aspx

zildjohn01
  • 11,339
  • 6
  • 52
  • 58
0

Addendum to the accpeted answer(s):

Assume that your pointer could hold only three values -- 0, 1 and -1 where 1 signifies a valid pointer, -1 an invalid one and 0 another invalid one. What is the probability that your pointer is NULL, all values being equally likely? 1/3. Now, take the valid case out, so for every invalid case, you have a 50:50 ratio to catch all errors. Looks good right? Scale this for a 4-byte pointer. There are 2^32 or 4294967294 possible values. Of these, only ONE value is correct, one is NULL, and you are still left with 4294967292 other invalid cases. Recalculate: you have a test for 1 out of (4294967292+ 1) invalid cases. A probability of 2.xe-10 or 0 for most practical purposes. Such is the futility of the NULL check.

dirkgently
  • 108,024
  • 16
  • 131
  • 187
0

You know, a new driver (at least on Linux) that is capable of this probably wouldn't be that hard to write.

On the other hand, it would be folly to build your programs like this. Unless you have some really specific and single use for such a thing, I wouldn't recommend it. If you built a large application loaded with constant pointer validity checks it would likely be horrendously slow.

dicroce
  • 45,396
  • 28
  • 101
  • 140
  • I don't understand why you would need a driver on Linux for this? `/proc/self/maps` already tells you the mapped memory regions for the current process, you can just parse that (virtual) file and check if the pointer address is in one of the mapped regions. If you need a higher performance solution than parsing a text file (which you can cache if you assume memory mappings rarely change), you can use hacks like those in answer https://stackoverflow.com/a/50593933 – so it is unclear how a custom driver would be useful – Simon Kissane Jan 03 '23 at 22:53
  • Cool. Didn't know about /proc/self/maps. Good to know. – dicroce Jan 04 '23 at 13:13
-1

you should avoid these methods because they do not work. blogs.msdn.com/oldnewthing/archive/2006/09/27/773741.aspx – JaredPar Feb 15 '09 at 16:02

If they don't work - next windows update will fix it ? If they don't work on concept level - function will be probably removed from windows api completely.

MSDN documentation claim that they are banned, and reason for this is probably flaw of further design of application (e.g. generally you should not eat invalid pointers silently - if you're in charge of design of whole application of course), and performance/time of pointer checking.

But you should not claim that they does not work because of some blog. In my test application I've verified that they do work.

TarmoPikaro
  • 4,723
  • 2
  • 50
  • 62