オーバーフローのプログラムのバグってどんな問題がおこるのかを新入社員に説明するために
わかりやすく実際のゲームのバグを通じて解説しようと試みたところ、
いざ情報をあつめたら、全部ドラクエだった件です。
(余談ですが、ドラクエ、大好きです。3予約しました!)
(1) カジノの大量のコインが10ゴールドで買えてしまう(ドラクエ4、ファミコン)
ドラクエ4のゲーム内施設カジノにおいて、
コイン1枚20ゴールドが定価なのですが、
大量発注(838861枚)すると4ゴールドで買えてしまう有名な裏技があります。
これは、支払いゴールドを計算するメモリ領域が24ビットであることに起因します。
つまり、
20G * 838861 = 16,777,220G
= 16,777,216 + 4G
= 2^24G + 4G
という感じで、24ビットでは収まりきれない金額になってしまいました。25ビット目が計算領域として必要でした。
かつ支払いゴールドとして参照する情報は24bitしか見ないので、4ゴールドと判定されてしまいます。
16,777,220Gを
bit列で表すと、
1|0000|0000|0000|0000|0000|0100|
|<- この範囲が支払Gの24bit部分 ->|
最上位の25bit目はオーバーフローしている
対策としては、一般的には32bitなどbit数を増やして桁溢れしないように計算するのがよいでしょう、
当時ではメモリカツカツだと思いますので、カジノコインの購入数を6桁-> 5桁に減らすんが良かったんじゃないかなーと思います。
(2) 8回逃げたら会心の一撃(ドラクエ4、ファミコン)
またまたドラクエ4です。
8回逃げるに失敗すると、その後かいしんのいちげき!を連発するようになるという裏技です。
なかなか仕組みが面白くて好きなバグです。
戦闘でつ買われるとあるメモリアドレスの4bitは下記のような割当になっているそうです
1 | 2 | 3 | 4 |
---|---|---|---|
呪文:パルプンテの会心の一撃フラグ | ときのすなフラグ | 逃げ失敗カウンタ1 | 逃げ失敗カウンタ2 |
ドラクエ4では、通常戦闘で、逃げるに失敗するごとに逃走確率が上がるように設定されており、
3回逃げるに失敗すると100%逃げられます。
→ これを実現するために、逃げ失敗カウンタで0〜3を管理するようにしています。
が、ボス戦では当然にげられないので4回目以降も逃げるに失敗します。
そうすると、逃げ失敗カウンタがオーバーフローして上位のビットを破壊しに行きます。
0回逃げ失敗状態
1 | 2 | 3 | 4 |
---|---|---|---|
0 | 0 | 0 | 0 |
呪文:パルプンテの会心の一撃フラグ | ときのすなフラグ | 逃げ失敗カウンタ1 | 逃げ失敗カウンタ2 |
3回逃げ失敗状態
1 | 2 | 3 | 4 |
---|---|---|---|
0 | 0 | 1 | 1 |
呪文:パルプンテの会心の一撃フラグ | ときのすなフラグ | 逃げ失敗カウンタ1 | 逃げ失敗カウンタ2 |
4回逃げ失敗状態
1 | 2 | 3 | 4 |
---|---|---|---|
0 | 1 | 0 | 0 |
呪文:パルプンテの会心の一撃フラグ | ときのすなフラグ | 逃げ失敗カウンタ1 | 逃げ失敗カウンタ2 |
8回逃げ失敗状態
1 | 2 | 3 | 4 |
---|---|---|---|
1 | 0 | 0 | 0 |
呪文:パルプンテの会心の一撃フラグ | ときのすなフラグ | 逃げ失敗カウンタ1 | 逃げ失敗カウンタ2 |
という流れで、逃げ失敗カウンタの2bit上に、たまたまパルプンテの効果で会心の一撃が出まくるフラグが存在していたため、
8回逃げ失敗カウンタをインクリメントすることで、会心の一撃が出まくるという仕組みでした。
以上の通り
- オーバーフローによって、見るべき値が消失する例
- オーバーフローによって、メモリ破壊が発生する例
の実例を有名バグから調べてみたら、たまたまどちらもドラクエ4にふくまれていたことに気づきました。
どうぞ、新人教育の参考情報や小ネタ話などにご利用ください。