>> On Sun, 21 Dec 2003 01:07:58 +0900
>> 「土」== tsuchiya@xxxxxxxxxxxxxxxxxxxxxxx (TSUCHIYA Masatoshi) said as follows:
土> 自分の保存しているメール全てを対象とするインデックスを作成して,便
土> 利に利用しているのですが,最近になって field search がうまくいかな
土> くなって困っています.
他の方の環境では再現しないと言うことなので,気合いを入れ直して,
debugger で真面目に追い掛けました.
最初に namazu_core() の動作を追い掛けました.nmz_search() の返り値は以
下のようになっていました.
(gdb) p hlist
$85 = {num = 1, stat = SUCCESS, data = 0x805a088}
(gdb) p hlist.data
$86 = (struct nmz_data *) 0x805a088
(gdb) p *hlist.data
$87 = {score = 1, docid = 43070, idxid = 0, date = 1054603541, rank = 1,
field = 0x0}
ここで,docid を強引に 43071 に変更してから print_result() 以下の処理
をさせてみると,正しく [emacs-w3m:05000] のメールが結果として表示され
ましたから,docid の値が間違っていることがはっきりしました.
次に,nmz_regex_grep() の以下の部分で break させて見て,その時の状態を
調べました.
if (-1 != nmz_re_search(rp, buf, strlen(buf), 0, strlen(buf), 0)) {
/* Matched */
n++;
if (n > max) {
(gdb) p i
$88 = 43070
(gdb) p buf
$89 = "[emacs-w3m:05000] make-temp-file\0..."
この結果から,buf には正しい個所が入っているにも関わらず,docid を求め
ている一時変数 i の値がおかしくなっていることが分かります.
それで,このループの上部を良く見てみると,
for (i = n = 0; fgets(buf, BUFSIZE - 1, fp); i++) {
if (buf[strlen(buf) - 1] != '\n') { /* too long */
i--;
continue;
}
という fgets() の成功・不成功を改行文字の存在で確認している部分があり,
これが怪しそうだと目星をつけて,break させてみました.すると,
(gdb) p buf
$90 = "[Mew-dist 11182] Re(2): +Backup (h\e.A\0 h\0 h\0...)\n\0..."
と,NULL文字を含む文字列が buf に代入されていることがあり,この場合は
fgets() は成功しているにも関わらず,buf[strlen(buf) - 1] != '\n' が成
り立ってしまうために,docid の計算が狂っているようです.
なお,ここで問題になっているメールの表題は,以下のようになっています.
$ egrep "^Subject:" ~/Mail/comp/emacs/mew/430 | od -t x2z
0000000 7553 6a62 6365 3a74 5b20 654d 2d77 6964 >Subject: [Mew-di<
0000020 7473 3120 3131 3238 205d 6552 3228 3a29 >st 11182] Re(2):<
0000040 2b20 6142 6b63 7075 2020 2020 2020 2020 > +Backup <
0000060 2020 2020 2020 2020 6828 2e1b 1b41 694e > (h..A.Ni<
0000100 6820 4e1b 2069 1b68 694e 2e2e 292e 000a > h.Ni h.Ni...)..<
0000117
試しに,この問題のメールと,別の普通のメール2通のみを含むディレクトリ
を用意して,新たにインデックスを作成したところ,問題が再現できました.
他の人でも,NULL文字を Subject: に含むようなメールを作れば,追試可能だ
と思います.
さてそうすると,対策としては2通り考えられます.
(1) 1行を読み込むことに失敗しているかどうかを判定する部分を頑健にする.
(1.1) 末尾に添付したパッチを適用する(かえって脆弱かも)
(1.2) fgets() の代わりに,取得された文字列数が分かる getline() 関
数を使う.
(2) インデックス作成時にNULL文字を取り除いておく,またはエスケープして
おく.
検討をお願いします.
;; ふと気になったのですが,MIME 文字列を decode すると NULL 文字になっ
;; てしまうような場合は大丈夫でしょうか?
;;;; なお,環境は Debian GNU/Linux です.
--
土屋 雅稔 ( TSUCHIYA Masatoshi )Attachment:
namazu.patch
Description: Binary data