■ 配列の境界を越えた書き込み

Cは、実行時に配列の境界チェックをしない。 そこで、配列の境界を越えて値を書き込める。

#include <stdio.h>

int main() {
  int x[2];
  int y;

  x[0] = 25;
  y = 72;

  printf ("x[0] -> %d\n",x[0]);
  printf ("y    -> %d\n",y);
  
  x[-1] = 122; /*** 境界を越えた書込 ***/
  
  printf ("x[0] -> %d\n",x[0]);
  printf ("y    -> %d\n",y);
}

実行結果は次の通り。x[-1]は変数yのことであり、yの値が書き換わってしまっ た。

x[0] -> 25
y    -> 72
x[0] -> 25
y    -> 122

実行時のスタック状況

↑小さい番地
  --------------------
  |        y         |
  --------------------
  |       x[0]       |
  --------------------
  |       x[1]       |
  --------------------
  |       ...        |
  --------------------
  |       ...        |
  --------------------
↓大きい番地

おまけ

配列の部分をポインタを使って書けば次の通り。

#include <stdio.h>

int main () {
  int x,y;
  int *px,*py;

  x = 25;
  y = 72;
  px = &x;
  py = &y;

  printf ("x(%p) -> %d\n",px,x);
  printf ("y(%p) -> %d\n",py,y);

  *(px - 1) = 122;
  
  printf ("x(%p) -> %d\n",px,x);
  printf ("y(%p) -> %d\n",py,y);
}
x(0xbffff8d8) -> 25
y(0xbffff8d4) -> 72
x(0xbffff8d8) -> 25
y(0xbffff8d4) -> 122
↑小さい番地
           --------------------
0xbffff0d4 |     y (4byte)    |
           --------------------
0xbffff0d8 |     x (4byte)    |
           --------------------
0xbffff0dc |       ...        |
           --------------------
0xbffff0e0 |       ...        |
           --------------------
↓大きい番地