web-dev-qa-db-ja.com

`malloc(0)`がnull以外のポインタを返す場合、それを `free`に渡すことはできますか?

サイズがゼロのブロックをリクエストしたときのmallocの動作についての説明を読んでいます。

malloc(0)の動作は実装定義であり、nullポインターを返すと想定されていますor非nullポインターであるにもかかわらず、アクセスすることは想定されていません。 (これは、使用可能なメモリを指すという保証がないため、これは理にかなっています。)

ただし、そのようなアクセスできない非nullポインターを取得した場合、通常の方法で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?
}
43
pnkfelix

C99標準(実際にはWG14/N1124。委員会草案-2005年5月6日。ISO/ IEC 9899:TC2)は、malloc()について次のように述べています。

返されるポインタは、割り当てられたスペースの開始(最下位バイトアドレス)を指します。スペースを割り当てることができない場合は、nullポインタが返されます。要求されたスペースのサイズがゼロの場合、動作は実装定義です。ヌルポインターが返されるか、返されたポインターがオブジェクトへのアクセスに使用されないことを除いて、サイズがゼロ以外の値であるかのように動作します。

free()について:

それ以外の場合、引数がcalloc、malloc、またはrealloc関数によって以前に返されたポインターと一致しない場合、または領域がfreeまたはreallocの呼び出しによって割り当て解除された場合、動作は未定義です。

IEEE Std 1003.1-2008(POSIX)、2016 Editionはfree()について述べています:

Free()関数は、ptrが指すスペースの割り当てを解除します。つまり、追加の割り当てに使用できるようになります。 ptrがnullポインターの場合、アクションは発生しません。それ以外の場合、引数が、malloc()のようにメモリを割り当てるPOSIX.1-2008の関数によって以前に返されたポインタと一致しない場合、または領域が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)
41
apriori

はい、実際には、メモリリークの可能性を回避するためにそうする必要があります。

通常、mallocシステムは、ポインターの直前のスペースに、割り当てサイズなどの情報とともに非表示の制御ブロックを返します。割り当てサイズがゼロの場合、mallocがnull以外を返す場合、このブロックはまだ存在し、メモリを占有します。

24
Malcolm McLean