Java Tip #10 - Constructor Exceptions are Evil
I saw this in the Secure Coding Antipatterns session at JavaOne 2006. It might scare the hell out of you.
Suppose I have the following class Foo and the constructor of Foo throws an exception. This might be due to some kind of security constraint or an invalid state. Suppose we don't anyone unauthorized to call the doEvil() method.
In the following code, is there anyway for me to get access to Foo if the constructor throws an exception?
I didn't see it at 1st, but there at least one way to do it. If Foo isn't final, I can subclass Foo and get access to the instance.
Now I construct a MyFoo instance, call System.gc() and runFinalization().
I get the following output.
The moral of this story is to use the final keyword if you want to prevent incomplete instances from being accessible. The presenters of the session also suggested using a "initialized" field that is set as the last line of the constructor. A critical method could validate this field before doing work. I think final is a better solution.
Enjoy.
BBB
Suppose I have the following class Foo and the constructor of Foo throws an exception. This might be due to some kind of security constraint or an invalid state. Suppose we don't anyone unauthorized to call the doEvil() method.
public class Foo {
public Foo() {
System.out.println("constructing foo: " + this);
throw new RuntimeException();
}
public void doEvil() {
System.out.println("Evil!Evil!Evil");
}
}
In the following code, is there anyway for me to get access to Foo if the constructor throws an exception?
try {
Foo x = new Foo(); // <-- exception thrown here }
catch Exception(e)
{ ... }
I didn't see it at 1st, but there at least one way to do it. If Foo isn't final, I can subclass Foo and get access to the instance.
public class MyFoo extends Foo {
public static Foo x;
@Override
protected void finalize() throws Throwable {
x = this;
}
}
Now I construct a MyFoo instance, call System.gc() and runFinalization().
try {
Foo x = new MyFoo();
} catch(Exception e) {
System.out.println(""+e);
}
System.gc();
System.runFinalization();
System.out.println("MyFoo instance: " + MyFoo.x);
MyFoo.x.doEvil();
I get the following output.
constructing foo: MyFoo@923e30
java.lang.RuntimeException
MyFoo instance: MyFoo@923e30
Evil!Evil!Evil
The moral of this story is to use the final keyword if you want to prevent incomplete instances from being accessible. The presenters of the session also suggested using a "initialized" field that is set as the last line of the constructor. A critical method could validate this field before doing work. I think final is a better solution.
Enjoy.
BBB