整数演算の誤った拡張や型の幅以上のシフト

整数演算の誤った拡張や型の幅以上のシフト

説明

intの乗算後に結果をlongへ変換しても、乗算時にオーバーフローした値がそのまま拡張されます。また、型のビット幅以上のシフトは、Javaのシフト距離の扱いにより意図と異なる結果になる場合があります。計算の正確性に関する問題であり、セキュリティへの影響は、その結果をサイズ制限やアクセス判断などに使うかどうかで変わります。

想定される影響

  • サイズ、個数、インデックスの計算誤り
  • 意図と異なるビットマスクやフラグ
  • 誤った中間結果による後続処理への影響

対処方法

  1. 乗算の前に、一方のオペランドをlongへ変換してください。
  2. オーバーフローをエラーとして扱う必要がある場合は、Math.multiplyExactを使ってください。
  3. シフト距離が対象の型のビット幅未満であることを確認してください。
  4. より広い結果が必要なら、シフト前に値の型を拡張してください。

例

乗算結果の拡張

変更前

java
public long calculateSize(int itemCount, int itemSize) {
    return (long) (itemCount * itemSize);
}

変更後

java
public long calculateSize(int itemCount, int itemSize) {
    return (long) itemCount * itemSize;
}

説明:

  • 変更前: キャスト前にintの乗算が行われるため、中間結果がすでにオーバーフローしている可能性があります。
  • 変更後: オペランドを先に変換し、乗算全体をlongの範囲で行います。

シフト演算

変更前

java
public int buildMask(int flags) {
    return flags << 32;
}

変更後

java
public long buildMask(int flags) {
    return ((long) flags) << 32;
}

説明:

  • 変更前: Javaのintのシフト距離には下位5ビットだけが使われるため、32ビットのシフトは意図した結果になりません。
  • 変更後: 先にlongへ変換し、64ビットの演算として実行します。

参考資料