[PHP-users 17812]Re: strftimeのバグ報告

Moriyoshi Koizumi moriyoshi @ at.wakwak.com
2003年 9月 11日 (木) 18:01:31 JST


小泉です。

現象確認できました。

(以下の例ではあえてフォーマット文字を使っていません。)

Z:\src\php-src-4-fresh\debug_ts>echo "<?php var_dump(strftime('12月')); ?>" | ic
onv -f Shift_JIS -t EUC-JP | php-cli.exe

"string(9) "12......"
"

で、原因は、PHP の strftime() が libc 固有の (≒プラットホーム固有の) 実装
に依存しているためです。

CRT のソースを追ったわけではないのですが、おそらく strftime() のフォーマッ
ト文字列は、Win32 の libc では、現在のロカールで規定された文字コードによっ
て書かれていると想定されるようになっていて、つまり、Shift_JIS (CP932) を与
えなくてはならないところに、EUC-JP を与えると、libc が混乱してしまうことが
あるということであり、結果、PHP の関数でも同様の現象が起こり得るというわけ
です。

もうちょっと技術的に言うと、「月」「日」といった漢字は、EUC-JP のコードマ
ップでは、それぞれ b7 ee と c6 fc という 2 バイトの列から表されますが、そ
れぞれの先頭バイトの b7 と c6 は、Shift_JIS では、半角カナに当たりますから、
Shift_JIS では、これらのバイト列は、1 つの文字ではなく、2 つの文字と解釈さ
れてしまいます。で、第 2 バイトに来ている ee と fc は、それぞれ Shift_JIS 
では、何らかのダブルバイト文字の第 1 バイトですから、strftime() の実装は、
そこから 2 バイトを問答無用、お構いなしに読んで、結果バッファにコピーしよ
うとします。

> 
> Smarty 2.5 で {html_select_date} を使用中に発見しました。
> {html_select_date month_format="%m月"} のように月のフォーマットを指定して展
> 開すると
> 
> <option label="01月*****" value="01">01月*****</option>
> <option label="02月*****" value="02">02月*****</option>
> 
> ***** の部分に余計な文字が付加されて文字化けを起こします。
> 文字化けの文字列は、一定ではありません。
> ブラウザー上でリロードすると違う文字化けが表示されます。

"%m月" => 25 6d b7 ee 00

上記は、PHP 内部での文字列表現を 1 バイトごとに 16 進数で表したものですが、
この場合だと、00 が文字列の終端を表すにもかかわらず、ee 00 を一つの文字の
ように扱ってしまいますので、バッファーオーバランしてしまいます。文字列の終
端以降のバイト列は、ヒープ領域にあり不定ですから、実行するたびにゴミの出方
が変化してしまうのです。また、最悪の場合は、アクセス違反となります。

もし、ユーザからの入力をチェックせずに、strftime() にそのまま渡していたと
して、その文字列が、上記のように strftime() 的に不正で、オーバランを引き起
こすものだとして、さらに、偶然、ヒープ領域に、たまたま重要なパスワードなど
が残されていたとしたら、十分セキュリティ上の脅威となり得ますが、strftime() 
に Shift_JIS を渡している限り、問題は起こりません。

従って、結論としては、国際化版の PHP を使い、Shift_JIS でコーディングされ
ることをお勧めするといった形になります。

バグといえばバグなのですが、PHP のバグであるかは微妙です。




PHP-users メーリングリストの案内