先日、あるWebサービスのテストをしていたところ、UTF-8でなければいけないパラメータの文字列のなかに、
ASCIIの ESC(0x1b)
が混入していて、アプリがクラッシュするという問題に遭遇しました。
原因はパラメータにISO-2022-JPのキャラクタセットの文字列を渡していたためでした。
いくら入力データが不正でもアプリがクラッシュしてしまうのはまずいので、 入力データの検査を追加することにしました。アプリはPython3で書かれています。
文字列のなかに ESC
が混入しているかどうか、どうやってチェックするべきか考えていたところ、
Pythonにはisprintable()
という便利な関数があることを発見しました。
試してみると、ちゃんと ESC
を検出してくれます。めでたしめでたしということでテストコードを書いて
プルリクエストを作成しレビューに回します。
新規にバリデーションを追加するわけなので、不正データは弾いてくれるのはいいのですが、
いままで使えていた正常データに影響が出ては困ります。念の為、プロダクションのデータベースに残っている
過去データを吸い上げて、正常データが不正と判定されないかどうか調べることにしました。
しかしそこで驚きの結果が出ます。正しいデータなのに不正と判定されるものが頻発したのです。
原因は2バイトの空白文字 \u3000
でした。isprintable()
はこの文字が含まれると False を返します。
ASCIIの空白文字 0x20
はもちろん printable (True)
と判定されます。
2バイトスペースが印字不可とは驚きの挙動ですが、仕様書的には正しい動作のようです。
ESC
の存在を直に調べるコードに書き換えて、プルリクエストを再提出。
プロダクションリリース前に発見できて良かったです。知らずにリリースしていたら、 お客さまから多くの苦情を頂いていた事でしょう。くわばらくわばら。