16

I want to know if a pointer points to a piece of memory allocated with malloc/new. I realize that the answer for an arbitrary address is "No you can't" but I do think it is possible to override malloc/free and keep track of allocated memory ranges.

Do you know a memory management library providing this specific tool?
Do you know something for production code?

Valgrind is great, but it is too much instrumentation (slow) and as Will said we don't want to use Valgrind like this (making the soft crash is good enough).
Mudflap is a very good solution, but dedicated to GCC, and sadly, a check does not simply return a boolean (see my answer below).
Note that checking that memory writes are legal is a security issue. So looking for performance is motivated.

log0
  • 10,489
  • 4
  • 28
  • 62
  • +1, this is crucial question for a need to test that POD memory (i.e. without constructors & destructors) gets allocated and deallocated properly. I guess C++ library in its heap management mechanisms has the answer, because it needs to track the allocated memory blocks and their sizes. But I don't know whether it exposes such data (and if not, whether it's possible to intrude to get the data) - I'm looking for an answer. – Serge Rogatch Jan 28 '15 at 08:47
  • Why do you need it exactly? Do know if the pointer is valid or to know if it is a heap pointer in general? – Paweł Bylica Aug 25 '16 at 10:05

10 Answers10

13

A proof it probably cannot be usefully done:

char * p1 = malloc(1);
free( p1 );
char * p2 = malloc(1);   // probably allocates same block as first malloc

Now both p1 and p2 point at same memory on heap, but only p2 is valid.

  • 7
    Well philosophically it can be disappointing, but if it ends up p2 points to the same address that p1, p1 is still an address of modifiable memory. So that's fine for me. – log0 Jun 17 '10 at 20:08
  • 1
    @Ugo even though both the C and C++ standards say p1 may not be used to access that memory? –  Jun 17 '10 at 20:15
  • 1
    Weeeeel maybe p2 is the same address as p1... depends on how your malloc works (running under valgrind will pretty much guarantee `p2 != p1` this is on purpose so you can detect use after free, but good malloc's still may or may not (some of them maintain FIFO queues of recently free'd objects of a certain size, they won't give back p1...)) – Spudd86 Jun 17 '10 at 20:17
  • @Neil the standard does NOT say p2 will be the same address as p1 (it's just somewhat probable) and at that point you're just nit picking because the question was about addresses not particular allocations so if `p1 == p2` then by the definition in the question the answer "p1 is heap alloc'd" is acceptable. – Spudd86 Jun 17 '10 at 20:20
  • 1
    Taking this further: what if, through some arbitrary sequence of events, the address pointed to be the old pointer p1 ends up in the middle of a newly allocated block instead of exactly matching p2? Then p1 could still be said to point at part of the heap, but p1 by itself wouldn't be useful in any reasonable way that I can imagine. – TheUndeadFish Jun 17 '10 at 20:21
  • @spudd I did say "probably", but substitute "possibly" if you prefer - in portable code you can't tell, and even if a FIFO is used, the same address will be returned if this is the first use of malloc & free in the code. –  Jun 17 '10 at 20:21
  • @spudd "the standard does NOT say p2 will be the same address as p1" - I didn't say it did. –  Jun 17 '10 at 20:22
  • 1
    Besides the fact that you shouldn't do this or rely on this behavior, I'm not seeing how this answers the question ... Maybe I missed something. – BobbyShaftoe Jun 17 '10 at 23:51
  • 1
    After free(p1) it is undefined behaviour to even use the value of the pointer, i.e. comparing it with p2 is already UB. – Secure Jun 18 '10 at 06:16
  • @BobbyShaftoe: Obviously you wouldn't rely on any of that behavior, but it is possible. It's a demonstration of how an invalid pointer could, by chance, point to something in an allocated block of memory. Since that's possible, it's impossible to tell whether a pointer is valid based on its value. TheUndeadFish's comment is relevant here: a pointer could easily point into something completely different. – David Thornley Jun 18 '10 at 13:42
  • Common, pointers are addresses. Not mystical objects keeping souls of their preceding lives. A pointer pointing to allocated memory is valid whatever happend when she was a child. – log0 Jun 19 '10 at 10:36
  • 1
    (Late comer to this comment stream) Any access by p1 after this code is erroneous. Most analysis tools won't catch this. Our CheckPointer tool *will* catch any indirect access through p1 after this code executes. See my answer in this thread. – Ira Baxter Jun 22 '11 at 03:56
  • 1
    @log0 Pointers are not addresses. After being freed, the value of the pointer p1 becomes indeterminate, as per standard. Reading it will cause undefined behavior. – 2501 Aug 26 '16 at 05:56
  • I wouldn't call this “a proof”. A proof would be calling every function exposed in your platform's `malloc.h` and showing that the results from pointer to malloc-allocated memory and a pointer to stack-allocated memory are indistinguishable. Trying one thing does not make it a proof. – Slipp D. Thompson Jan 04 '23 at 00:03
10

There's no standard way to do this, but various malloc debugging tools may have a way of doing it. For example, if you use valgrind, you can use VALGRIND_CHECK_MEM_IS_ADDRESSABLE to check this and related things

Chris Dodd
  • 119,907
  • 13
  • 134
  • 226
  • Nice ! I didn't know linking with a library was not standard though ;) – log0 Jun 17 '10 at 20:23
  • 1
    @Ugo Arguably, linking with a library is not standard. But that aside, what is in libraries used by tools such as valgrind is definitely non-standard, which is why they are platform specific. –  Jun 17 '10 at 20:39
  • @Neil Why would linking with a library not be standard ? – matias Jun 17 '10 at 21:03
  • 1
    @matias Neither the C++ nor the C standard really describes such a thing - but that is off the point of this question. –  Jun 17 '10 at 21:10
  • @matias Neither the C++ nor the C standard really describes breadth first search, which means it is arguably not standard. – log0 Jun 17 '10 at 21:13
  • @Ugo -- the library is not necessarily be available on every platform that supports C or C++, so its not "standard" – Chris Dodd Jun 17 '10 at 22:24
  • 2
    if you're using valgrind, you don't check things are addressable you just let valgrind explode when you have a bug, and you fix it :) – Will Jun 18 '10 at 07:02
  • @Ugo: the standard describes the mechanisms used to implement a breadth first search. it does not describe the mechanisms used to implement library functionality. It describes how multiple translation units are turned into one program, but it doesn't describe *any* mechanism* by which separate libraries can be created, or loaded by your application. – jalf Jun 18 '10 at 13:09
  • 1
    @Neil/jalf/Chris Well you are right linking is not standardized but you are still doing standard c++. Same thing with platform specific code, assigning the video frame buffer address somewhere in your code doesn't make your code non standard it just makes it platform specific. – log0 Jun 18 '10 at 13:24
  • @Ugo: I can easily write a breadth-first search algorithm in standard C++ (C would be a little more difficult, not having STL containers, `std::deque` in particular). valgrind is not necessarily available with a standard C++ platform, and cannot be written in standard C++. Therefore, in any standard C++ implementation I've got breadth-first search, but not necessarily valgrind. – David Thornley Jun 18 '10 at 13:55
  • @David you mean std::queue don't you ? – log0 Jun 19 '10 at 10:07
  • @Ugo: I was thinking std::deque at the time, for some reason, but std::queue is a much better choice. Thanks. – David Thornley Jun 21 '10 at 15:08
5

You can do this yourself, if performance is not a real issue for your application:

Define MyMalloc(...) and MyFree(...) in which, along with calling malloc/free, you update a (ordered)list of pairs {address -- the result of malloc, blockSize -- the amt of memory requested }. Then when you need to check a pointer p, you look for a pair satisfying: address <= p <= address + blockSize.

Other conditions could/should be checked, if you want to actually use that pointer, this will only tell if an address is in use or not.

Andy
  • 3,631
  • 2
  • 23
  • 32
3

On macOS/Darwin, yes you can.

Pass your pointer to malloc_zone_from_ptr(…); if it gives you NULL back, it wasn't allocated with any variant of malloc/calloc/etc.

This is the same mechanism that's used spit out a “*** error for object %p: pointer being freed was not allocated” and SIGABRT when you try to free() a non-malloc'd pointer. See Darwin's malloc.c

Here's some test code:

#include <malloc/malloc.h>

…

int *mallocAllocated = (int *)malloc(16);
int *newAllocated = new int[16];
int stackAllocated[16];

printf("mallocAllocated allocated with malloc: %s\n",
    (malloc_zone_from_ptr(mallocAllocated) != NULL) ? "yes" : "no");
printf("newAllocated allocated with malloc: %s\n",
    (malloc_zone_from_ptr(newAllocated) != NULL) ? "yes" : "no");
printf("stackAllocated allocated with malloc: %s\n",
    (malloc_zone_from_ptr(stackAllocated) != NULL) ? "yes" : "no");

free(mallocAllocated);
free(newAllocated);
free(stackAllocated); // aborts with SIGABRT here

outputs:

mallocAllocated allocated with malloc: yes
newAllocated allocated with malloc: yes
stackAllocated allocated with malloc: no

Caveat: Is this safe across all Darwin platforms and builds, and all types of memory allocation? No idea. All I know is what the source code and man malloc_zone_from_ptr says.

Why would you want to do this specifically on a macOS/«Apple»OS/Darwin system? Well, if you're playing around with stack-allocating Objective-C objects and you want to make sure you don't call [super dealloc] into NSObject's implementation, that would be one esoteric use-case.

Slipp D. Thompson
  • 33,165
  • 3
  • 43
  • 43
2

Mudflap (for gcc) seems very sweet. You have to compile your soft with but it will check any wrong pointer access (heap/stack/static). It is designed to work for production code with slowdown estimated between x1.5 to x5. You can also disable check at read access for speedup.
User check can be performed using

void __mf_check (void *ptr, __mf_size_t sz, int type, const char *location)

Calling this function results to: nothing, fork to gdb, segv or abort depending on environment parameters.

log0
  • 10,489
  • 4
  • 28
  • 62
1

You can use LD_PRELOAD, and wrap malloc inside your own function.

Daniel Băluţă
  • 1,255
  • 11
  • 13
1

See our CheckPointer tool, which will check every pointer access for validity. Its not particularly fast, but it will catch errors that even Valgrind wont catch (e.g., pointers to deallocated stack frames, etc.)

Another answer to this question shows a case where doing pure memory range checking on pointer validity would fail to detect a problem. He's sort of right, in that if only have memory range addresses you can't reliably check that a reallocated block of store is misused. This is called a temporal error. By associating the allocation event with the memory block as well as the range, you can detect this. And Checkpointer does this, and will detect the error.

Community
  • 1
  • 1
Ira Baxter
  • 93,541
  • 22
  • 172
  • 341
0

Memory allocations have an (virtual) address and a length.

The pointer only contains the address.

If you track the length separately, you can check its contained, e.g.:

int check_contained(const char* src,size_t srclen,const char* sub,size_t sublen) {
   return (sub >= src) && (sub+sublen < src+srclen);
}

Symbian has an AllocLen function, but there's no POSIX nor win32 equivalent.

Will
  • 73,905
  • 40
  • 169
  • 246
0

I did something similar, but can't remember how exactly it was coded and i don't have the code at hand.

But the basic idea was to override the new and delete for a base class. In new a static flag was set (e.g. bool inDynamicAlloc=true). This flag is questioned in the constructor of the base class. When it was true, the object was allocated on the heap, on the stack otherwise.

The constructor resets the flag afterwards.

Hope this helps.

jopa
  • 1,109
  • 7
  • 6
0

You could use the same techniques that a conservative garbage collector uses to determine if a pointer-like object points to the heap or not. Indeed you could probably crib the source code from bdwgc itself. This would be a non-trivial task, but it would be something you could control and port as needed. (Much of the porting work has already been done, in fact.)

JUST MY correct OPINION
  • 35,674
  • 17
  • 77
  • 99