[インデックス 1460] ファイルの概要
このコミットは、Go言語のランタイムにおけるメモリ管理の一部である src/runtime/malloc.c
ファイルに対する変更です。具体的には、free
関数が nil
(C言語における NULL
に相当) ポインタを受け取った際の挙動を修正しています。
コミット
commit 0c3243053465e0e4482fb5040c2e4e16972751cc
Author: Russ Cox <rsc@golang.org>
Date: Fri Jan 9 16:22:13 2009 -0800
free(nil)
R=iant
DELTA=3 (3 added, 0 deleted, 0 changed)
OCL=22467
CL=22471
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/0c3243053465e0e4482fb5040c2e4e16972751cc
元コミット内容
このコミットの目的は、「free(nil)
」の挙動を修正することです。これは、Goランタイムのメモリ解放関数 free
が nil
ポインタを引数として受け取った場合に、何もせずに即座にリターンするように変更することを意味します。
変更の背景
C言語の標準ライブラリ関数 free()
は、NULL
ポインタを引数として受け取った場合、何もしないことが保証されています。これは、メモリ解放処理を行う前にポインタが有効かどうかをチェックする手間を省き、コードを簡潔にするための一般的な慣習です。
Go言語の初期のランタイムにおける free
関数は、nil
ポインタが渡された場合に、内部で不正なメモリアクセスやクラッシュを引き起こす可能性がありました。このコミットは、Goランタイムのメモリ管理をより堅牢にし、C言語の free
関数と同様の安全な挙動を保証するために導入されました。これにより、プログラマが free
を呼び出す前にポインタが nil
でないことを明示的にチェックする必要がなくなり、Goのメモリ管理の信頼性が向上しました。
前提知識の解説
メモリ管理と free
関数
コンピュータプログラムは、実行時にメモリを動的に確保し、使用し、そして解放する必要があります。このプロセスをメモリ管理と呼びます。malloc
(またはGoにおける new
や make
に相当する内部的なアロケータ) はメモリを確保し、free
は確保されたメモリをシステムに返却する役割を担います。メモリを解放し忘れるとメモリリークが発生し、確保されていないメモリを解放しようとすると未定義の動作やクラッシュを引き起こす可能性があります。
ポインタと nil
ポインタは、メモリ上の特定のアドレスを指し示す変数です。nil
(C言語では NULL
) は、どの有効なメモリ位置も指していないことを示す特別なポインタ値です。プログラムにおいて、ポインタが nil
であるかどうかをチェックすることは、無効なメモリアクセスを防ぐ上で非常に重要です。
Goランタイム
Go言語は、ガベージコレクションを備えた独自のランタイムを持っています。このランタイムは、メモリの確保、解放、スケジューリング、ゴルーチンの管理など、Goプログラムの実行に必要な低レベルの操作を処理します。src/runtime/malloc.c
は、このランタイムの一部であり、Goプログラムが使用するメモリの動的な割り当てと解放を担当するC言語で書かれたコードです。
技術的詳細
このコミットの技術的な詳細は、free
関数が nil
ポインタを安全に処理するように変更された点に集約されます。
従来の free
関数は、引数 v
(解放するメモリブロックへのポインタ) が nil
であることを想定していませんでした。そのため、v
が nil
の場合、その後の処理(例えば、page = (uintptr)v >> PageShift;
のようなアドレス計算や、MHeapMapCache_GET
を用いたメモリヒープの検索)が不正なメモリアドレスに対して行われ、ランタイムエラーやセグメンテーション違反を引き起こす可能性がありました。
この変更により、free
関数の冒頭で if(v == nil) return;
というシンプルなチェックが追加されました。これにより、v
が nil
であった場合、関数は即座に処理を終了し、それ以降の危険な操作が実行されるのを防ぎます。これは、防御的プログラミングの典型的な例であり、関数の入力に対する堅牢性を高めます。
Go言語のランタイムはC言語で書かれている部分が多く、C言語の慣習(free(NULL)
が安全であること)に合わせることで、Goのメモリ管理コードの移植性、保守性、そして安全性が向上します。
コアとなるコードの変更箇所
変更は src/runtime/malloc.c
ファイルの free
関数内で行われました。
--- a/src/runtime/malloc.c
+++ b/src/runtime/malloc.c
@@ -68,6 +68,9 @@ free(void *v)
MSpan *s;
MCache *c;
+ if(v == nil)
+ return;
+
// Find size class for v.
page = (uintptr)v >> PageShift;
sizeclass = MHeapMapCache_GET(&mheap.mapcache, page, tmp);
コアとなるコードの解説
追加された3行のコードは以下の通りです。
if(v == nil)
return;
if(v == nil)
: これは条件分岐の開始です。v
はfree
関数に渡されたポインタです。nil
はGoランタイムのCコードにおけるNULL
に相当するマクロまたは定義です。この条件は、「もしポインタv
がnil
であるならば」という意味になります。return;
: これは、if
文の条件が真(つまりv
がnil
)であった場合に実行されるステートメントです。関数から即座に制御を戻し、それ以降のfree
関数の処理(メモリ解放ロジック)を実行しないようにします。
このシンプルな変更により、free
関数は nil
ポインタに対して安全な操作となり、Goプログラムの安定性が向上しました。
関連リンク
- Go言語の公式ドキュメント: https://go.dev/
- Go言語のソースコードリポジトリ: https://github.com/golang/go
- C言語の
free
関数に関するドキュメント (例: cppreference.com): https://en.cppreference.com/w/c/memory/free
参考にした情報源リンク
- 上記のGitHubコミットページ: https://github.com/golang/go/commit/0c3243053465e0e4482fb5040c2e4e16972751cc
- Go言語のランタイムに関する一般的な知識 (Goのメモリ管理、ガベージコレクションなどに関する記事や書籍)
- C言語のメモリ管理 (
malloc
,free
) に関する一般的な知識 (C言語の標準ライブラリ関数に関するドキュメント) - 防御的プログラミングの原則に関する情報