gccで、配列の範囲を超えてアクセスしてる人を探してぶっ殺したい - 揮発性のメモ2
gccで、構造体の中の配列の範囲を超えてアクセスしてる人を探してぶっ殺したい。
しかし、 -fsanitize=address で検知できるのは「構造体をはみ出たかどうか」のみである。
配列の範囲は -fsanitize=bounds で検知する
サンプルコード
#include <stdio.h> struct hoge { int i; char a[15]; }; int main() { struct hoge hoge = {}; printf("sizeof(hoge)=%ld\n", sizeof(struct hoge)); hoge.a[15] = 1; // ★A printf("%d\n", hoge.a[15]); hoge.a[16] = 1; // ★B printf("%d\n", hoge.a[16]); return 0; }
gcc -g -fsanitize=address sani.c
構造体が配列にぴっちりしているとき
struct hoge { char a[15]; };
struct hoge のサイズは 15バイト(char 15バイト)となる。
よって、hoge.a[15] は配列を超えているし構造体もはみ出ているので検知される。
構造体がアライメントに合わされてパディングがついてるとき
struct hoge { int i; char a[15]; };
struct hoge のサイズは 20バイト(int 4バイト + char 15バイト + パディング 1バイト)となる。
よって、hoge.a[15] は配列を超えてはいるが構造体の中なので 検知されない。
hoge.a[16] は構造体をはみ出ているので検知される。
構造体で配列の定義が先になっているとき
struct hoge { char a[15]; int i; };
struct hoge のサイズは 同じく20バイトとなる。
しかし、配列を超えても超えても次の変数があるので
hoge.a[15] も hoge.a[16] も構造体の中であるため検知されない。
-fsanitize=bounds
sanitize=bounds ならどこの配列だろうと範囲越えをチェックできる
gcc -g -fsanitize=address -fsanitize=bounds sani.c
やったぜ