mezzofantiにおける整数オーバーフローの問題
mezzofantiはOCRエンジンtesseract-ocr使って実装されたAndroid向けアプリです。Android端末のカメラで撮影した写真をOCRエンジンを使って文字データに変換し、さらにGoogle Translateを使って各言語に翻訳してくれる優れモノですが、このアプリには整数オーバーフローに起因するバグが存在することが報告されています。
問題はGetFreeSpaceB()メソッドにおけるSDカードの容量計算にありました。それでは早速問題のコードを見てみましょう。
mezzofanti/AssetsManager.java: /** * @return the free space on sdcard in bytes */ public static long GetFreeSpaceB() { try { String storageDirectory = Environment.getExternalStorageDirectory().toString(); StatFs stat = new StatFs(storageDirectory); return stat.getAvailableBlocks() * stat.getBlockSize(); } catch (Exception ex) { return -1; } }
このメソッドでは、StatFsクラスのgetAvailableBlocks()とgetBlockSize()メソッドを使ってSDカードの空容量(バイト数)を計算しようとしています。これらのメソッドの返り値はint型であるため、乗算はint型の幅で行われます。int型の最大値は2,147,483,647(およそ2GiB)です。従って、これより大きな値は負の値(あるいはラップアラウンドして意図しない正の値)になってしまい、アプリの利用を妨げる結果となりました。
このコードを修正するには、前述のアプローチ2で紹介したアップキャストの手法を用い、long型の幅で演算するようにキャストすると良いでしょう。
return (long)stat.getAvailableBlocks() * stat.getBlockSize();
型変換にもご注意を
ここまで、整数の算術演算に関する整数オーバーフローの問題について見てきました。もう一つ、整数に起因する大きな問題として、型変換があります。整数をより小さな型へ変換する場合や、浮動小数点数を整数に変換する場合など、変換前の値が変換後の型で表現できる範囲に収まっているかどうかをチェックする必要があります。今回は紹介しませんでしたが、「NUM12-J. 数値型の縮小変換時にデータの欠損や誤解釈を引き起こさない」に詳しく解説しています。そちらも併せてご覧ください。