Java言語仕様§12.5「クラスインスタンスの作成」には以下のように記されている。
C++ とは異なり、プログラム言語 Java では新規クラスインスタンス生成中のメソッドディスパッチに対する代替規則を規定していない。オブジェクトの初期化中に、サブクラスでオーバーライドしたメソッドを起動すると、新たなオブジェクトの初期化が完了する前であっても、オーバーライドしたメソッドのほうが起動される。
オーバーライド可能なメソッドをオブジェクトの構築時に呼び出すと、初期化の完了していないデータが使用され、実行時例外や予期せぬ結果を招く恐れがある。また、オブジェクトの構築が完了する前にthis参照が外部に晒され、初期化完了前のデータあるいは矛盾したデータを、他のスレッドに晒す危険性がある。詳しくは「TSM01-J. オブジェクトの構築時にthis参照を逸出させない」を参照。結論としては、コンストラクタにおいては、final宣言もしくはprivate宣言されているメソッドのみを呼び出すべきである。
違反コード
以下の違反コードでは、doLogic()メソッドは初期化される前のデータを使用してしまう。
class SuperClass { public SuperClass () { doLogic(); } public void doLogic() { System.out.println("This is superclass!"); } } class SubClass extends SuperClass { private String color = null; public SubClass() { super(); color = "Red"; } public void doLogic() { System.out.println("This is subclass! The color is :" + color); // ... } } public class Overridable { public static void main(String[] args) { SuperClass bc = new SuperClass(); // "This is superclass!" を出力 SuperClass sc = new SubClass(); // "This is subclass! The color is :null" を出力 } }
スーパークラスのコンストラクタにおいてdoLogic()メソッドが呼び出されている。スーパークラスのインスタンスが直接構築される場合、スーパークラスのdoLogic()メソッドが呼び出される。しかし、サブクラスがスーパークラスのコンストラクタを呼び出す場合には、サブクラスのdoLogic()メソッドが呼び出される。その場合、サブクラスのコンストラクタは処理を完了しておらず、colorの値はnullのままである。
適合コード
以下の適合コードでは、doLogic()メソッドをfinal宣言しており、オーバーライドされることはない。
class SuperClass { public SuperClass() { doLogic(); } public final void doLogic() { System.out.println("This is superclass!"); } }
リスク評価
オーバーライド可能なメソッドをコンストラクタから呼び出していると、オブジェクトの初期化が完了する前に攻撃者がthis参照にアクセスできる。これは脆弱性につながる可能性がある。
ルール | 深刻度 | 可能性 | 修正コスト | 優先度 | レベル |
---|---|---|---|---|---|
MET05-J | 中 | 中 | 中 | P8 | L2 |
自動検出
コンストラクタにおけるオーバーライド可能なメソッド呼出しは、容易に自動検出することができる。
関連ガイドライン
ISO/IEC TR 24772:2010 | Inheritance [RIP] |
参考文献
[ESA 2005] | Rule 62: Do not call nonfinal methods from within a constructor |
[JLS 2005] | Chapter 8, Classes, §12.5 Creation of New Class Instances |
[Rogue 2000] | Rule 81. Do not call non-final methods from within a constructor |
Secure Coding Guidelines for the Java Programming Language, Version 3.0 | Guideline 4-4. Prevent constructors from calling methods that can be overridden |
翻訳元
これは以下のページを翻訳したものです。
MET05-J. Ensure that constructors do not call overridable methods (revision 84)