メインコンテンツ

以前に割り当て解除したポインターの解放

割り当てなしで複数回解放されているメモリ

説明

この欠陥は、メモリのブロックが、関数 free を使用して中間割り当てなしで連続して解放された場合に発生します。

リスク

malloccalloc、または realloc を使用してポインターに動的メモリが割り当てられている場合、ポインターはヒープ上のメモリ位置を指します。このポインターに対して関数 free を使用すると、メモリの関連ブロックが再割り当て用に解放されます。メモリのこのブロックを解放しようとすると、セグメンテーション違反が発生する可能性があります。

修正方法

修正方法は欠陥の根本原因によって異なります。最初の割り当て解除と 2 番目の割り当て解除の間でメモリ ブロックをポインターに割り当てることを意図しているかどうかを確認します。そうでない場合は、2 番目の free ステータスを削除します。

メモリ ブロックを解放した後、対応するポインターに NULL を割り当てることをお勧めします。ポインターを解放する前に、NULL 値かどうかをチェックしてエラーを処理します。この方法により、既に解放されているブロックを解放するのを避けることができます。

すべて展開する

#include <stdlib.h>

void allocate_and_free(void)
{

    int* pi = (int*)malloc(sizeof(int));
    if (pi == NULL) return;

    *pi = 2;
    free(pi);
    free (pi);       
    /* Defect: pi has already been freed */
}

最初の free ステートメントにより、pi が参照するメモリのブロックが解放されます。pi に対する 2 番目の free ステートメントにより、既に解放されたメモリが解放されます。

修正 — 重複する割り当て解除を削除

1 つの修正方法として、2 番目の free ステートメントを削除することができます。

#include <stdlib.h>

void allocate_and_free(void)
{

    int* pi = (int*)malloc(sizeof(int));
    if (pi == NULL) return;

    *pi = 2;
    free(pi);
    /* Fix: remove second deallocation */
 }
#include <stdlib.h>
  
void reshape(char *buf, size_t size) {
  char *reshaped_buf = (char *)realloc(buf, size);
  if (reshaped_buf == NULL) {
    free(buf);
  }
}

この例では、関数 reshape() の引数 size がゼロになり、その結果、realloc() でサイズがゼロの再割り当てが行われる可能性があります。GNU® ライブラリなどの一部の実装では、サイズがゼロの再割り当てによってメモリが解放されると、二重解放の欠陥につながります。

修正 – サイズがゼロの再割り当てを防止する

1 つの修正方法として、使用する前に realloc() のサイズ引数の値がゼロかどうかをチェックします。サイズ引数がゼロの場合は、メモリを再割り当てするのではなく、単に解放します。

#include <stdlib.h>

void reshape(char *buf, size_t size) {
  if (size != 0) {
    char *reshaped_buf = (char *)realloc(buf, size);
    if (reshaped_buf == NULL) {
      free(buf);
    }
  }
  else {
    free(buf);
  }

}

結果情報

グループ: 動的メモリ
言語: C | C++
既定値: オン
コマンド ライン構文: DOUBLE_DEALLOCATION
影響度: High

バージョン履歴

R2013b で導入

すべて展開する