CF25 Extension GArR Issue #02
漢字の「上」を使うとバグる件
ユーザからの報告を元に動作検証。
デバッグに関するメモ
漢字の「上」
漢字の「上」という文字を含めた行に対して指定されたデリミタで分割する際に不具合が発生するという報告。
G-方向キー上=38
G-方向キー下=48
サンプルとして上記文字列を変換した結果が以下。デリミタとして「改行」と「=」が指定されている二次元配列への変換例
-方向キー上
G-方向キー下
このように先頭1バイト分削られている行があるという不具合。
更に検証、上下ラインを入れ替えて試すと結果は
G-方向キー下=48
G-方向キー上=38
バグは発生しない。
なんらかの原因で1バイト分の情報が失われるケースがあるようだ。条件をもっとシンプルにする
下=48
上=38
上記例の場合はどうなるだろうか、結果は以下
下
=
この結果はかなり違和感を感じた。文字列の抽出位置が 1 バイトずれているのは間違いない。ではこの 1 バイト分の情報とは何?
まだ正体が分からない、次の条件として
下=48
38=上
こうすると?
下
38
動作は正常。
バグを起こすための必要条件は確定、ダメ文字( 文字コード ) の出現、その結果バグとして先頭1バイト分情報が喪失。( 本来ダメ文字ではなくバグのせいでダメ文字になってるだけ )
一応 Shift-JIS のダメ文字も含めて16進数で比較をしてみた。
区 点 JIS SJIS EUC UTF-8 UTF-16 字
05 29 253D 835C A5BD E382BD 30BD ソ
41 29 493D 955C C9BD E8A1A8 8868 表
30 69 3E65 8FE3 BEE5 E4B88A 4E0A 上
「ソ」と「表」は Shift-JIS のダメ文字。16進数で見るとどちらも5C
で終わっている点に共通がある。これは有名だけど今回はたぶん関係ない。関係ないけどバグを起こす原理は似たようなものと思われる。
「ソ」/「表」と「上」という文字コードには問題を起こす共通的な要素は無い。実際に「上」という漢字を「ソ」や「表」に置き換えても問題は発生しなかった。
問題を起こすその他の文字列
問題を起こす文字が他にも必ずあるはず、あれば必ず共通項がある。だからそれを探しだすことにした。
区 点 JIS SJIS EUC UTF-8 UTF-16 字
26 69 3A65 8DE3 BAE5 E998AA 962A 阪
28 69 3C65 8EE3 BCE5 E5BCB1 5F31 弱
26 71 3A67 8DE5 BAE7 E6A68A 698A 榊
30 18 3E32 8FB0 BEB2 E5BA8A 5E8A 床
26 71 3A67 8DE5 BAE7 E6A68A 698A 榊
30 69 3E65 8FE3 BEE5 E4B88A 4E0A 上
31 54 3F56 9075 BFD6 E8A88A 8A0A 訊
32 79 406F 90ED C0EF E688A6 6226 戦
42 74 4A6A 95E8 CAEA E6888A 620A 戊
最初に「坂弱」という候補を2つ試して外れ。バグは再現しない。SJIS の 16進数は無実だと分かっていたが念の為。
次に本命である UTF-8 から共通項を探す。
考え方としてはシンプルに末尾「8A」もしくは「88A」をターゲットに。いくつか調べたら「88A」が共通でバグを再現できる文字であることが分かった。つまり「戊」「訊」などがバグを発生させる共通文字。
utf-8 を16進数で符号化したバイト列が末尾 「88A」 の文字はバグを起こす、しかしこれだと意味が分からないため結論を出すことは一旦保留。現時点でダメ文字は「上」「戊」「訊」が判明したけれど、きっとまだある。
上記三つの文字は UTF-16 でもバイト列末尾が「0A」で共通してる。これで探して区別することもできるのかなという疑問。
よく考えると0x0a
は 16進数だと ASCII文字コードの改行( LF )
に相当。考え方としてはこちらが本命ではないか?考えを改める。そして utf-16 の16進数でバイト列末尾0a
の文字をすべて探す。
区 点 JIS SJIS EUC UTF-8 UTF-16 字
01 52 2154 8173 A1D4 E3808A 300A 《
01 86 2176 8196 A1F6 EFBC8A FF0A *
16 43 304B 88C9 B0CB E4BC8A 4F0A 伊
20 09 3429 8AA7 B4A9 E5888A 520A 刊
30 69 3E65 8FE3 BEE5 E4B88A 4E0A 上
31 54 3F56 9075 BFD6 E8A88A 8A0A 訊
32 52 4054 90D2 C0D4 E8848A 810A 脊
34 26 423A 91B8 C2BA E5B08A 5C0A 尊
36 63 445F 92DD C4DF E5908A 540A 吊
42 32 4A40 95BE CAC0 E5BC8A 5F0A 弊
42 74 4A6A 95E8 CAEA E6888A 620A 戊
45 57 4D59 9778 CDD9 E8B88A 8E0A 踊
45 60 4D5C 977B CDDC E9A48A 990A 養
46 78 4E6E 97EC CEEE E99C8A 970A 霊
http://www9.plala.or.jp/sgwr-t/c_sub/ascii.html
http://ash.jp/code/unitbl21.htm
該当は 14 文字。全て試して現時点でバグを起こすダメ文字であると認定。
utf-8 で 16進数バイト列末尾88A
はやはり共通ではなかった。末尾8A
は共通しているけれど全角アルファベット小文字のj
はダメ文字では無い。
区 点 JIS SJIS EUC UTF-8 UTF-16 字
03 74 236A 828A A3EA EFBD8A FF4A j
推測した通りの結果が得られた時点で大きく一歩前進。utf-16 と16進数バイト列末尾0A
の文字という重要なキーワードも手に入った。
こちらで仕込んだバグとして1バイト分単純な計算ミスとパースエラー。推測だけど末尾 0A の 16進数値な文字は改行として解釈されたのかもしれない。改行は不可視文字だから GArR の内部で除去される対象になってるけど、実際に削除はせず改行の分だけ1バイト分ずらしてメモリにコピーしてるはず。この1バイト分ずらすロジックが今回報告されたバグと現象が相似してる。
該当箇所を探す
すごくシンプルなバグだったら簡単に直せる。想像している通りだとすれば、ウィンドウズ環境で改行を\r\n
とするべきところを UNIX 環境用の\n
で済ませている可能性、とか。
少し考えたが、やりかねない。普段馴染みがあるのは\n
なので無意識に書いてる場合がある。
発見
本当に UNIX 用の改行方式“\n”
が指定してあったのをソースコードに見つけてしまう。ウィンドウズ用のプログラム書いていることをすっかり忘れていたのか…。
これで治れば色々と辻褄も全てあってしまう。
“\r\n”
これだけで治る?
直った
ダメ文字は無くなっていた。
次へ
前へ