$Id: howto-efence.html,v 1.1 2000/07/05 13:43:38 sakane Exp $
%Hd: Electric Fenceを使ってみる

何?
環境変数
マニュアルで推奨されている使い方
その他


o 何?

自分の技術力を越えたプログラム書く時に超便利なツール。

できる事
	o バッファ・オーバーラン
	o バッファ・アンダーラン
	o 開放した領域を触る
	o サイズ 0の malloc

を見つけることができる。
コンパイル時に libefence.a をリンクする事で malloc(3)や free(3)を置き換える。

欠点は
	o 激しくメモリを使う。
	o プログラム動作が異常に遅くなる。

何はともあれ使ってみる。

	#include 

	#include 
	#include 

	int
	main()
	{
		char *c;

		c = malloc(4);
		c[3] = 0;
		free(c);

		exit(0);
	}

サイズ 4の領域の4番目に 0を代入するコードである。
当り前だが何の問題もなく正常終了する。
では、サイズ 4の領域の5番目を触るとどうなるか?

	int
	main()
	{
		char *c;

		c = malloc(4);
		c[4] = 0;
		free(c);

		exit(0);
	}

	% ./a.out 
	%

一見正常終了したように見える。が、Electric Fenceを使うと、

	% cc -Wall -Werror -g test1.c -L/usr/local/lib -lefence
	% ./a.out
	  Electric Fence 2.0.5 Copyright (C) 1987-1995 Bruce Perens.
	Bus error(core dumped)
	%

今度は Bus errorになる。gdbから実行すると、

	% gdb a.out
	(gdb) r
	Starting program: ./a.out 

	  Electric Fence 2.0.5 Copyright (C) 1987-1995 Bruce Perens.

	Program received signal SIGBUS, Bus error.
	0x8048765 in main () at test1.c:12
	12              c[4] = 0;
	(gdb)

となるので、どこが悪いか一目瞭然。
次は、開放した領域を触ってみる。

	int
	main()
	{
		char *c;

		c = malloc(4);
		free(c);
		c[3] = 0;

		exit(0);
	}

	% ./a.out
	  Electric Fence 2.0.5 Copyright (C) 1987-1995 Bruce Perens.
	Bus error(core dumped)
	%

同じく Bus errorになる。
こんな小さなコードでは、普通書いてる最中にどこが悪いか一目瞭然だけど、
と言うかこんなコード書かないけど、例を見て「おぉ!」と思った人は沢山居るはず。
少なくとも僕は「おぉぉぉっ!」と泣きました。泣いてないけど。

libefenceが有効になっているかは、Copyrightが表示される事でわかる。


o 環境変数

libefenceには、できる事で書いた機能を有効にするための環境変数が用意されている。

- EF_ALIGNMENT

サイズ 6の領域の7番目を触るとどうなるか?

	int
	main()
	{
		char *c;

		c = malloc(6);
		c[6] = 0;
		free(c);

		exit(0);
	}

	% ./a.out
	  Electric Fence 2.0.5 Copyright (C) 1987-1995 Bruce Perens.
	%

正常終了したように見える。EF_ALIGNMENT を 0 に設定して再度実行すると、

	% setenv EF_ALIGNMENT 0
	% ./a.out 
	  Electric Fence 2.0.5 Copyright (C) 1987-1995 Bruce Perens.
	Bus error(core dumped)
	%

デフォルトでは、境界内のオーバーランは見つけられない。
EF_ALIGNMENT を変更すると、この境界を変えることができる。
デフォルトは sizeof(int)なので、これを 0にすると厳密にチェックする。

- EF_PROTECT_BELOW

文字通りアンダーランを見つけることができる。
この環境変数に 1 をセットしないとアンダーランのチェックは有効にならない。
デフォルトは無効になっている。
セットするとオーバーランのチェックは無効になる。

	int
	main()
	{
		char *c;

		c = malloc(6);
		c[-1] = 0;
		free(c);

		exit(0);
	}

	% setenv EF_PROTECT_BELOW 1
	% ./a.out
	  Electric Fence 2.0.5 Copyright (C) 1987-1995 Bruce Perens.
	Bus error(core dumped)
	%

だけど、

	int
	main()
	{
		char *c;

		c = malloc(6);
		c[6] = 0;
		free(c);

		exit(0);
	}

	% setenv EF_ALIGNMENT 0
	% setenv EF_PROTECT_BELOW 1
	% ./a.out
	  Electric Fence 2.0.5 Copyright (C) 1987-1995 Bruce Perens.
	%

オーバーランをトラップすることはできなくなる。

- EF_ALLOW_MALLOC_0

1をセットすると malloc(0)をトラップしなくなる。

	int
	main()
	{
		char *c;

		c = malloc(0);
		free(c);

		exit(0);
	}

デフォルトはトラップする。

	% ./a.out 
	  Electric Fence 2.0.5 Copyright (C) 1987-1995 Bruce Perens.

	ElectricFence Aborting: Allocating 0 bytes, probably a bug.
	Illegal instruction(core dumped)
	%

EF_ALLOW_MALLOC_0 に 1 を設定すると、

	% setenv EF_ALLOW_MALLOC_0 1
	% ./a.out 
	  Electric Fence 2.0.5 Copyright (C) 1987-1995 Bruce Perens.
	%

トラップしなくなる。


o マニュアルで推奨されている使い方

1. libefence.aをリンクすべし。
2. とりあえずデバッガからプログラムを起動して、バッファ・オーバーランと
   開放した領域を触るのを直す。
3. EF_PROTECT_BELOW を設定してバッファ・アンダーランを直す。
7. EF_ALIGNMENTを 0 にしてさらにバッファ・オーバーランを直す。



o その他
	もちろん以下のような memory leakは見つけられないけど、どうにかして欲しい。

	int
	main()
	{
		char *c;

		c = malloc(4);
		c = malloc(4);
		free(c);

		exit(0);
	}

o EF_PROTECT_FREE
	これ何?デフォルトで使えてるような気もする。