ダングリングポインター
解放後使用の危険性です。
「ダングリングポインター」はCoddyKit上の無料C Academyレッスンです。 これはレッスン4/4です。 下記で完全なレッスンを無料で読むことができます。その後、ブラウザ内の組み込みコードエディタと24時間対応のAIチューターでハンズオン演習できます。 これはC Academy学習パスの一部であり、ウェブとCoddyKitアプリ全体で進捗が同期されます。 C Academyコースには全4レッスンが含まれています。
ダングリングポインタとは
ダングリングポインタとは、すでに解放されたメモリや、それ以外の理由で無効になったメモリを指すポインタです。
これを使うと未定義動作になり、クラッシュやデータ破壊、気づきにくいバグにつながります。
#include <stdio.h>
#include <stdlib.h>
int main(void) {
int *p = malloc(sizeof(int));
*p = 5;
printf("%d\n", *p);
free(p);
p = NULL;
return 0;
}解放後の使用
最も一般的な原因は、freeの後にポインタを通して読み書きすることです。
そのメモリブロックは、すでに別の用途に再利用されている可能性があります。
#include <stdio.h>
#include <stdlib.h>
int main(void) {
int *p = malloc(sizeof(int));
*p = 42;
free(p);
/* Reading *p here would be use-after-free. */
p = NULL;
printf("avoided use-after-free\n");
return 0;
}解放後にNULLを設定
解放した直後にポインタへNULLを設定すると、誤った使用を明確なクラッシュに変えられます。また、free(NULL)なら安全に実行できます。
#include <stdio.h>
#include <stdlib.h>
int main(void) {
char *buf = malloc(10);
buf[0] = 'A';
free(buf);
buf = NULL;
if (buf == NULL) printf("buf is safely null\n");
return 0;
}ローカルアドレスの返却
ローカル(スタック)変数のアドレスを返すと、ダングリングポインタが作られます。関数が戻ると、その変数はなくなるためです。
代わりにヒープを使うか、バッファを渡してください。
#include <stdio.h>
#include <stdlib.h>
int *make_value(int v) {
int *p = malloc(sizeof(int));
*p = v;
return p;
}
int main(void) {
int *p = make_value(99);
printf("%d\n", *p);
free(p);
return 0;
}1つのブロックを指す複数のポインタ
2つのポインタが同じメモリブロックを指している場合、一方を通して解放すると、もう一方がダングリングポインタになります。
所有権を管理し、所有者だけが解放するようにしてください。
#include <stdio.h>
#include <stdlib.h>
int main(void) {
int *a = malloc(sizeof(int));
*a = 7;
int *b = a;
printf("%d\n", *b);
free(a);
a = NULL;
b = NULL;
printf("both nulled\n");
return 0;
}realloc後のダングリング
reallocによってブロックが移動すると、以前の場所を指していた古いポインタはダングリングポインタになります。
reallocが返したポインタだけを使ってください。
#include <stdio.h>
#include <stdlib.h>
int main(void) {
int *a = malloc(sizeof(int));
a[0] = 1;
int *b = realloc(a, 50 * sizeof(int));
/* a may now be dangling; use only b. */
b[0] = 2;
printf("%d\n", b[0]);
free(b);
return 0;
}ヘルパー関数での解放
ヘルパー関数がメモリブロックを解放すると、呼び出し元のポインタはダングリングポインタになります。呼び出し後にNULLを設定するか、ヘルパー関数がポインタへのポインタを受け取る設計にしてください。
#include <stdio.h>
#include <stdlib.h>
void destroy(int **p) {
free(*p);
*p = NULL;
}
int main(void) {
int *p = malloc(sizeof(int));
*p = 5;
destroy(&p);
printf("p is %s\n", p == NULL ? "null" : "set");
return 0;
}危険な理由
解放後の使用が危険なのは、そのメモリに別のデータが入っている可能性があるためです。書き込みによって無関係な状態が壊れることがあり、攻撃者に悪用される可能性もあります。
スコープに基づくダングリングポインタ
ブロック内で宣言した変数を指すポインタは、そのブロックが終了すると無効になります。ポインタは、指している対象の有効期間を超えて保持しないでください。
#include <stdio.h>
int main(void) {
int *p;
{
int x = 10;
p = &x;
printf("in scope: %d\n", *p);
}
/* p now dangles; do not dereference it here. */
printf("block ended\n");
return 0;
}ダングリングポインタの検出
AddressSanitizerやValgrindなどのツールは、実行時に解放後の使用を検出し、該当する正確な行を示します。
開発中はサニタイザーを有効にしてビルドしてください。
コードで確認する安全なライフサイクル
確保し、使用し、解放し、NULLを設定します。これを一貫して守ると、ポインタがダングリングポインタになるのを防げます。
#include <stdio.h>
#include <stdlib.h>
int main(void) {
int *p = malloc(sizeof(int));
if (!p) return 1;
*p = 123;
printf("%d\n", *p);
free(p);
p = NULL;
return 0;
}理解度チェック
ダングリングポインタについての理解度を確認しましょう。
まとめ
ダングリングポインタについて学びました。
- 解放済み、またはスコープ外のメモリを指し、それを使うと未定義動作になります。
- ローカル変数のアドレスを返さないでください。また、
freeの後や、reallocによってブロックが移動した後にポインタを使わないでください。 - 解放後はポインタに
NULLを設定し、所有権を管理してください。 - サニタイザーとValgrindを使って、解放後の使用を検出してください。
よくある質問
「ダングリングポインター」レッスンは無料ですか?
はい。「ダングリングポインター」の完全なテキストはこのウェブで無料で読めます。インタラクティブに演習し(組み込みコードエディタと24時間対応のAIチューター)、C Academyコースの残りをアンロックするには、CoddyKit PROにアップグレードしてください。 C Academyコースには全4レッスンが含まれています。
「ダングリングポインター」で何を学びますか?
解放後使用の危険性です。 ブラウザで直接実行するハンズオンコードでC Academyを演習し、24時間対応のAIチューターがレッスンを進める中での質問に答えます。
C Academyを始めるのに経験は必要ですか?
事前経験は必要ありません。CoddyKitのC Academyは初級者から上級者向けに構成されているため、ここから始めるか最初から始めて、自分のペースで進むことができます。 これはレッスン4/4です。
「ダングリングポインター」レッスンにはどのくらい時間がかかりますか?
ほとんどのCoddyKitレッスンは約5~10分かかります。各レッスンはコンパクトでインタラクティブなので、着実に進歩し、ウェブとアプリ全体で正確に前回の場所から再開できます。
このC Academyレッスンでコードを書いて実行できますか?
はい。すべてのC Academyレッスンに組み込みコードエディタが含まれているため、ブラウザでリアルコードを書いて実行し、即座のAIフィードバックを取得できます。ローカル設定は不要です。
このコースのすべてのレッスン
- malloc と free
- calloc と realloc
- メモリリーク
- ダングリングポインター