不正なアクセス
範囲外アクセスと未初期化です。
「不正なアクセス」はCoddyKit上の無料C Academyレッスンです。 これはレッスン3/4です。 下記で完全なレッスンを無料で読むことができます。その後、ブラウザ内の組み込みコードエディタと24時間対応のAIチューターでハンズオン演習できます。 これはC Academy学習パスの一部であり、ウェブとCoddyKitアプリ全体で進捗が同期されます。 C Academyコースには全4レッスンが含まれています。
リークの先へ
リークはメモリを無駄にしますが、不正なアクセスはメモリを破壊します。memcheckは次のような問題を検出します。
- バッファーの末尾を越えて読み書きする
freeの後にメモリを使用する- 未初期化の値を読み取る
- 不正なポインターを通して読み書きする
これらは、最も危険で再現が難しいクラッシュを引き起こします。
範囲外への書き込み
このプログラムは5個のintを格納する領域を確保しますが、インデックス5、つまり6番目の要素に書き込みます。
インデックス5は末尾の1要素分先にあります。memcheckはこの行でサイズ4の不正な書き込みを報告します。
#include <stdlib.h>
int main(void) {
int *a = malloc(5 * sizeof(int));
a[5] = 99; /* valid indices are 0..4 */
free(a);
return 0;
}エラーの読み方
レポートには、操作、サイズ、ブロックとの位置関係が示されます。
Invalid write of size 4Address 0x... is 0 bytes after a block of size 20 alloc'd
「20バイトのブロックの0バイト後」は、アクセス先が20バイト(5個のint)の確保領域の直後だったことを示します。
範囲外からの読み取り
読み取りも検出されます。ここではループが1要素分余計に実行されます。
プログラムが運よく「動作」する可能性があっても、memcheckは最後の反復でサイズ4の不正な読み取りを検出します。
#include <stdlib.h>
#include <stdio.h>
int main(void) {
int *a = calloc(3, sizeof(int));
for (int i = 0; i <= 3; i++) /* should be i < 3 */
printf("%d\n", a[i]);
free(a);
return 0;
}未初期化値
mallocはメモリをゼロ初期化しません。値を代入する前に使用すると、予測できない値になります。
その値が制御フローや出力に影響すると、memcheckは条件分岐または移動が未初期化値に依存していると報告します。
#include <stdlib.h>
#include <stdio.h>
int main(void) {
int *p = malloc(sizeof(int));
if (*p == 0) /* *p was never set */
printf("zero\n");
free(p);
return 0;
}未初期化値の報告が遅れる理由
memcheckは、未初期化メモリを読み取った瞬間には警告しません。「定義済みかどうか」を追跡し、分岐、出力、システムコールなど、未定義の値が実際に意味を持つ時点でのみ報告します。
これにより、未初期化のバイト列を無害にコピーしただけの場合の誤警告を避けられます。
解放後の使用
解放した後のメモリに触れることは未定義動作です。memcheckはこれを正確に検出します。
サイズ4の不正な読み取りと、Address ... is 0 bytes inside a block of size 4 free'dという注記を報告し、freeが実行された場所まで示します。
#include <stdlib.h>
#include <stdio.h>
int main(void) {
int *p = malloc(sizeof(int));
*p = 7;
free(p);
printf("%d\n", *p); /* read after free */
return 0;
}二重解放
同じポインターを2回解放すると、アロケーターの管理情報が破壊されます。
memcheckはInvalid free()を報告し、現在の解放と元の割り当ての両方を表示するため、誤りが明確になります。
#include <stdlib.h>
int main(void) {
int *p = malloc(sizeof(int));
free(p);
free(p); /* freed twice */
return 0;
}起点を追跡する
未初期化値のエラーには、--track-origins=yesを追加します。
するとmemcheckは、問題のある値が使用された場所だけでなく、作成された場所も報告するため、曖昧な警告を正確な修正箇所に変えられます。
valgrind --track-origins=yes ./progスタックとグローバル
memcheckはヒープエラーの検出を得意としています。一方、スタックやグローバル配列のオーバーフローに対する検出範囲は限定的です。
そのような場合は、AddressSanitizer(gcc -fsanitize=address)のほうが適していることがよくあります。2つのツールは互いに補完し合います。
境界を1つずれる問題: ヌル終端文字
よくあるヒープオーバーフローの1つが、文字列終端文字の入れ忘れです。strlenは'hello'に対して5を返しますが、末尾の'\0'を格納するには文字列に6バイト必要です。
strcpyが末尾の1バイトを終端の外側に書き込むと、memcheckはInvalid writeを報告します。
#include <stdlib.h>
#include <string.h>
int main(void) {
char *s = malloc(strlen("hello")); /* needs +1 */
strcpy(s, "hello"); /* writes the '\0' past end */
free(s);
return 0;
}クイックチェック
このコード断片に対してmemcheckが何を報告するか確認してください。
まとめ
これで、不正なアクセスによるバグを見つけられるようになりました。
- 範囲外の読み取り/書き込みは、ブロックからのオフセットとともにInvalid read/writeとして表示されます
- 未初期化値は、判断や出力に影響した時点で指摘されます
- 解放後使用と二重解放は、両方の呼び出し箇所とともに検出されます
--track-origins=yesで未定義値の起点を特定し、スタックのバグにはASanを組み合わせます
次は、レポート全体の読み方です。
よくある質問
「不正なアクセス」レッスンは無料ですか?
はい。「不正なアクセス」の完全なテキストはこのウェブで無料で読めます。インタラクティブに演習し(組み込みコードエディタと24時間対応のAIチューター)、C Academyコースの残りをアンロックするには、CoddyKit PROにアップグレードしてください。 C Academyコースには全4レッスンが含まれています。
「不正なアクセス」で何を学びますか?
範囲外アクセスと未初期化です。 ブラウザで直接実行するハンズオンコードでC Academyを演習し、24時間対応のAIチューターがレッスンを進める中での質問に答えます。
C Academyを始めるのに経験は必要ですか?
事前経験は必要ありません。CoddyKitのC Academyは初級者から上級者向けに構成されているため、ここから始めるか最初から始めて、自分のペースで進むことができます。 これはレッスン3/4です。
「不正なアクセス」レッスンにはどのくらい時間がかかりますか?
ほとんどのCoddyKitレッスンは約5~10分かかります。各レッスンはコンパクトでインタラクティブなので、着実に進歩し、ウェブとアプリ全体で正確に前回の場所から再開できます。
このC Academyレッスンでコードを書いて実行できますか?
はい。すべてのC Academyレッスンに組み込みコードエディタが含まれているため、ブラウザでリアルコードを書いて実行し、即座のAIフィードバックを取得できます。ローカル設定は不要です。
このコースのすべてのレッスン
- Valgrind を使う理由
- リークの検出
- 不正なアクセス
- レポートの読み方