publicメソッドの引数の検証にassertを使わないこと。Java言語仕様 §4.10「assert文」には以下のように規定されている。
...パブリックメソッドの引数チェックにassertを用いるべきでない。たいていの場合、引数チェックはメソッド契約の一部を成しており、この契約はassertが有効であるか否かに関わらず、守らなければならない。
assertを引数の検証に使った場合に発生するもう1つの問題として、誤った引数があった場合、適切な実行時例外(たとえばIllegalArgumentException、IndexOutOfBoundsException、NullPointerException)をスローしなければならないという点が挙げられる。assertが失敗しても、適切な例外がスローされるわけではない。
違反コード
getAbsAdd()メソッドは、引数xとyの絶対値の和を計算して返す。メソッドは引数の検証を行っておらず、「MET00-J. メソッドの引数を検証する」に違反している。したがって、整数オーバーフローが発生する場合や、引数のいずれかもしくは両方がInteger.MIN_VALUEである場合、誤った計算結果を返してしまう。
public static int getAbsAdd(int x, int y) { return Math.abs(x) + Math.abs(y); } getAbsAdd(Integer.MIN_VALUE, 1);
違反コード
以下の違反コード例では、assertを用いてパブリックメソッドの引数を検証している。
public static int getAbsAdd(int x, int y) { assert x != Integer.MIN_VALUE; assert y != Integer.MIN_VALUE; int absX = Math.abs(x); int absY = Math.abs(y); assert (absX <= Integer.MAX_VALUE - absY); return absX + absY; }
assertによるチェックの条件自体は正しい。しかし、assertを無効にしてコードが実行されると、検証コードは実行されない。
適合コード
以下の適合コードでは、メソッドの引数の検証において、Math.abs()に渡す値がInteger.MIN_VALUEでないこと、また、整数オーバーフローを引き起こす値ではないことを確認している。
public static int getAbsAdd(int x, int y) { if (x == Integer.MIN_VALUE || y == Integer.MIN_VALUE) { throw new IllegalArgumentException(); } int absX = Math.abs(x); int absY = Math.abs(y); if (absX > Integer.MAX_VALUE - absY) { throw new IllegalArgumentException(); } return absX + absY; }
別の解決策としては、longを使用して加算を行い、演算結果をlong型のローカル変数に保存するという方法もある。この方法をとるのであれば、結果のlong値がintの幅で表現できる範囲に収まることを確認しなくてはならない。この確認に失敗するということは、intの幅では加算が整数オーバーフローを引き起こすことを意味する。
リスク評価
メソッドの引数の検証にassertを使うと、誤った計算、実行時例外、プログラムの制御フローに関する脆弱性を引き起こす恐れがある。
ルール | 深刻度 | 可能性 | 修正コスト | 優先度 | レベル |
---|---|---|---|---|---|
MET01-J | 中 | 中 | 中 | P8 | L2 |
関連ガイドライン
MITRE CWE | CWE-617. Reachable assertion |
参考文献
[Daconta 2003] | Item 7: My Assertions Are Not Gratuitous |
[ESA 2005] | Rule 68: Explicitly check method parameters for validity, and throw an adequate exception in case they are not valid. Do not use the assert statement for this purpose |
[JLS 2005] | §4.10 The assert statement |
翻訳元
これは以下のページを翻訳したものです。
MET01-J. Never use assertions to validate method arguments (revision 28)