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

时间:2017-06-02 14:24:44

标签: c memory-management malloc free

我一直在阅读有关malloc请求零大小的块时的行为的讨论。

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

但是,如果获得这样一个不可访问的非空指针,我是否可以通常的方式将其传递给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?
}

2 个答案:

答案 0 :(得分:42)

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

  

返回的指针指向开始(最低字节   地址)分配的空间。如果无法分配空间,则为空指针   回。如果请求的空间大小为零,则行为是实现定义的:   返回空指针,或者行为就像大小一样   非零值,但返回的指针不得用于访问对象

和约free()

  

否则,如果   该参数与之前由calloc,malloc或realloc函数返回的指针不匹配,或者如果通过调用free或realloc释放了该空间,则该行为未定义。

IEEE Std 1003.1-2008(POSIX),2016年版关于free()

  

free()函数将导致ptr指向的空间   释放;也就是说,可供进一步分配。如果是ptr   空指针,不会发生任何动作。否则,如果参数确实如此   不匹配POSIX.1-2008中函数返回的指针   像malloc()一样分配内存,或者空间如何   通过调用free()或realloc()解除分配,行为是   未定义。

因此,无论*alloc()返回什么,您都可以转到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)

答案 1 :(得分:25)

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

malloc系统通常在指针之前的空间中返回一个隐藏的控制块,其中包含分配大小等信息。如果分配大小为零,则此块仍然存在并占用内存,如果malloc返回非null。