glibc では realloc(p, 0) は本当に free(p) を伴うのでしょうか? 質問する

glibc では realloc(p, 0) は本当に free(p) を伴うのでしょうか? 質問する

p != NULLとがp以前の割り当て(たとえば によるmalloc)から派生している場合、 GNU/Linuxではrealloc(p, 0)と同等であると述べる人がいることや書籍などの参考文献があることを発見しましたfree(p)。この論文を裏付けるためにman reallocまさにそのように述べています(強調は筆者によるものです)。

realloc() 関数は、ptr が指すメモリ ブロックのサイズを size バイトに変更します。領域の開始から古いサイズと新しいサイズの最小値までの範囲では、内容は変更されません。新しいサイズが古いサイズより大きい場合、追加されたメモリは初期化されません。ptr が NULL の場合、呼び出しは、size のすべての値に対して malloc(size) と同等になります。sizeが0でptrがNULLでない場合、呼び出しはfree(ptr)と同等になります。ptr が NULL でない限り、これは malloc()、calloc()、または realloc() の以前の呼び出しによって返されている必要があります。指し示された領域が移動された場合、free(ptr) が実行されます。

ご覧のとおり、この質問ただし、C 標準では、何が起こるべきかを正確に定義しておらず、実際の動作は実装によって定義されます。具体的には、次のようになります。

C11 §7.22.3/p1メモリ管理機能言う:

要求されたスペースのサイズがゼロの場合、動作は実装定義になります。ヌルポインタが返されるまたは、返されたポインターがオブジェクトにアクセスするために使用されない点を除いて、サイズがゼロ以外の値である場合と同じように動作します。

およびC11 §7.22.3.5realloc関数含まれるもの:

3) (...) 新しいオブジェクトのメモリが割り当てることができません、古いオブジェクト割り当て解除されていないそしてその値は変更されません

4) このrealloc関数は新しいオブジェクトへのポインタを返します(古いオブジェクトへのポインタと同じ値になる場合があります)。新しいオブジェクトを割り当てることができなかった場合はヌルポインタ

私は実際の動作を調べるためにいくつかの基本的なコードを書いて、mcheckメモリ チェッカーには以下が付属していますglibc:

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

int main(void)
{
    int a = 5;
    int *p, *q;

    mtrace();

    p = malloc(sizeof(int));
    q = &a;

    printf("%p\n", (void *) p);
    printf("%p\n", (void *) q);

    q = realloc(p, 0);

    printf("%p\n", (void *) p);
    printf("%p\n", (void *) q);

    return 0;
}

結果は次のとおりです。

$ gcc -g check.c 
$ export MALLOC_TRACE=report
$ ./a.out 
0xfd3460
0x7ffffbc955cc
0xfd3460
(nil)
[grzegorz@centos workspace]$ mtrace a.out report 

Memory not freed:
-----------------
           Address     Size     Caller
0x0000000000fd3460      0x4  at /home/grzegorz/workspace/check.c:12

ご覧のとおり、qは に設定されていますNULL。 はfree()実際には呼び出されなかったようです。 実際、私の解釈が間違っていない限り、 は呼び出されるはずがありません。 はポインタreallocを返したのでNULL、新しいオブジェクトは割り当てられなかったはずであり、次のことを意味します。

古いオブジェクトは解放されず、その値は変更されません。

これは正しいです?

ベストアンサー1

編集: glibcは2.18より前のようですが、2.18ではmtraceのバグが修正されました(ここ)。2.20 glibc では、テスト プログラムは次のように報告します: 「メモリ リークはありません。」

freeglibcで呼び出されます。現在のglibc 2.21のソースから(ここそしてここ):

/*
  REALLOC_ZERO_BYTES_FREES should be set if a call to
  realloc with zero bytes should be the same as a call to free.
  This is required by the C standard. Otherwise, since this malloc
  returns a unique pointer for malloc(0), so does realloc(p, 0).
*/

#ifndef REALLOC_ZERO_BYTES_FREES
#define REALLOC_ZERO_BYTES_FREES 1
#endif

void *
__libc_realloc (void *oldmem, size_t bytes)
{
  mstate ar_ptr;
  INTERNAL_SIZE_T nb;         /* padded request size */

  void *newp;             /* chunk to return */

  void *(*hook) (void *, size_t, const void *) =
    atomic_forced_read (__realloc_hook);
  if (__builtin_expect (hook != NULL, 0))
    return (*hook)(oldmem, bytes, RETURN_ADDRESS (0));

#if REALLOC_ZERO_BYTES_FREES
  if (bytes == 0 && oldmem != NULL)
    {
      __libc_free (oldmem); return 0;
    }
#endif

おすすめ記事