Bug Collection
Software Bugs

Y2K — ある UNIX アプリケーションの場合

UNIX には 2000 年 (y2k) 問題はない、あるのは 2038 年問題だ——という方もいらっしゃるかも知れない。 しかし、そうとばかりも言い切れない。 UNIX カーネルには問題がなくても、その UNIX 上で実行されるアプリケーション・プログラムはどうか。 日付の年号を西暦の下 2 ケタで表現しているならば、そのアプリケーションは 2000 年問題を抱えている可能性がある。 さらに、西暦年号を 4 ケタすべて用いているものであっても、2000 年問題をはらんでいる可能性は完全には否定できない。 そして、そんなアプリケーションが実際に存在するのである。

ここに述べるのは、某企業の UNIX システム上で (たぶん今も) 実際に運用されているあるアプリケーション・プログラムについてである。 そのアプリケーションは、C 言語の標準ライブラリ関数に対するプログラマーの理解不足のために、あるいはプログラマーが UNIX をよく知らなかったために、本来ならあるはずのない 2000 年問題をその中に抱え込むことになってしまった、いわば不幸なプログラムである。

その某企業の××システムは 1996 年に書かれたものであるが、2000 年問題を考慮してか、日付の年号を西暦 4 ケタで表示ないし印字するようになっていた。 にもかかわらず、2000 年問題はやや毛色を変えて紛れ込んでいたのである。 問題は、ログファイル出力ルーチンにあった。 そこでは、4 ケタの西暦年号を得るために次のような C コードを用いていた。

int year;
time_t t;
struct tm *p;

t = time(NULL);
p = localtime(&t);
if (p->tm_year >= 70 && p->tm_year <= 99)
	year = p->tm_year + 1900;
else
	year = p->tm_year + 2000;

処理の内容を説明すると、まず time() システムコールによって現在の時刻を獲得する。 この値は 1970 年 1 月 1 日 00:00:00 (UTC) からの経過秒数であるため、標準ライブラリ関数 localtime() を使って年月日時分秒の形式に分割する (結果は localtime() が内部に持つ tm 構造体に格納される)。 そして、そのうちの年の数値 (tm_year) について、それが 70 以上 99 以下である場合には 1900 を、それ以外の場合には 2000 をそれぞれ加算して西暦年号 (year) を求めている。 つまり、巷でよく見かけるインチキな 2000 年対応の方法をここでも適用しているわけである。

tm 構造体のメンバー tm_year に西暦年号の下 2 ケタが格納されるものであるならば、上記の処理は一応正しいと言えるかもしれない。 だが、実際には、tm_year に格納されるのは西暦 1900 年からの経過年数である。 したがって、たとえば西暦 2000 年の場合、tm_year には 100 が格納される。 つまり、上の処理では西暦 2000 年を 2100 年としてしまうのである!

私は上のコードを見たときすぐに気づいたが、それを修正できるような立場にはなく、また、ログファイルにしか影響を及ぼさない実害のないバグであったので、そのままにしておいた。 他の部分で何か問題が起こらないかぎり、このログファイルの内容が見られることもあるまい。 もっとも、こんなバグを抱えているのだから、そのアプリケーション内部には他にどんなバグが潜んでいるか知れない。 問題はすぐに発生する可能性もある。 そうなったとき、ログファイルを見た人がどんな顔をするか、そしてその後どんな事態が展開するかを考えると、想像するだけでも楽しいことではある。

(1999/07/27)



1999/07/27 公開
2006/03/21 更新
面独斎 (Mendoxi)
mendoxi@cam.hi-ho.ne.jp