【C言語】
オーバーフローと
オーバーランの違い
(overFlow VS overRun)

warning: unsigned conversion from ‘int’ to ‘unsigned char’ changes value from ‘305419896’ to ‘120’

警告: ‘int’ から ‘uint8_t’ への符号なし変換 {別名 ‘unsigned char’ } は、値を ‘305419896’ から ‘120’ に変更します

[-Woverflow]

■overFlowとは桁あふれ

void overFlow(void){    
    uint8_t  x ;
    x = 0x12345678 ;
    printf("1byteに16進8桁は入らず桁あふれして %x になる\n",x);
    fflush(stdout);
}

桁あふれ
計算結果が数値の表現範囲を超えること


■overRunとはメモリ破壊

void overRun(void){    
    uint8_t  x ;
    *(uint32_t *)&x = 0xAB ;
    printf("1byteしかない領域をキャストして4byteあるとコンパイラを騙す %X\n",x);
    fflush(stdout);
}

停止線位置通過
データが格納領域の範囲を超えること


bufferOverRunとbufferOverFlowその1

void bufferOverRun_bufferOverFlow1(void){    
    char    buf[BUFSIZ];
    char    c;
    printf("一桁の数字を入れてね");
    fgets(buf,BUFSIZ,stdin);
    //書式%dはint型4byte分を第3引数に書き込む
    //cは1byteしかないので3byteメモリ破壊する
    sscanf(buf,"%d",&c);
    printf("%dが入力されました\n",c);
    fflush(stdout);
}

頭にbufferが付くと
 bufferOverRunも
bufferOverFlowも
同じ意味で使われる場合が多く
データが格納領域の範囲を超えること
つまりメモリ破壊の意味。

bufferOverRunとbufferOverFlowその2

void bufferOverRun_bufferOverFlow2(void){ 
    char    buf[4];
    printf("四桁の数字を入れてね");
    fgets(buf,BUFSIZ,stdin);
    printf("%dが入力されました\n",atoi(buf));
    fflush(stdout);
}

これはバッファオーバーラン・バッファーオーバーフローの典型的な例で
4桁の数字を入れるのだから
4byteピッタリで宣言する
几帳面な人がよく起こすバグです。

bufは4byteしかないので
\n\0の考慮が抜けています。
4桁入力すると2byteメモリ破壊します。

まとめ(コンパイル可能)

#define     _CRT_SECURE_NO_WARNINGS 1
#include    <stdio.h>
#include    <stdlib.h>
#include    <stdint.h>
//桁あふれ  
//計算結果が数値の表現範囲を超えること
void overFlow(void){    
    uint8_t  x ;
    x = 0x12345678 ;
    printf("1byteに16進8桁は入らず桁あふれして %x になる\n",x);
    fflush(stdout);
}
//停止線位置通過
//データが格納領域の範囲を超えること
void overRun(void){    
    uint8_t  x ;
    *(uint32_t *)&x = 0xAB ;
    printf("1byteしかない領域をキャストして4byteあるとコンパイラを騙す %X\n",x);
    fflush(stdout);
}
//頭にbufferが付くと
//  bufferOverRunも
//  bufferOverFlowも同じ意味で使われる場合が多く
//  【データが格納領域の範囲を超えること】の意味。
//  不具合が即時発覚するとは限らず潜在化する場合が多い。
//  次のオプションは不具合検出に役に立ちます。
//      gcc     -Wall -Wextra -fsanitize=address
//      clang   -Wall -Wextra -fsanitize=address
void bufferOverRun_bufferOverFlow1(void){    
    char    buf[BUFSIZ];
    char    c;
    printf("一桁の数字を入れてね");
    fgets(buf,BUFSIZ,stdin);
    //書式%dはint型4byte分を第3引数に書き込む
    //cは1byteしかないので3byteメモリ破壊する
    sscanf(buf,"%d",&c);
    printf("%dが入力されました\n",c);
    fflush(stdout);
}
void bufferOverRun_bufferOverFlow2(void){ 
    char    buf[4];
    printf("四桁の数字を入れてね");
    //bufは4byteしかない\n\0の考慮が抜けてる
    //4桁入力すると2byteメモリ破壊する
    fgets(buf,BUFSIZ,stdin);
    printf("%dが入力されました\n",atoi(buf));
    fflush(stdout);
}
int main(void){
    bufferOverRun_bufferOverFlow1();
    bufferOverRun_bufferOverFlow2();
    overFlow();
    overRun();
}

このプログラムは環境によって
即時不具合が発覚するとは限りません。
問題なく動いてしまう場合もあり、
潜在化する場合が多いです。
※受け入れ試験の前日深夜に発覚したりします。


次のオプションは不具合検出に役に立つので
是非使ってみて下さい。
 gcc     -Wall -Wextra -fsanitize=address
 clang   -Wall -Wextra -fsanitize=address


追加:メモリリークとバッファオーバーランは全然別のバグ

#include <stdio.h>
#include <string.h>
int main(void){
    char    buf[16];
    //sizeof(char)*16と書きたかった
    strncpy(buf,__FILE__,   sizeof(buf)*16);
    puts(buf);
    fflush(NULL);

    //%buf[0]と書きたかった
    snprintf(&buf[16],16,
        "%s:%s:%d",
            __FILE__,__func__,__LINE__);
    puts(buf);
    fflush(NULL);
}

「strncpy メモリリーク」で検索すると上記のようなコードが結構ヒットするけれど、
メモリリークは解放漏れ、
バッファオーバーランはメモリ破壊で
全然別のバグです。