【C言語】
メモリ破壊
Out of bounds,
Off-by-one Error

warning: array subscript 10 is outside array bounds of ‘char[10]’

警告:配列の添え字 10 は ‘char[10]’ の配列境界外です。
[-Warray-bounds]

■1.初歩的な間違い

#include <stdio.h>
#include <string.h>
int f1(void)
{
    int     ary[10]={0};
    //ダメ:参照できるのはary[0]~ary[9]まで
    return  ary[10];
}

配列は ary[10]で宣言したら、
参照できるのはary[0]~ary[9]までです。
ary[10]は参照できません。
ary[10]を参照すると未定義動作となり何が起きるかわかりません。


■2.回り過ぎ(<と<=を間違える)

int f2(void)
{
    int ary[20];
    //ダメ:一回まわりすぎ
    for(int i=0;i<=20;i++){
        ary[i] = 0;
    }
    return  ary[0];
}

一回多く回りすぎです。
i <= 20 ではなくて
i < 20 か
i<= 19 です。
配列の要素数が明示されている
i < 20 を推奨します。

バグの多くは境界で発生するので
以上・以下・未満・超える
を正確に使いわけましょう。


■3.回り切ったカウンタで参照

int f3(void)
{
    int ary[30]={0};
    int i;
    for(i=0;i<30;i++){
        ary[i] = 0;
    }
    //ダメ:回り切ったiは30になってる
    return  ary[i];
}

forループを回り切ると添え字の i は30になっているので
ary[30] の配列境界外参照となります。
回り切った時のiを添え字に使う時は注意してください。


■4.文字列転送にmemcpyを使う間違い

char buf[1024];
void f41(void)
{
    //ダメ:空文字列””の後ろを領域外参照する
    memcpy(buf,"",sizeof(buf));
}
void f42(void)
{
    //推奨はしないがbufは全部0クリアされる。
    strncpy(buf,"",sizeof(buf));
}

文字列配列の初期化に 
f41()のようにmemcpy()を使用すると
空文字列””の後ろを参照してしまうので
文字列リテラル領域外参照となります。


f42()のようにstrncpy()を使用すると
領域外参照は発生しませんが無駄な動きをするので推奨はしません。

文字列配列の初期化をしたいならば全部0クリアする必要はなく
buf[0] = ‘\0’の先頭だけ初期化で必要十分です。


■5.ガード処理が甘い

#define MAX 4
int f5(int idx)
{
    int buf[MAX] = {'A','B','C','D'} ;
    if(idx > MAX) {//ダメ:idx == MAX を許容する
        return  -1;
    }
    return  buf[idx] ;
}
int main(void)
{
    printf("%c\n",f5(MAX)   );
}

添え字のガード条件が誤っているので idx が MAXの時も
制御が下へ行ってbuf[MAX]を参照してしまいます。
if(idx > MAX) { ではなくて
if(idx >= MAX) {でしょう。


■6.¥0の考慮抜け

warning: ‘__builtin_memcpy’ writing 5 bytes into a region of size 4 overflows the destination

警告:サイズ4の領域へ5バイト書き込み
[-Wstringop-overflow=]

#include    <string.h>
void    f6(void)
{
    char    buf[4];
    strcpy(buf,"1234");
}

終端文字¥0の考慮が抜けています。
コピー先が4byte しかないのに5byteコピーしました。

参考:

ARR30-C. 境界外を指すポインタや配列添字を生成したり使用したりしない

CWE-125: Out-of-bounds Read

CWE-787: Out-of-bounds Write

CWE-193: Off-by-one Error