如果 `malloc(0)` returns 是一个非空指针,我可以将它传递给 `free` 吗?

If `malloc(0)` returns a non-null pointer, can I pass that to `free`?

我一直在阅读有关 malloc 在您请求大小为零的块时如何表现的讨论。

我知道 malloc(0) 的行为是实现定义的,它应该是 return 一个空指针, 一个非我仍然不应该访问的空指针。 (这是有道理的,因为不能保证它指向任何可用的内存。)

但是,如果得到这样一个不可访问的非空指针,我可以用通常的方式将它传递给 free 吗?或者这是非法的,因为我从 malloc(0) 获得的指针可能不指向实际分配的内存块?

具体来说,以下代码是否具有明确定义的行为:

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

int main() {
    int* x = (int*) malloc(0);
    if (x == NULL) {
        printf("Got NULL\n");
        return 0;
    } else {
        printf("Got nonnull %p\n", x);
    }
    free(x); // is calling `free` here okay?
}

是的,事实上您必须这样做以避免可能的内存泄漏。

malloc 系统通常 returns 指针前 space 中的隐藏控制块,其中包含分配大小等信息。如果分配大小为零,这个块仍然存在并占用内存,if malloc returns non-null.

C99 标准(实际上是 WG14/N1124。委员会草案 -- 2005 年 5 月 6 日。ISO/IEC 9899:TC2)关于 malloc():

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

大约 free():

Otherwise, if the argument does not match a pointer earlier returned by the calloc, malloc, or realloc function, or if the space has been deallocated by a call to free or realloc, the behavior is undefined.

IEEE Std 1003.1-2008 (POSIX),2016 年版说 free():

The free() function shall cause the space pointed to by ptr to be deallocated; that is, made available for further allocation. If ptr is a null pointer, no action shall occur. Otherwise, if the argument does not match a pointer earlier returned by a function in POSIX.1-2008 that allocates memory as if by malloc(), or if the space has been deallocated by a call to free() or realloc(), the behavior is undefined.

因此,无论 *alloc() returns,您都可以传递给 free()

至于malloc()的当前实现:

FreeBSD 使用贡献的 jemalloc

void *
je_malloc(size_t size)
{
    void *ret;
    size_t usize JEMALLOC_CC_SILENCE_INIT(0);

    if (size == 0)
        size = 1;
    [...]

而 Apple 的 libmalloc 可以

void *
szone_memalign(szone_t *szone, size_t alignment, size_t size)
{
    if (size == 0) {
        size = 1; // Ensures we'll return an aligned free()-able pointer
    [...]

GLIBC 也改变了请求的大小;它使用以字节为单位的请求大小调用此宏作为参数,以将大小对齐到特定边界或简单地最小分配大小:

#define request2size(req)                                       \
    (((req) + SIZE_SZ + MALLOC_ALIGN_MASK < MINSIZE)  ?         \
    MINSIZE :                                                   \
    ((req) + SIZE_SZ + MALLOC_ALIGN_MASK) & ~MALLOC_ALIGN_MASK)