web-dev-qa-db-ja.com

小さいサイズでreallocを呼び出すと、残りが解放されると思いますか?

次の非常に短いコードスニペットについて考えてみましょう。

_#include <stdlib.h>

int main()
{
    char* a = malloc(20000);
    char* b = realloc(a, 5);

    free(b);
    return 0;
}
_

Reallocのマニュアルページを読んだ後、2行目で19995余分なバイトが解放されるかどうかは完全にはわかりませんでした。マニュアルページを引用するには:The realloc() function changes the size of the memory block pointed to by ptr to size bytes.ですが、その定義から、残りが解放されることを確信できますか?

つまり、bが指すブロックには確かに5つの空きバイトが含まれているので、遅延準拠のアロケータがrealloc行に対して何もしないだけで十分でしょうか?

注:free(b)行をコメントアウトすると、valgrindが示すように、私が使用するアロケータは19 995余分なバイトを解放するようです:

_==4457== HEAP SUMMARY:
==4457==     in use at exit: 5 bytes in 1 blocks
==4457==   total heap usage: 2 allocs, 1 frees, 20,005 bytes allocated
_
27
qdii

はい、新しいオブジェクトを割り当てることができるかどうかはC標準によって保証されています。

(C99、7.20.3.4p2)「realloc関数は、ptrが指す古いオブジェクトの割り当てを解除し、sizeで指定されたサイズの新しいオブジェクトへのポインターを返します。」

25
ouah

はい。成功した場合。

コードスニペットは、よく知られた悪質なバグを示しています。

_char* b = (char*) realloc(a, 5);
_

これが成功すると、以前にaに割り当てられていたメモリが解放され、bは、元のブロックと重複する場合と重複しない場合がある5バイトのメモリを指します。

ただし、呼び出しが失敗した場合、bnullになりますが、aはまだ元のメモリを指しているため、引き続き有効です。その場合、メモリを解放するためにfree(a)を実行する必要があります。

一般的な(危険な)イディオムを使用すると、さらに悪いことになります。

_a = realloc(a, NEW_SIZE);     // Don't do this!
_

reallocの呼び出しが失敗すると、aはnullになり、元のメモリは孤立し、プログラムが終了するまで元に戻せなくなります。

20
Adam Liss

これは、libcの実装によって異なります。以下のすべてが適合動作です。

  • 何もしない、つまりデータをそのままの場所に残して古いブロックを返す、おそらく現在未使用のバイトをさらに割り当てて再利用する (そのような再利用は一般的ではありません)
  • データを新しいブロックにコピーし、古いブロックを解放してOSに戻す
  • 新しいブロックにデータをコピーし、さらに割り当てるために古いブロックを保持する

それも可能です

  • 新しいブロックを割り当てることができない場合はnullポインタを返します

この場合、古いデータもそのまま残ります。たとえば、realloc()の戻り値がそのブロックへのポインターの唯一のコピーを上書きした場合、メモリリークが発生する可能性があります。

賢明なlibc実装は、ヒューリスティックを使用して、どのソリューションが最も効率的かを判断します。

また、この説明は実装レベルであることに注意してください。意味的に、realloc()は、割り当てが失敗しない限り、常にオブジェクトを解放します。

3
Christoph

Realloc関数には次の規約があります。

void * result = realloc(ptr、new_size)

  • 結果がNULLの場合、ptrは引き続き有効で変更されません。
  • 結果が非NULLの場合、ptrは無効になり(解放されたかのように)、再び使用することはできません。結果は、正確にnew_sizeバイトのデータへのポインタになりました。

内部で行われていることの正確な詳細は実装固有です。たとえば、結果はptrに等しくなる可能性があります(ただし、new_sizeを超える追加のスペースは変更しないでください)。reallocはfreeを呼び出すか、独自の内部free表現を行う場合があります。重要なことは、reallocがnull以外の値を返した場合、開発者はptrの責任を負う必要がなくなり、reallocがNULLを返した場合も引き続き責任を持つことです。

1
SecurityMatt

19995バイトが解放された可能性は低いようです。より可能性が高いのは、reallocが20000バイトブロックを別の5バイトブロックに置き換えたことです。つまり、20000バイトブロックが解放され、新しい5バイトブロックが割り当てられました。

0
Ike Naar