4

Is there any way to know if pointer is pointing to dynamically allocated memory or static allocated memory?

Array are passed as pointers to functions

void func (int* p)
{
  if( p )
  {
    cout << p[0] << p[1] ;
   ...
   // func has a responsibility to deallocate what p is pointing
  }
}

int main()
{
  int a[] = {10, 20, 30, 50};
  func(a);
  ...
  return 0;
}

If ownership for deallocation is transferred to func. How func p would know whether 'p' is pointing to dynamically allocated memory or static allocated memory ?

fuz
  • 88,405
  • 25
  • 200
  • 352
atulya
  • 535
  • 2
  • 8
  • 25

6 Answers6

4

You can't know this. This is by definition of your function. Prefer using smart pointers or you have to make pretty clear in your functions documentation that it takes over the ownership of your passed object or array.

HelloWorld
  • 2,392
  • 3
  • 31
  • 68
2

There is no portable way to find out if a pointer is pointing to dyanmically allocated memory or to statically allocated memory. It might be possible to deduct this information by carefully checking if the pointer points to one of the data or bss segments of any of the binary and shared libraries you have loaded in your program. Even then, the line between statically and dynamically allocated memory is blurry: Is memory that is part of a shared library loaded later on dynamic or static in your opinion?

fuz
  • 88,405
  • 25
  • 200
  • 352
1

First things first, it is the caller's responsibility to use the function with suitable arguments, and the coder's to make it explicit that this function would try do deallocate the pointer passed as argument.

Secondly, this is not a good practice to have some algorithm function managing memory. The main reason is that you might want to use it on a subset of an input. For example if you compute the sum of an array, you might want to be able to compute the sum of the subarray starting at index 3.

It is the caller's job to manage the memory, not yours. Just don't put any deallocation in a function that does something else.

Anyway, you can detect if the address is on the stack or not, see 1 However please note that not being on the stack doesn't mean that it was allocated on the heap, it could be pointing to some static data such as a string literal.

Community
  • 1
  • 1
Lectem
  • 503
  • 6
  • 19
0

You can't tell.

You should release memory in the "same sort of place" that you allocate it. Broadly this means that if the caller to a function allocates memory then that caller should release it. Similarly, if you provide a function to allocate memory, then provide another one to release it.

Some folk like to allocate memory in a function and make it the caller's responsibility to release it. But that can cause problems especially if the function is compiled separately to the caller; such as in a dll or shared object.

What you are proposing: deleting memory in a function that was allocated in the caller is the worst of all worlds. Don't do it.

Bathsheba
  • 231,907
  • 34
  • 361
  • 483
0

not only that you can't really know it, you can't even tell is a pointer is valid one.

int* x = 0xDEADBEEF;

clearly, most of the chances the pointer doesn't even point to a valid memory address.

but not all is lost. you can do all kinds of tricks to achieve this goal at least partialy. some of them include:

  1. create a memory pool and force anything dynamic to be allocated from there. then , with simple pointer arithmetics you can find out if the memory address is there
  2. overload global new and delete. unless some of your classes overload new and delete operators, you can catch most of the dynamic allocations. this will not work if you are using malloc.
  3. if you are on windows , and you're a winapi expert you might try hooking HeapAlloc and thus track some of memory addresses.
David Haim
  • 25,446
  • 3
  • 44
  • 78
-1
//***************************************************************//
//******************  try something like this  ******************//
//***************************************************************//

#include <stdlib.h>
#include <stdio.h>

// define one of these
// define LINUX
#define MACOS
// #define WINDOWS

#if defined LINUX || defined WINDOWS
#include <malloc.h>
#endif
#ifdef MACOS
#include <malloc/malloc.h>
#endif


// prototypes
int     freeable(void *ptr);
void    safe_free(void *ptr, const char *function, int line);


inline int freeable(void *ptr)
{
    size_t    sz;
#ifdef MACOS
    sz = malloc_size(ptr);
#endif
#ifdef LINUX
    sz = malloc_usable_size(ptr);
#endif
#ifdef WINDOWS
    sz = _msize(ptr);
#endif

    // fprintf(stderr, "freeable bytes = %ld\n", sz);
    if (sz)
        return(TRUE);

    return(FALSE);
}


void    safe_free(void *ptr, const char *function, int line)
{
    if (freeable(ptr) == FALSE) {
        if (ptr == NULL)
            fprintf(stderr, "%s(): Attempting to free NULL object [called from function %s(), line %d]\n\n", __FUNCTION__, function, line);
        else
            fprintf(stderr, "%s(): Attempting to free unallocated, statically allocated, or previously freed object [called from function %s(), line %d]\n\n", __FUNCTION__, function, line);
        return;
    }

    free(ptr);

    fprintf(stderr, "%s(): Successfully freed object [called from function %s(), line %d]\n\n", __FUNCTION__, function, line);

    return;
}


int main(int argc, char *argv[])
{
    void    *ptr;
    size_t  sz;

    ptr = NULL;
    fprintf(stderr, "\nfree NULL ptr:\n");
    safe_free(ptr, __FUNCTION__, __LINE__);

    ptr = (void *) "string";
    fprintf(stderr, "free static string:\n");
    safe_free(ptr, __FUNCTION__, __LINE__);

    ptr = (void *) 0x0123456789BCDEF;
    fprintf(stderr, "free unallocated ptr:\n");
    safe_free(ptr, __FUNCTION__, __LINE__);

    ptr = (void *) malloc(10);
    fprintf(stderr, "free allocated ptr:\n");
    safe_free(ptr, __FUNCTION__, __LINE__);

    fprintf(stderr, "free previously freed ptr:\n");
    safe_free(ptr, __FUNCTION__, __LINE__);

    return(0);
}