2

First of all I am not very familiar with the stack and heap.

In a lot of programs I see that pointers are checked for NULL. But that doesn't prevent a crazy address like 0x002011 to be passed.

My question: is there "safe" address interval, that I can check a pointer belongs to and be reasonably sure it's valid, before dereferencing it?

Matthew Murdoch
  • 30,874
  • 30
  • 96
  • 127
  • `NULL` is usually implemented as `#define NULL 0`. I prefer using C++0x `nullptr` which is an actual type representing an invalid pointer. – AJG85 Jul 18 '11 at 23:35
  • A Windows-specific view, but the underlying ideas are more generic: [IsBadXxxPtr should really be called CrashProgramRandomly](http://blogs.msdn.com/b/oldnewthing/archive/2006/09/27/773741.aspx) – MSalters Jul 19 '11 at 09:40

12 Answers12

8

No. Make sure to initialize pointers to NULL when creating a new variable, and then only change the value with malloc (when C) or new (when C++) or other allocating functions (or assigning to another valid pointer or NULL). Set back to NULL after free and delete respectively.

littleadv
  • 20,100
  • 2
  • 36
  • 50
  • This is correct, but sometimes it makes sense to create a mechanism to check whether a pointer is valid, such as when you're trying to make an API that's bulletproof. Typically, it involves a combination of two tricks. First, you call an OS-specific function to check whether the pointer is valid (or, similarly, dereference it in a try block or some other way to prevent a crash when the pointer is bad). Second, you place a flag value at a fixed offset, so that you can "sniff" whether it's pointed at what's expected. You could do both at once by enabling RTTI and checking it in a try block. – Steven Sudit Jul 18 '11 at 20:31
  • Agree in most if not all. I don't think that pointers need to be reset to NULL after freeing the allocated memory, the reason is that it creates a false sense of security and might confuse more than help (consider that if more than one pointer refer to the same object, delete/reset to NULL will apply only to one of them, and it will be confusing why, if you always reset to NULL you get an error while dereferencing a non-NULL pointer... – David Rodríguez - dribeas Jul 18 '11 at 20:41
  • @David - having several pointers pointing to the same place is entirely different problem:-) – littleadv Jul 18 '11 at 21:12
  • @David: It depends. If you're writing, say, a linked list and have a Remove() method, you're going to want to set a deleted pointer back to NULL. But if it's a local variable that's going out of scope anyhow, then not so much. Of course, both of these are good use cases for smart pointers. – Steven Sudit Jul 18 '11 at 23:08
  • @Steven Sudit: I understand what you say, but I see it from a different point of view. In the list example, you are not setting the pointer to NULL because you deleted it, but because the invariants of your list implementation require null termination. In particular, the GCC implementation of `std::list` never sets pointers to NULL (the implementation uses a different invariant: a sentinel object stored with the `list` object, in which case, removal from the list implies deleting but not setting to NULL. The reason for the NULL or not is related to the invariants of your code, not to deletion. – David Rodríguez - dribeas Jul 18 '11 at 23:22
  • 1
    @David: There's definitely a place for sentinel objects and null objects. My point is that NULL is the logical default value. If you're going to keep the pointer around, then it's safer to set it to a known value so that it either works or fails consistently than to leave it pointing at random memory, which could lead to more subtle bugs. – Steven Sudit Jul 19 '11 at 00:26
  • @Steven Sudit: Is it? Even in the single list that is null terminated, only while removing the last element you set the pointer to null, and that is only a side effect of the operation *update 'next' pointer that referred to removed object to be the value of then 'next' pointer in the removed object*, that is, the implementation will most probably not set it to null, but rather: `type* to_remove = node->next; node->next = node->next->next; delete to_remove;` The fact that the null termination means that `node->next->next` is null is irrelevant to the operation. – David Rodríguez - dribeas Jul 19 '11 at 11:00
  • ... the pointer is set to null *on construction*, before memory is actually acquired, and the invariant that the last element's `next` pointer is null is maintained thoughout the code without `delete ptr; ptr = 0;` being present in the code. Granted that there are a few corner cases where you want to manually set to null after deletion (for example, if you hold an *optional* element through a pointer, and you remove it, the invariant that null marks the element as not present must be maintained, and that requires setting to null, but again, that is an invariant of the design. – David Rodríguez - dribeas Jul 19 '11 at 11:04
  • @David: Realistically, I'd use a smart pointer, which means that it would set itself to null upon deletion, regardless. – Steven Sudit Jul 26 '11 at 00:54
3

NULL is a special value that is guaranteed to be an invalid pointer. Any other value could be valid.

David Heffernan
  • 601,492
  • 42
  • 1,072
  • 1,490
2

Everything except NULL that comes out of malloc and friends is a valid pointer, however crazy its value may seem to you. In fact, 0x002011 may be a perfectly valid pointer on some computers (although probably not modern-day desktops).

And a whole lot of pointers to properly-aligned, "sane-looking" addresses that still don't belong to your program. If you don't leave pointers uninitialized and don't manually set them to bullshit values, the only invalid pointer you'll have to watch out for is NULL. Alternatively, if this is for library code: Don't try to do this for your users, as you can't (if the above wasn't explicit enough), and it's their job anyway.

Matthew Murdoch
  • 30,874
  • 30
  • 96
  • 127
2

There's another case that hasn't been addressed here: writing a library function where you have no control over the parameters that are passed in and you want to ensure that your function returns a "bad pointer" type of error rather than crashing if a pointer to an invalid address is used.

If that's the case, then I think there are OS-specific functions that can give you the valid address range of the current process. You will also need to consider whether the address's alignment is valid for the data type being passed. E.g., if a 4-byte integer value can legally reside at an odd address where address%4 != 0.

Note that even if you take these precautions, there's still no guarantee that the caller won't pass a legal pointer to invalid data. The bottom line is that you can't fix a bug in the calling code.

Dave
  • 331
  • 1
  • 4
1

No, there isn't a (portable and reliable) way to detect whether a pointer is good.

NPE
  • 486,780
  • 108
  • 951
  • 1,012
1

No, that is not the right way to do things.

You should instead figure out why those crazy addresses are being passed in the first place. You should always either be passing a valid pointer that you've used new or malloc (or some variant of those) to create, or you should be passing the address of stack allocated objects.

Alex
  • 14,973
  • 13
  • 59
  • 94
1

A pointer is an implementation detail, not a contextual type. Therefore, "valid pointer value" is not a universal property of pointers; it is a property of the context in which the pointer is being used (or the abstraction the pointer is representing). For example, a pointer that points to something on a thread's stack is not a valid pointer to pass to free(...). If you can express the context in which a pointer is valid, then it is simply a matter of enumerating or matching against all pointers that are valid within that context to determine whether a pointer is valid (again, within that context).

MSN
  • 53,214
  • 7
  • 75
  • 105
0

No, there is not. If possible, use references that should always point to valid memory. Pointers are dangerous from their nature and that's why the higher level languages such as Java omit them altogether.

Actually, not even NULL is guaranteed to point to an invalid memory. It's just a convention that's being held but not backed by any standard AFAIK.

Karel Petranek
  • 15,005
  • 4
  • 44
  • 68
  • 2
    A NULL pointer is guaranteed by the standard to be invalid. It is not, however, guaranteed to point to address 0 specifically. – jalf Jul 18 '11 at 19:45
0

There's no way, as others have said.

But if there would be a way to know which addresses are in the address space of a process, then you could have a clue (if the address is "inside", it is not surely a good valid pointer; but if it is outside, for sure it is not valid).

Some possible checks are system dependent (the previous sentence too, indeed, assumes a specific "set" of modern systems); e.g. on many machines addresses must be word-aligned or alike, so that if you have an odd address (for a non-byte datum), you can suppose it is not valid pointer.

Though, these and other "reasonings" are not reliable (nor portable).

ShinTakezou
  • 9,432
  • 1
  • 29
  • 39
0

No, and this is why checking pointers against NULL, except when you have defined and documented that a function accepts NULL and attributes a special meaning to it, is utterly nonsensical. C does not make it possible to write functions which accept pointers but which are robust against the caller breaking the contract. If you don't like this, either don't use pointers or don't use C.

R.. GitHub STOP HELPING ICE
  • 208,859
  • 35
  • 376
  • 711
0

In Windows you could try using VirtualQuery function. It accepts a pointer (lpAddress) you want to test and returns the information about the page that contains the address, if it is a valid one.

If lpAddress specifies an address above the highest memory address accessible to the process, the function fails with ERROR_INVALID_PARAMETER.

This question might give you some starting point on Linux: Is there a better way than parsing /proc/self/maps to figure out memory protection?

Community
  • 1
  • 1
Vinicius Kamakura
  • 7,665
  • 1
  • 29
  • 43
0

No, For a pointer any value other than zero, could be a valid address. Therefore traditionally programmers have used NULL as the default invlaid value for a pointer.

However, if you are devloping a library where you need this facility then you can one of the following

  1. Allocate the memory needed by the library in the beginning. (Assuming you know the requirement beforehand). Use Custom Memory Manager which would use this chunk of memory to service memory allocation and free requests by the library. Any address which is beyond allocated memory ( { start address, start adress + size}) is an invalid pointer.

OR

  1. Develop custom memory manager, which keeps track of memory chunks allocated to different modules of the library. To check pointer validity it goes through its internal table to see if such a memory has been allocated or not.

Note: If performance is the issue then you can have a memory manager running in two modes, i.e. release and debug. Chuck the additional checking in the release version.

Opencore (in Android) does something similar to second approach.

Shash316

Shash316
  • 2,218
  • 18
  • 19