Why does malloc(0) cause a major memory leak on Windows?

走远了吗. 提交于 2021-02-10 19:59:55

问题


I have just concluded a happy 4.5 hours of debugging a nasty leak in my system.

It turns out I was doing this:

params = allocate(sizeof(Something*) * num_params); 

which in turns essentially calls malloc with the first argument passed in. When num_params is 0, it would call malloc(0).

Running this in a loop, the program would very quickly take up most of the memory. I fixed it by first checking if num_params == 0, and if so avoiding the call to allocate.

I know that the Standard dictates malloc(0) is implementation-defined. So, how is this implemented in the Windows 7 C runtime library, and why does it cause a leak?

Edit: Clarifying the question - why does malloc(0) on Windows allocate memory, and what is the logic that dictates how much memory will be allocated?


回答1:


malloc(0) returns a new valid address because that's the option it chose among those the C standard permits.

7.22.3 Memory management functions (emphasis mine)

1 The order and contiguity of storage allocated by successive calls to the aligned_alloc, calloc, malloc, and realloc functions is unspecified. The pointer returned if the allocation succeeds is suitably aligned so that it may be assigned to a pointer to any type of object with a fundamental alignment requirement and then used to access such an object or an array of such objects in the space allocated (until the space is explicitly deallocated). The lifetime of an allocated object extends from the allocation until the deallocation. Each such allocation shall yield a pointer to an object disjoint from any other object. The pointer returned points to the start (lowest byte address) of the allocated space. If the space cannot be allocated, a null pointer is returned. If the size of the space requested is zero, the behavior is implementation-defined: either a null pointer is returned, or the behavior is as if the size were some nonzero value, except that the returned pointer shall not be used to access an object.

The implementation on windows chooses the second behavior. And so it must do some allocation to ensure the requirement appearing immediately before. Each valid pointer returned by an allocation function must be disjoint from any other pointer returned by an allocation function.


Relevant reading:

  • Why is the return value of malloc(0) implementation-defined?



回答2:


Some systems simply return NULL without allocating anything. But it's perfectly legitimate for malloc to allocate a 0 byte block of memory and return a pointer to that memory. This block must be freed like any other allocated by malloc.

When you allocate memory, there's a certain amount of overhead involved. So even allocating 0 bytes takes up memory.

Also, systems may over-allocate or have have alignment restrictions that may render some memory unusable after each allocation. This may or may not happen here.


In the comments, you mentioned you are doing something along the lines of the following:

if (num_params > 0) {
    ...free elements of params...
    free(params);
}

Instead, you should have been doing the following:

if (params) {
    ...free elements of params...
    free(params);
}



回答3:


From the man page:

If size is 0, malloc allocates a zero-length item in the heap and returns a valid pointer to that item

And, with the valgrind check for the small program:

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

int main()
{
    int *p = malloc(0);

    if(!p) {
        printf("%p\n", p);
    }
    //free(p);
    return 0;
}

We have the log:

HEAP SUMMARY:
==11874==     in use at exit: 0 bytes in 1 blocks
==11874==   total heap usage: 1 allocs, 0 frees, 0 bytes allocated
==11874== 
==11874== 0 bytes in 1 blocks are definitely lost in loss record 1 of 1
==11874==    at 0x4C2FB0F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)

But with free function:

HEAP SUMMARY:
==11887==     in use at exit: 0 bytes in 0 blocks
==11887==   total heap usage: 1 allocs, 1 frees, 0 bytes allocated
==11887== 
==11887== All heap blocks were freed -- no leaks are possible




回答4:


As others have quoted, malloc(0) is implementation defined, a null pointer is returned or the behaviour is as if the size were some nonzero value. Clearly it's the second option and quoting Microsoft's documentation for malloc

If size is 0, malloc allocates a zero-length item in the heap and returns a valid pointer to that item.

Doesn't specifiy the overhead.


To get a sense we can look at glibc implementation for malloc.c

Even a request for zero bytes (i.e., malloc(0)) returns a pointer to something of the minimum allocatable size


Minimum allocated size:
4-byte ptrs: 16 bytes (including 4 overhead)
8-byte ptrs: 24/32 bytes (including, 4/8 overhead)



来源:https://stackoverflow.com/questions/61876053/why-does-malloc0-cause-a-major-memory-leak-on-windows

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!