0

I wish to free blocks of memory which I don't have pointers to. In my program, I call malloc sequentially, hoping that the memory created by malloc(1), malloc(4), malloc(5) is continuous. Then I free these memory when I only have the pointer to malloc(5). But I can't think of how this can be done; I cannot simply create a pointer that reference to the address of ptr[-5] and then free 5 bytes of memory? How can this be done?

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

int main(){

    malloc(1);
    malloc(4);
    char* ptr = malloc(5);

    free(ptr);
}
JBL
  • 12,588
  • 4
  • 53
  • 84
Pippi
  • 2,451
  • 8
  • 39
  • 59
  • 5
    Why do you malloc in the wild like that in the first place? – JBL Sep 12 '14 at 16:12
  • 5
    Why? Just why? If you want contiguous memory, allocate it with one call to `malloc` and do some pointer arithmetic. This is just going to induce undefined behavior. – Dark Falcon Sep 12 '14 at 16:12
  • 3
    Hoping for memory allocations to be continuous seems quite optimistic :) – xlecoustillier Sep 12 '14 at 16:14
  • thanks for all the comments. It's not practical to assume that the memory is continuous. I really want a single call to malloc. – Pippi Sep 12 '14 at 16:20
  • 1
    It appears you are potentially want to something very interesting here but not providing the higher level details. What is the higher level goal? Forming a post with the higher level goal & details may give you want you want. – chux - Reinstate Monica Sep 12 '14 at 16:40
  • 1
    It seems you need to implement your own memory management on top of what the C Standard provides. – alk Sep 12 '14 at 16:48

6 Answers6

7

You cannot do what you want to do. You should not even try to do what you want to do.

Even if you work out exactly what malloc() is doing, your program would then be relying on undefined behavior. The behavior could change when a new version of the C library arrives, and your program would almost certainly fail if you compiled it using a different toolchain (switch from GNU C to Microsoft C or whatever).

Any time you allocate memory, you need to keep track of the pointer. If your program doesn't even know about the memory, there is no way to free it.

Keep track of your memory allocations. If you are designing data structures to be dynamically allocated, your design should include features to track them, such as keeping a list of addresses in a linked list or something.

If this seems like a lot of work, maybe consider using a managed language like C# or Java or Python or whatever.

steveha
  • 74,789
  • 21
  • 92
  • 117
  • 1
    Upvoted, but I'd add it's not just that you can't do it, there's no point to doing it. `malloc()` says 'give me some memory' and the return value is the address of the memory. If you immediately discard the return value, then you can't use the memory (let alone free it), so why ask for it in the first place? – abligh Sep 12 '14 at 16:19
  • Well, the example code on the question is just silly, but it seems likely that the actual program is doing stuff with the pointers and just not bothering to keep track of them. I've written trivial programs that call `malloc()` without bothering to keep track of the memory, since the program will of course release all its resources when it terminates. But my professional dynamic programs all track every allocation and I run Valgrind to make sure they never leak memory. http://stackoverflow.com/a/1529832/166949 – steveha Sep 12 '14 at 16:29
2

free(void*)

[deallocate] A block of memory previously allocated by a call to malloc, calloc or realloc is deallocated, making it available again for further allocations.

If ptr does not point to a block of memory allocated with the above functions, it causes undefined behavior. - http://www.cplusplus.com/reference/cstdlib/free/

There is no way.

AlexanderBrevig
  • 1,967
  • 12
  • 17
2

But I can't think of how this can be done

That's because it is not possible. The blocks that you get back from malloc can come in truly arbitrary order. The only way to free a dynamically allocated block of memory is to keep a pointer to it accessible to your program. Anything else is undefined behavior.

Note: Implementations of malloc perform "bookkeeping" to figure out what kind of block you are releasing. While it is not impossible to hack into their implementation, there is no way of doing it in a standard-compliant, portable way.

Sergey Kalinichenko
  • 714,442
  • 84
  • 1,110
  • 1,523
1

You cannot create a [-5]...thing for a variety of reasons but the from a practical standpoint you have to remember that memory allocated with malloc() is coming off of the heap and not the stack so to "count" to it from somewhere else is difficult (since multiple calls to malloc are not guaranteed to be sequential).

What happens when a pointer loses its association to memory (or goes out of scope) without being freed is called a memory leak and without exhaustive techniques not readily available in C (Java's mark/sweep garbage collection for example, or mallocing the entire memory and scanning it or something) it is not possible to reclaim this memory.

So you cannot free memory in C when a pointer is not known.

SubSevn
  • 1,008
  • 2
  • 10
  • 27
1

This is by no means an endorsement of what you have done, but it is possible assuming you know that the blocks were allocated continuously.

For example:

int main(){
  char* ptr1=malloc(1);
  char* ptr2=malloc(4);
  char* ptr3=malloc(5);

  // Verify that the memory is in fact continuous.
  assert(ptr3==(ptr2+4));
  assert(ptr3==(ptr1+5));

  free(ptr3);    // Frees 5 bytes at ptr3
  free(ptr3-4);  // Frees 4 bytes at ptr2
  free(ptr3-5);  // Frees 1 byte at ptr1 
}

So, you if you have a pointer and know for a fact that you allocated a set of continuous bytes before it, you can simply offset the pointer with pointer arithmetic. It is highly dangerous and not recommended, but it is possible.

Edit:

I ran a test program and on my architecture, it allocated in 32 byte chunks, so ptr1+32==ptr2, and ptr2+32=ptr3. It did this for any chunks less than or equal to 24 bytes. So if I allocated 24 or less, then each ptr would be 32 bytes greater than the previous. If I allocated 25 or more, then it allocated an additional 16 bytes, making the total 48.

So, in my architecture, you'd need to be much more creative in how you generate your pointers using pointer arithmetic since it will not work as expected.

Here is an example program that works for all sizes of ptr1, ptr2, and ptr3 on my architecture.

#define ROUNDUP(number, multiple) (((number + multiple -1)/multiple)*multiple)
#define OFFSET(size) ((size < 24) ? 32 : ROUNDUP(size+8,16))
int main(int argc, char* argv[]){

  char* ptr1, *ptr2, *ptr3;
  int s1=atoi(argv[1]);
  int s2=atoi(argv[2]);
  int s3=atoi(argv[3]);
  ptr1=(char*)malloc(s1);
  ptr2=(char*)malloc(s2);
  ptr3=(char*)malloc(s3);

  fprintf(stdout, "%p %p %p\n", ptr1, ptr2, ptr3);

  assert(ptr3==(ptr2+OFFSET(s2)));
  assert(ptr2==(ptr1+OFFSET(s1)));

  // Try to construct ptr2 from ptr3.
  free(ptr3);
  free(ptr3-OFFSET(s2));
  free(ptr3-OFFSET(s2)-OFFSET(s1));
}
Trenin
  • 2,041
  • 1
  • 14
  • 20
1

First of all - as it seems you do not understand how malloc works - passing continuous numbers to malloc, won't make it allocate an array. malloc is defined as follows:

void* malloc (size_t size);

While an integer can be converted to size_t, it's still the number of bytes allocated, not the element number. If you want to allocate an array, do it as follows:

int* myDynamicArray = malloc(sizeof(int)*numberOfElements);

Then, you can access the elements by doing:

int i;
for(i=0;i<numberOfElements;i++)
   printf("%d",myDynamicArray[i]);

Then, like others pointed out - you can deallocate the memory by calling the free function. free is defined as follows:

void free (void* ptr);

And you simply call it by doing:

free(myDynamicArray);
Paweł Stawarz
  • 3,952
  • 2
  • 17
  • 26