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