Visaカードで 23,148,855,308,184,500ドルの請求発生、原因はプログラムエラー 100
ストーリー by soara
今月のお支払い金額は200京円になります 部門より
今月のお支払い金額は200京円になります 部門より
あるAnonymous Coward 曰く、
Visaカード所有者に誤って23,148,855,308,184,500ドルの請求が発生するという事態が何件か起きていたそうだ(CNN.com, CNN.co.jp)。
本家記事によると、この請求された金額からどのようなエラーが発生していたかを導き出せるとのこと。恐らく保存されている数字は「23,148,855,308,184,500.00」の100倍、すなわち「2314885530818450000」という数字になる。この数字を16進数で表すと「20 20 20 20 20 20 12 50」となる。C/C++を触っているプログラマーなら何が起きたか、お分かりだろう。16進数の「20」はスペースであり、2進数でゼロが入力されるべき箇所にスペースが入力されたため、世界の GDPを超えるような天文学的金額の請求が発生したのでないかと考えられるそうだ。
なお、Visaは問題のプログラムエラーは既に修正済みと説明しているとのことだ。
マスターカードだと (スコア:5, おもしろおかしい)
"Priceless"
って印刷されてるんですかね?
むす人好きーさん (スコア:4, おもしろおかしい)
ムスジンスキーさんは当初、あまりの超高額な数字に借金まみれの自分を想像、まだ生まれてもいない孫や、その孫の代までずっーっと返済が続くのかと恐れおののいたという。
なんてお人好しな…
Re:むす人好きーさん (スコア:3, おもしろおかしい)
Re:むす人好きーさん (スコア:1, 参考になる)
残した借金のせいで、セワシのお年玉は「50円」ですよ。
Re:むす人好きーさん (スコア:2, すばらしい洞察)
なぜ相続放棄して借金をチャラにしないのかと子供の頃から不思議だった。
貧しいはずのセワシが、恐竜狩りやら何やらと贅沢を楽しんでいるあたり、未来の社会制度の歪みを利用したトリックがあるのかもしれない。
Re: (スコア:0)
Re:むす人好きーさん (スコア:1)
CNN.comの方に"Josh Muszynski, 22, of Manchester"とありますね。
そうするとムスジンスキーさんですかねえ、やっぱり。
Re: (スコア:0)
アレゲでなくてすまんのだが (スコア:3, 参考になる)
FM Fukuokaのモーニングジャムでこのことが報じられたときに、請求された人とクレジット会社の間で電話で2時間ぐらい押し問答があったらしいことに、パーソナリティのなかじーが引っかかっていたのが印象に残っている。
# 「押し問答しようがなかろうもん!」ってことで。
返却してれば世界一の金持ち (スコア:3, すばらしい洞察)
何を買ったか知らないがそれを返却してれば最高の金持ちになったかもしれない。
というかもし気づかずに返済日が来ていたらバンクオブアメリカはいきなり凄まじい負債が増えて驚いたかもしれない。
プロセッサ速度 4294967295MHz (スコア:3, おもしろおかしい)
LEXMARKのプリンタドライバさんには実力よりずいぶんと高く評価していただきました。
でも、LEXMARKのプリンタドライバさんは周波数ではない何かを感じたらしく、「お使いのコンピュータシステムはシステムの最低必要条件を満たしていません。ソフトウェアをインストールすることはできますが、最適な使用環境ではありません」と伝えてきましたとさ。
フレームのもと覚悟、でも言わずにはいられない (スコア:2, すばらしい洞察)
2 進数でゼロが ………
</blockquote>
2 進数だろうが、10 進数だろうが 0 は 0 なんだよ 8-)
Re: (スコア:0)
20が0x20のスペースだったとして普段0が0x30として扱われてない不思議も気になります
Re:フレームのもと覚悟、でも言わずにはいられない (スコア:2)
char型配列を用いて多バイト長整数の値を設定する関数があったとします。
数字が10進数文字列で保存されていたとすれば、
数字はちゃんと処理されてスペースが0x20のまま処理されたとしても、
例えば、"123"の値は 1*100 + 2*10 + 3になるのだから、
" 3"の値は 20*100 + 20*10 + 3になると考えるのが自然だが、
20*256^2 + 20*256 + 3になっているように見える。
数字が文字列でなくバイナリで保存されていてbyteごとに処理していたなら、0x20も妥当な数字として意味を持つはず。
数字が16進文字列で保存されているならば、例えば頭に4つ連続したスペースが入ると、
'0'から'f'には適切な処理が行われて、0x20はそのまま読み込まれるとしても
0x20*0x1000 + 0x20*0x100 + 0x20*0x10 + 0x20 = 0x22220
のように、頭に0x22が出てくるはず。
なので、値を設定する関数の間違いではないと思うのです。
つまり内部構造を理解せずに内部構造を直接いじったバカがいたのではないか、と。
多バイト長整数が
struct BigInt{
unsigned char nums[BIGINT_LEN];
};
のような感じで実装されていて、整数がバイナリで入っているとしましょう。
きっと、彼は、数字を右揃えで表示したかった。
どうすればいいか考えていたら、多バイト整数型が(unsigned) charの配列で実現されていることを発見した。
「そうか!数字は文字列として保存されてるんだ!」
→配列の頭に' 'を入れる
1を聞いて0を知れ!
Re:フレームのもと覚悟、でも言わずにはいられない (スコア:1)
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
int i;
char digit[8] = {0x70, 0x32, 0x40, 0x40, 0x40, 0x40, 0x40};
for (i = 0; i < 8; i++)
putchar(digit[i]);
putchar('\n');
exit(EXIT_SUCCESS);
}
おい、ヤナワ実行してみてくれ。
p2@@@@@
………
Re: (スコア:0)
Re:フレームのもと覚悟、でも言わずにはいられない (スコア:1)
Re: (スコア:0)
これは整数型の話ですよね?
バイナリエディタなら理解できるが (スコア:2, 興味深い)
HEXエディタ的なものでバイナリデータを直接いじっていて、修正箇所を0埋めにしたい時に誤ってスペースバーで消してしまい、0x20になってしまった、ということなら十分あり得るミスだと思うのだけれども(ASCIIダンプ上では空白になるので)
プログラムのミスやバグで0x00を0x20で埋めてしまうようなことってあるのだろうか?
もしタレコミの説が本当の原因だったとしたら、どうも人為的なデータの改竄ミスが起きていたのではないかと疑ってしまうのだが・・・
みんな忘れているぞ (スコア:1, 参考になる)
16進数の内部表現を10進数に変換して表示しているいう前提から、スペースパディング説が出てくるのだ。
なのでBCDだの文字列だのは本末転倒もいいところ。
Re:みんな忘れているぞ (スコア:1)
Re:みんな忘れているぞ (スコア:1)
原因を推測するのは、問題を理解してからにしようよ (スコア:1, 興味深い)
リンク先を読んだだけですが
複数人が同じ金額の被害にあっていることがわかります。タレコミも「何件か起きていた」と書いていますね。
誤請求を削除していることから、金額に誤りがあったのではなく、請求自体が誤りであったことがわかります。
つまり、本来の請求額がゼロパディングのミスで書き換わってしまったなどという推測は全て的外れです。
Re:原因を推測するのは、問題を理解してからにしようよ (スコア:1)
プリペイド? (スコア:1, 参考になる)
これを見て (スコア:0)
自殺した人間はいたのかどうか
もしいたならVisaが責任を持つのか
16進数の20はC/C++に特有なのか? (スコア:0, フレームのもと)
> C/C++を触っているプログラマーなら
じゃあ他の言語のプログラマーはEBCDICコードでも使ってるのでしょうか?
ASCIIコードは言語に依存しないですよ。(ISO8859でも、Unicodeでも、
16進数でいう20、10進数でいう32はスペースですからねえ)。
Re:16進数の20はC/C++に特有なのか? (スコア:1)
他の言語というか, それなりに抽象化が進んだ高級言語なら同一のデータが多義的に取り扱われるってことはありませんから.
そういう高級言語では文字はいかなる場合でも文字でしかありませんし, バイナリデータはバイナリデータとして取り扱われます. 共用体を使えば同一の記憶空間を複数のデータ種別で取り扱うことが可能ですが, これについても高級言語では共用体に格納されているデータ種別を管理していて誤操作を防ぐようになっていたりしますから. それに比べればCなんかだと共用体の型管理は無いし, それどころか型キャスト一発でどんなデータも変換できるとか, char型にしても根本的に文字ではなくて8bitのバイナリデータに過ぎないとか
そういう意味からすれば, ASCIIだろうがEBCDICだろうが文字コードという発想に至るだけで, それなりにCの様な低級言語/システム記述用言語なりアセンブラなりに親しんでいると思ってよいでしょう.
charは8ビットですらないかも (スコア:2, おもしろおかしい)
言語使用上は8ビットと定義されているわけでもないしなぁ。
ではおまえは何者なのだ!>char
#ギターを弾く人ではない
屍体メモ [windy.cx]
Re:16進数の20はC/C++に特有なのか? (スコア:1, すばらしい洞察)
American Standard Code for Information Interchangeの略称だって忘れちゃったんですか?
Re:16進数の20はC/C++に特有なのか? (スコア:1, おもしろおかしい)
じゃぁC/C++プログラマーがEBCDICコードを使ってることはないのでしょうか?
C/C++は文字コードに依存しないですよ。\0の値は0とは限らないですよ!
あと、EBCDICコードって書くとコードコード。
Re: (スコア:0)
おれが16進数を覚えたのはMSX-BASICでスプライトのパターンを作るためだったはず。
2進数の方が直感的だろうけど、かったるいし。
ASCIIコードも、だいたい覚えてた。いまは忘れたけど。
次に16進数を触ったのはマシン語をハンドアセンブルでやったときかな。
Cを勉強したのはずっと後になってから。
Re: (スコア:0)
COBOLだと0x20は'0'で' 'は0x40だそうです。
# もうやだこの会社
Re:16進数の20はC/C++に特有なのか? (スコア:3, 興味深い)
フレームワークなんかがトラブル防止のために0x00をエスケープして消しちゃうシステムも普通にあったりします。クレジット会社のシステムに連結するところにそんなのが組み込まれてる可能性も否定できないでしょう。
(バージョンアップでセキュリティ対策としてそんな仕様変更が組み込まれ、技術者がその辺を理解しないままバージョンアップしちゃった、とか普通にあり得ます。)
ついでに、送られてきた情報のバイト数を見て「文字列なのか数値なのか」を判断するようなシステムも実際に日本の某銀行では稼働していたりするので、例えば
0x31 0x00 0x30 0x00(UTF-16LEの文字列で「10」)
が、0x00をエスケープされた結果
0x31 0x30 となり、バイト数が2バイトしかなかった為に「整数型」と判断された挙げ句、「12592(10)」と解釈される、等と言うことはあってもおかしくありません。
(「2バイトの時は整数型、それ以上なら文字列として扱う」なんて仕様が本当にあったりする。もちろん「文字が1文字だけ送られてくることは仕様上ありえない」のが前提。)
さて、どっちが馬脚なのやら。
# 上に書いた「某銀行」の中の人なのでAC
# 仕様として正しいとは思わないけどね、自分も。
Re: (スコア:0)
どうでもいい枝葉末節にそんな長文で突っ込んで、何か楽しいのかな?
「それはasciiとUTF-8だけなので注意。UTF-16では0x20 0x00になったりします」
と1行書けば済むのに。
Re:16進数の20はC/C++に特有なのか? (スコア:1)
その枝葉末節をおろそかにするところにバグは潜むわけで強調したくなる理由はわかる。
#ところで引用分までいれて空白込みの238文字(引用抜き空白込みで163文字)って長文か?
#楽しいかどうかは本人次第だろうし、丁寧に例まで挙がってて私には#1607108よりは「参考になる」よ?
#馬脚云々は余計かもしれないけど、コメント全体としては「フレームのもと」とは思えないな。
Re: (スコア:0)
COBOLでも、こんなこと起きるの? (スコア:0)
エラーの内容を推測するより、 (スコア:0)
こんなはっきりした間違いが残ったということは全くテストされていないとしか思えない。
レアケースだろうが、プログラムした範囲はテストするものじゃないのか。
修正などで手が入った箇所ならなおさら。
つまり、未テストのコードがあとどれ位あるか・・・
Re:疑わしい (スコア:1)
Re:疑わしい (スコア:1)
請求金額は12ドル50セントでしょう。他国のタバコの値段など知りませんが、それならちょっと高いかな、くらいですし。
全部文字列のまま突っ込んだから文字列に含まれていた0x20が頭に残っていたって方が、頭にパディングを入れるためにわざわざ0x20を付加したっていう説明よりすっきりしませんか?
Re:疑わしい (スコア:1)
Re:疑わしい (スコア:1)
逆に、米国で、煙草1箱$1.94は信じがたい安さだと思いますが...
#1607126 [srad.jp]の、$46.88だかが化けているという方が、1カートン(10箱)をまとめて買った金額として納得のいくような。
#安い煙草があるんだろうか。
限度額チェック (スコア:1)
だから限度額のチェックって、支払いの際に行われて、請求する際には行われていない
と思うよ。
ただ、原則どおり運用していれば限度額≧請求額だよなあ。
だから (スコア:1)
今回のミスって、請求時のミスなんじゃないの?
Re:限度額 (スコア:1, すばらしい洞察)
手数料どころか商品の代金さえも回収できませんよ
Re:限度額が反映されないのは (スコア:1, 興味深い)
> BCDコードを文字列と誤認してスペースをパディングするコードを書いたのではないかって意見が一番もっともらしい気がします。
違うよ。
> 恐らく保存されている数字は「23,148,855,308,184,500.00」の100倍、すなわち「2314885530818450000」という数字になる。この数字を16進数で表すと「20 20 20 20 20 20 12 50」となる。
表示された数字を16進数化しなければ'20'は出てこないんだから。
本来$12.50の請求に'20'をパディングしてしまい、BCDデータを16進数と見なして表示するバグも入っていないと
> Visaカード所有者に誤って23,148,855,308,184,500ドルの請求が発生するという事態が
こうならないんだが、さすがに後者は極めて考えにくい。
Re:限度額が反映されないのは (スコア:1)
勘定なので、BCD表現を含む固定小数点数というのは順当だと思います。
ただ、やっぱり、請求するときに起きてるように思います。
この二本立てじゃないでしょうか。
前者は微妙に思えますが、まあ、どうでしょうね。
Re:限度額が反映されないのは (スコア:1, 興味深い)
違うよ。GIGOというものがあってね
ここからわかることは
1. 請求額の計算かそれより前の処理のどこかで、内部表現に16進数が使われている可能性が高い(BCDや文字列ではなく)
2. 1と同じかそれより前の処理のどこかで、ゴミデータが紛れ込んだ
3. 1の数字は2のゴミかその加工された子孫だろうが、そのものではないかもしれないし、Negative Balance Feeの根拠となったゴミとは祖先を共通とする異なるゴミかもしれない。
わからないことは
・それ以外の処理については外部からは全くなにもわからない。内部表現などもってのほか。
Re:限度額が反映されないのは (スコア:1)
なるほど、エラーのせいで、買い物していないゴミデータが請求されていたということですね。
買ってもいないのに請求は予想外でした。(#1607508) [srad.jp]からするとそうなのかも知れませんね。
# $46.88を8バイト長でーとか考えてたんですが、
# 単純なゴミ入れゴミ出しだったということですね。