JPCERT コーディネーションセンター

MET01-J. メソッドの引数の検証にassertを使わない

publicメソッドの引数の検証にassertを使わないこと。Java言語仕様 §4.10「assert文」には以下のように規定されている。

...パブリックメソッドの引数チェックにassertを用いるべきでない。たいていの場合、引数チェックはメソッド契約の一部を成しており、この契約はassertが有効であるか否かに関わらず、守らなければならない。

assertを引数の検証に使った場合に発生するもう1つの問題として、誤った引数があった場合、適切な実行時例外(たとえばIllegalArgumentExceptionIndexOutOfBoundsExceptionNullPointerException)をスローしなければならないという点が挙げられる。assertが失敗しても、適切な例外がスローされるわけではない。

違反コード

getAbsAdd()メソッドは、引数xyの絶対値の和を計算して返す。メソッドは引数の検証を行っておらず、「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)

Top へ

Topへ
最新情報(RSSメーリングリストTwitter