Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Does the pointer passed to free() have to point to beginning of the memory block, or can it point to the interior?

The question is in the title... I searched but couldn't find anything.


Edit:

I don't really see any need to explain this, but because people think that what I'm saying makes no sense (and that I'm asking the wrong questions), here's the problem:

Since people seem to be very interested in the "root" cause of all the problem rather than the actual question asked (since that apparently helps things get solved better, let's see if it does), here's the problem:

I'm trying to make a D runtime library based on NTDLL.dll, so that I can use that library for subsystems other than the Win32 subsystem. So that forces me to only link with NTDLL.dll.

Yes, I'm aware that the functions are "undocumented" and could change at any time (even though I'd bet a hundred dollars that wcstombs will still do the same exact thing 20 years from now, if it still exists). Yes, I know people (especially Microsoft) don't like developers linking to that library, and that I'll probably get criticized for the right here. And yes, those two points above mean that programs like chkdsk and defragmenters that run before the Win32 subsystem aren't even supposed to be created in the first place, because it's literally impossible to link with anything like kernel32.dll or msvcrt.dll and still have NT-native executables, so we developers should just pretend that those stages are meant to be forever out of our reaches.

But no, I doubt that anyone here would like me to paste a few thousand lines of code and help me look through them and try to figure out why memory allocations that aren't failing are being rejected by the source code I'm modifying. So that's why I asked about a different problem than the "root" cause, even though that's supposedly known to be the best practice by the community.

If things still don't make sense, feel free to post comments below! :)


Edit 2:

After around ~8 hours of debugging, I finally found the problem:

It turns out that RtlReAllocateHeap() does not automatically work like RtlAllocateHeap() if the pointer given to it is NULL.

like image 391
user541686 Avatar asked Jan 03 '11 22:01

user541686


3 Answers

It has to point to the beginning of the block. It's safe to pass a null pointer to free(), but passing any pointer not allocated by malloc() or one of its relatives will cause undefined behaviour. Some systems will give you a runtime error - something along the lines of "Deallocation of a pointer not malloced".

Edit:

I wrote a test program to get the error message. On my machine, this program:

#include <stdlib.h>

int main(int argc, char **argv)
{
  int *x = malloc(12);
  x++;

  free(x);

  return 0;
}

Crashes with this message:

app(31550) malloc: *** error for object 0x100100084: pointer being freed was not allocated
like image 68
Carl Norum Avatar answered Sep 22 '22 15:09

Carl Norum


The only thing you can pass to free is a pointer returned to you from malloc (or calloc, realloc, etc), or NULL.

I'm guessing you're asking because you have some function where you do a malloc, and you want to mess with the data block and then get rid of it when you're done, and you don't want to be bothered keeping a copy of the original pointer around. It doesn't work that way.

like image 26
Andy Lester Avatar answered Sep 25 '22 15:09

Andy Lester


From the comments you have added to existing answers, it seems you are asking the wrong question. If memory alignment is what you need, why don't you ask that question? Ask about the root problem rather than asking about your perceive solution!

So if you don't mind I'll answer the question you should have asked:

Aligned memory allocation is supported in Win32 by _aligned_malloc(). It is more of less equivalent to POSIX memalign()

If you need an implementation of aligned allocation, it is fairly simple to implement:

void* aligned_malloc( size_t size, size_t alignment )
{
    void* unaligned = malloc( size + alignment ) ;
    void* aligned = (void*)(((intptr_t)unaligned + alignment) & ~(alignment - 1));
    void** free_rec_ptr = ((void**)aligned - 1) ;
    *free_rec_ptr = unaligned ;

    return aligned ;
}

void aligned_free( void* block )
{
    void** free_rec_ptr = ((void**)block - 1) ;
    free( *free_rec_ptr ) ;
}

The alignment argument must be a power of two.

like image 29
Clifford Avatar answered Sep 22 '22 15:09

Clifford