
C言語入門|メモリ範囲外アクセスの恐怖
ここまでで、配列・ポインタ・添え字の正体が見えてきましたね。
「[] はただのメモリアクセス」「ポインタ演算で自由に番地を動かせる」。
……と聞くと、ちょっとワクワクしませんか?
でもその自由さには、とんでもなく重い代償がついてきます。
それが メモリ範囲外アクセス、いわゆる オーバーラン です。
C言語は、
危ないことができる → でも止めてはくれない
という、プロ向けの性格をしています。

添え字はただのアドレス計算だった
すでに学んだとおり、添え字は安全装置ではありません。
array[i]は実際には、
*(array + i)として評価されます。
つまり、
- i が大きすぎても
- i がマイナスでも
C言語は何も文句を言いません。
オーバーランとは何か
オーバーランの定義
本来割り当てられていないメモリ領域に
読み書きしてしまうこと
これが起きると、
- 他の変数を書き壊す。
- 実行制御情報を書き壊す。
- セキュリティ情報を漏らす。
といった、非常に危険な事態につながります。
メモリ配置を具体的に見てみよう
次のような変数が、たまたま連続して配置されていると仮定します。
int age;
int items[5];
char secret[16];前提
- 1セル=1バイト
- int型=4バイト
メモリ配置イメージ(例)

危険なコード例(オーバーラン)
プロジェクト名:10-6-1 ソースファイル名: sample10-6-1.c
#include <stdio.h>
int main(void)
{
int age = 25;
int items[5] = {1, 2, 3, 4, 5};
char secret[32] = "HELLO";
items[-1] = 999;
items[6] = 888;
printf("age=%d\n", age);
printf("secret=%s\n", secret);
return 0;
}次のコードを見てください。
実行結果(例)
age=999
secret=�ELLO※ 環境によって結果は変わります
※ 正常に見えることもあります(それが一番怖い)
何が起きているのか
items[-1] の正体
| 式 | 実際の意味 |
|---|---|
| items[-1] | *(items - 1) |
これは、
- items の先頭アドレスから
- int 1個分(4バイト)前
つまり age の領域を書き換えています。
items[6] の正体
| 式 | 実際の意味 |
|---|---|
| items[6] | *(items + 6) |
これは、
- 配列の範囲を超えて
- secret の一部を書き換える
という、非常に危険な操作です。
なぜエラーにならないのか
ここがC言語の最大の特徴です。
- 添え字の範囲チェックをしない。
- 実行時にも止めない。
- コンパイル時にも警告しないことが多い。
つまり、
壊れているのに動いてしまう
という、最悪の状態が普通に起こります。
オーバーランが引き起こす本当の恐怖
オーバーランは、単なるバグでは終わりません。
- プログラムの暴走
- 強制終了
- OSの重要情報の破壊
- パスワードや秘密情報の漏えい
実際、過去の多くの脆弱性は
バッファオーバーラン が原因でした。
C言語プログラマが守るべき鉄則
オーバーランを常に警戒する
- 配列サイズを必ず意識する。
- 添え字の上限・下限を自分で管理する。
- 「たまたま動いた」を信用しない。
C言語は、
自由を与える代わりに、責任をすべて押し付ける言語
です。
ハッカーという言葉について少しだけ
ちなみに、
- ハッカー = 技術を極めた人
- クラッカー = 悪意ある攻撃者
が本来の意味です。
C言語を深く理解している人は、
善にも悪にもなれる力を持ちます。
だからこそ、
正しく、慎重に、使いこなす必要があるのです。
