[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[FDclone-users:00838] Re: FreeBSD/ports for 7.0R



 しらいです。

In Message-Id <20081115184922.62C5B48068C@yuka.unixusers.net>
        Takashi SHIRAI <shirai@unixusers.net>writes:
>  しらいです。

>  もう少し深く追ってみました。先の mail で patch を当てた箇
> 所の関数は、巡り巡って自身を再帰的に呼び出しているのですが、
> gcc の最適化によって reentrant になっていないようです。
>  多分、私の書いたコードのせいではないと信じたいのですが、そ
> もそも再帰的に呼ばれないようにしておいた方が安全だと思うので、
> また別の patch も作ってみました。

 何だかこの書き方だと gcc のせいにしてしまっているようです
けど、ようやく原因が判明したので報告しておきます。

 今回の現象は確かに compiler に依存していましたが、これはそ
の compiler のバグではなくて実装依存ということで、コードをき
ちんと書くことで回避可能でした。
 「n = ++n」なんて記述をすると「結果が保証出来ない」旨の警
告を吐かれると思いますが、今回の一件もこれに近い話で、実装依
存で保証し切れないコードを私が書いていました。


> -# if	defined (DEP_KANJIPATH) || defined (DEP_ROCKRIDGE)
> -			openlist[n].path =
> -				strdup2(convput(conv, path, 0, 1, NULL, NULL));
> -# endif

 この patch に書かれている openlist という構造体配列は動的
にメモリ確保され、この関数内の上の方で realloc() されていま
す。
 realloc() はご存知のとおり確保されたメモリのサイズを変更し、
場合によってはポインタ値を変更しますので、この関数に入った時
と出ていく時では異なる値になり得ます。

 さて、この関数は convput() の中で辿り辿って再帰的に呼ばれ
ているので、comvput() を呼ぶ前と返って来た時とでは値が異なる
可能性があります。
 一般的な compiler では代入すべき変数 openlist[n].path のメ
モリ上の配置アドレスは、実際に代入を行なう直前に確定されるの
で、関数convput() の処理が完了してから決まります。
 ところが、ある種の gcc はこのアドレスを convput() の呼出し
前に確定してしまいます。このため想定外の代入が行なわれてしま
うのです。

 アドレス確定後に呼出された convput() が openlist 値を変え
てしまうと、先に確定したアドレスは最早無関係の領域なので、そ
こに代入を行なうことで buffer overflow が生じます。
 一方、本来代入すべきアドレスには何も代入されないので、何ら
かの期待されない値が格納されたままになります。今回のケースで
は NULL が入ったままになっていました。
 これらの誤った代入により、NULL pointer をアクセスしに行っ
て core を吐いて freeze していたのが今回の現象だと思います。

 結局、openlist[n].path への代入を、convput() の呼出しと異
なる行で行なうことで、この compiler のお節介は回避可能なので、
二つの patch はどちらも有効になりますね。


>  再現性に乏しいのでどちらの patch が有効なのか自信がありま
> せん。[FDclone-users:00836] の patch とこれと両方試してみて
> 貰えないでしょうか。

 個人的にはやはり後から作った方の patch の方がより安心出来
ると思うので、もし UTF-8 directory の freeze も両 patch で修
正されるようなら、こっちを採用するつもりです。

                                               しらい たかし