...
Code Block |
---|
|
class MySingleton {
private static MySingleton Instanceinstance;
protected MySingleton() {
Instanceinstance = new MySingleton();
}
public static synchronized MySingleton getInstance() {
return Instanceinstance;
}
}
|
A malicious subclass may extend the accessibility of the constructor from protected to public, allowing untrusted code to create multiple instances of the singleton. Also, the class field Instance
has not been declared final.
...
Code Block |
---|
|
class MySingleton {
private static final MySingleton Instanceinstance = new MySingleton();
private MySingleton() {
// private constructor prevents instantiation by untrusted callers
}
public static synchronized MySingleton getInstance() {
return Instanceinstance;
}
}
|
The MySingleton
class need not be declared final because it has a private constructor.
...
Code Block |
---|
|
class MySingleton {
private static MySingleton Instanceinstance;
private MySingleton() {
// private constructor prevents instantiation by untrusted callers
}
// Lazy initialization
public static MySingleton getInstance() { // Not synchronized
if (Instanceinstance == null) {
Instanceinstance = new MySingleton();
}
return Instanceinstance;
}
}
|
A singleton initializer method in a multithreaded program must employ some form of locking to prevent construction of multiple singleton objects.
...
Code Block |
---|
|
public static MySingleton getInstance() {
if (Instanceinstance == null) {
synchronized (MySingleton.class) {
Instanceinstance = new MySingleton();
}
}
return Instanceinstance;
}
|
This is because two or more threads may simultaneously see the field Instance
instance
as null
in the if
condition and enter the synchronized block one at a time.
...
Code Block |
---|
|
class MySingleton {
private static MySingleton Instanceinstance;
private MySingleton() {
// private constructor prevents instantiation by untrusted callers
}
// Lazy initialization
public static synchronized MySingleton getInstance() {
if (Instanceinstance == null) {
Instanceinstance = new MySingleton();
}
return Instanceinstance;
}
}
|
Compliant Solution (Double-Checked Locking)
...
Code Block |
---|
|
class MySingleton {
private static volatile MySingleton Instanceinstance;
private MySingleton() {
// private constructor prevents instantiation by untrusted callers
}
// Double-checked locking
public static MySingleton getInstance() {
if (Instanceinstance == null) {
synchronized (MySingleton.class) {
if (Instanceinstance == null) {
Instanceinstance = new MySingleton();
}
}
}
return Instanceinstance;
}
}
|
This design pattern is often implemented incorrectly. Refer to rule LCK10-J. Do not use incorrect forms of the double-checked locking idiom for more details on the correct use of the double-checked locking idiom.
...
Code Block |
---|
|
class MySingleton {
static class SingletonHolder {
static MySingleton Instanceinstance = new MySingleton();
}
public static MySingleton getInstance() {
return SingletonHolder.Instanceinstance;
}
}
|
This is known as the initialize-on-demand holder class idiom. Refer to rule LCK10-J. Do not use incorrect forms of the double-checked locking idiom for more information.
...
Code Block |
---|
|
class MySingleton implements Serializable {
private static final long serialVersionUID = 6825273283542226860L;
private static MySingleton Instanceinstance;
private MySingleton() {
// private constructor prevents instantiation by untrusted callers
}
// Lazy initialization
public static synchronized MySingleton getInstance() {
if (Instanceinstance == null) {
Instanceinstance = new MySingleton();
}
return Instanceinstance;
}
}
|
A singleton's constructor cannot install checks to enforce the requirement that the class is only instantiated once because deserialization can bypass the object's constructor.
...
Code Block |
---|
|
class MySingleton implements Serializable {
private static final long serialVersionUID = 6825273283542226860L;
private static MySingleton Instanceinstance;
private MySingleton() {
// private constructor prevents instantiation by untrusted callers
}
// Lazy initialization
public static synchronized MySingleton getInstance() {
if (Instanceinstance == null) {
Instanceinstance = new MySingleton();
}
return Instanceinstance;
}
private Object readResolve() {
return Instanceinstance;
}
}
|
At runtime, an attacker can add a class that reads in a crafted serialized stream:
...
Upon deserialization, the field MySingleton.untrusted
is reconstructed before MySingleton.readResolve()
is called. Consequently, Untrusted.captured
is assigned the deserialized instance of the crafted stream instead of MySingleton.Instanceinstance
. This issue is pernicious when an attacker can add classes to exploit the singleton guarantee of an existing serializable class.
...
Code Block |
---|
|
class MySingleton implements Serializable {
private static final long serialVersionUID =
2787342337386756967L;
private static MySingleton Instanceinstance;
// non-transient instance field
private String[] str = {"one", "two", "three"};
private MySingleton() {
// private constructor prevents instantiation by untrusted callers
}
public void displayStr() {
System.out.println(Arrays.toString(str));
}
private Object readResolve() {
return Instanceinstance;
}
}
|
"If a singleton contains a nontransient object reference field, the contents of this field will be deserialized before the singletonâs readResolve
method is run. This allows a carefully crafted stream to 'steal' a reference to the originally deserialized singleton at the time the contents of the object reference field are deserialized" [Bloch 2008].
...
Code Block |
---|
|
public enum MySingleton {
; // empty list of enum values
private static MySingleton Instanceinstance;
// non-transient field
private String[] str = {"one", "two", "three"};
public void displayStr() {
System.out.println(Arrays.toString(str));
}
}
|
...
Code Block |
---|
|
class MySingleton implements Cloneable {
private static MySingleton Instanceinstance;
private MySingleton() {
// private constructor prevents
// instantiation by untrusted callers
}
// Lazy initialization
public static synchronized MySingleton getInstance() {
if (Instanceinstance == null) {
Instanceinstance = new MySingleton();
}
return Instanceinstance;
}
}
|
Compliant Solution (Override clone()
Method)
...
Code Block |
---|
|
class MySingleton implements Cloneable {
private static MySingleton Instanceinstance;
private MySingleton() {
// private constructor prevents instantiation by untrusted callers
}
// Lazy initialization
public static synchronized MySingleton getInstance() {
if (Instanceinstance == null) {
Instanceinstance = new MySingleton();
}
return Instanceinstance;
}
public Object clone() throws CloneNotSupportedException {
throw new CloneNotSupportedException();
}
}
|
...