1文字分のミスで大トラブル

http://www.asahi.com/national/update/1027/TKY200710270270.html


障害の引き金になったのが、2バイト(2進法で16けた)のデータだった。例えば改札機の場合、ネガデータは5451件分(6万5518バイト)を一区切りとして処理される。処理は4バイトずつ進めるため、最後に2バイト余る。全角ひらがなや漢字1文字分のデータ量だ。

 半端な2バイトも、件数がこの一区切りまでなら正常に処理されていた。だが、5452件以上になると「85件増すごとに5件の割合で、余った2バイトの処理を忘れる」(同社)というプログラムの欠陥があった。

 相互利用が始まった3月から9月下旬まで、ネガデータは障害が発生する件数に達していなかった。以後もたまたま障害の条件をすり抜けていたが、10月12日のデータは「5件」に合致して2バイトが欠落し、改札機が立ち上がらなくなった。

http://pc11.2ch.net/test/read.cgi/prog/1180240243/693


ネガデータは、サイズが大きいので、分割して送信するのが鉄則。
特にSuicaは、他に比べて利用書が多いのでネガデータ量が多い。

つまり
1)ネガデータを暗号化&パケットに分割して送信
2)受信機は、受信したパケットをいったんSRAM上に保持
3)すべてを受信した際に、パケットを連結して復号処理を行う
4)検証OKなら、FROM上にネガデータを書き込む

おそらく3)でこけた可能性が高い。ネガデータの処理は明細処理より簡単なはずなんでけどね。

http://www.itmedia.co.jp/news/articles/0710/12/news117.html


調べたところ、ネガデータに「ある長さ、ある件数」といった条件が重なった時、データが読み込めなくなるプログラム不具合が判定部側にあることが判明。このため、判定部はエラーを返しながらネガデータ読み込みのリトライをひたすら繰り返す状態に陥り、起動処理が止まった。

65518÷5451=12.019
ヘッダ+1件12バイトの固定長のデータであると思われる。
65518−5451×12=106(ヘッダの長さ)

  • データはヘッダ106バイト+件数×12バイトという構成
  • 64KBの静的バッファがあり、それを超えると区切って処理
  • 4バイト単位で装置側に送信
  • 残り2バイトのときに送信もれを起こし、受信側(装置)が無限ループ

とかそんな感じか。
85件中5件が残り2バイトになるパターンを調べてみると、64バイト毎に処理するとなるっぽい。

というわけで処理部分の想像

char buffer[65536];
if ( length <= 65518 ) {
  receive_data( buffer, length );
  process_data( buffer, length );
} else {
  while ( length >= 64 ) {
    receive_data( buffer, 64 );
    process_data( buffer, 64 );
    length -= 64;
  }
  int dword_size = length / 4;
  if ( dword_size > 0 ) {      // 直接こうじゃないだろうが結果としてはこんな感じ
    receive_data( buffer, length );
    process_data( buffer, length );
  }
}

送信もれはともかく、受信できずに無限ループはかっこ悪いです。