
According to the Java Language Specification [[JLS 2005]], Section 15.8.3, this
when used as a primary expression, the keyword
this
denotes a value that is a reference to the object for which the instance method was invoked (§15.12), or to the object being constructed. The type ofthis
is the classC
within which the keywordthis
occurs. At run time, the class of the actual object referred to may be the classC
or any subclass ofC
.
The this
reference is said to have escaped when it is made available beyond its current scope. Common ways by which the this
reference can escape include
- returning
this
from a non-private, overridable method that is invoked from the constructor of a class whose object is being constructed. (For more information, see guideline [MET04-J. Ensure that constructors do not call overridable methods].)Unknown macro: {mc}subclasses!
- returning
this
from a non-private method of a mutable class, which allows the caller to manipulate the object's state indirectly. This commonly occurs in method-chaining implementations; see guideline VNA04-J. Ensure that calls to chained methods are atomic for more information. - passing
this
as an argument to an [alien method] invoked from the constructor of a class whose object is being constructed. - using inner classes. An inner class implicitly holds a reference to the instance of its outer class, unless the inner class is declared static.
- publishing by assigning
this
to a public static variable from the constructor of a class whose object is being constructed. - overriding the finalizer of a non-final class and obtaining the
this
reference of a partially initialized instance, when the construction of the object ceases. (For more information, see guideline [OBJ05-J. Prevent access to partially initialized objects].) This can happen when the constructor throws an exception. Misuse is not limited to untrusted code; trusted code can also inadvertently add a finalizer and letthis
escape by violating guideline [MET18-J. Do not use finalizers]. - passing internal object state to an [alien method]. This enables the method to retrieve the
this
reference of the internal member object.
This guideline describes the potential consequences of allowing the this
reference to escape during object construction, including race conditions and improper initialization. For example, declaring a field final ensures that all threads see it in a fully initialized state only when the this
reference does not escape during the corresponding object's construction. Guideline TSM03-J. Do not publish partially initialized objects describes the guarantees provided by various mechanisms for safe publication and relies on conformance to this guideline. In general, it is important to detect cases where the this
reference can leak out beyond the scope of the current context. In particular, public
variables and methods should be carefully scrutinized.
Noncompliant Code Example (Publish Before Initialization)
This noncompliant code example publishes the this
reference before initialization has concluded, by storing it in a public static volatile
class field.
final class Publisher { public static volatile Publisher published; int num; Publisher(int number) { published = this; // Initialization this.num = number; // ... } }
Consequently, other threads may obtain a partially initialized Publisher
instance. Also, if the object initialization (and consequently, its construction) depends on a security check within the constructor, the security check can be bypassed if an untrusted caller obtains the partially initialized instance. (For more information, see guideline [OBJ05-J. Prevent access to partially initialized objects].)
Noncompliant Code Example (Non-volatile Public Static Field)
This noncompliant code example publishes the this
reference in the last statement of the constructor but is still vulnerable because the published
field is not declared volatile and has public accessibility.
final class Publisher { public static Publisher published; int num; Publisher(int number) { // Initialization this.num = number; // ... published = this; } }
Because the field is non-volatile and non-final, the statements within the constructor can be reordered by the compiler in such a way that the this
reference is published before the initialization statements have executed.
Compliant Solution (Volatile Field and Publish after Initialization)
This compliant solution declares the published
field volatile and reduces its accessibility to package-private so that callers outside the current package scope cannot obtain the this
reference.
final class Publisher { static volatile Publisher published; int num; Publisher(int number) { // Initialization this.num = number; // ... published = this; } }
The constructor publishes the this
reference after initialization has concluded. However, the caller that instantiates Publisher
must ensure that it does not see the default value of the num
field before it is initialized (a violation of guideline TSM03-J. Do not publish partially initialized objects). Consequently, the field that holds the reference to Publisher
might need to be declared volatile in the caller.
Initialization statements may be reordered if the published
field is not declared volatile. The Java compiler, however, does not allow fields to be declared as both volatile
and final
.
The class Publisher
must also be final
; otherwise, a subclass can call its constructor and publish the this
reference before the subclass's initialization has concluded.
Compliant Solution (Public Static Factory Method)
This compliant solution eliminates the internal member field and provides a newInstance()
factory method that creates and returns a Publisher
instance.
final class Publisher { final int num; private Publisher(int number) { // Initialization this.num = number; } public static Publisher newInstance(int number) { Publisher published = new Publisher(number); return published; } }
This approach ensures that threads do not see an inconsistent Publisher
instance. The num
field is also declared final
, making the class immutable and eliminating the possibility of obtaining a partially initialized object.
Noncompliant Code Example (Handlers)
This noncompliant code example defines the ExceptionReporter
interface:
public interface ExceptionReporter { public void setExceptionReporter(ExceptionReporter er); public void report(Throwable exception); }
This interface is implemented by the DefaultExceptionReporter
class, which reports exceptions after filtering out any sensitive information (For more information, see guideline ERR00-J. Do not suppress or ignore checked exceptions.)
The DefaultExceptionReporter
constructor prematurely publishes the this
reference before construction of the object has concluded. This occurs in the last statement of the constructor (er.setExceptionReporter(this)
), which sets the exception reporter. Because it is the last statement of the constructor, this may be misconstrued as benign.
// Class DefaultExceptionReporter public class DefaultExceptionReporter implements ExceptionReporter { public DefaultExceptionReporter(ExceptionReporter er) { // Carry out initialization // Incorrectly publishes the "this" reference er.setExceptionReporter(this); } // Implementation of setExceptionReporter() and report() }
The MyExceptionReporter
class subclasses DefaultExceptionReporter
with the intent of adding a logging mechanism that logs critical messages before an exception is reported.
// Class MyExceptionReporter derives from DefaultExceptionReporter public class MyExceptionReporter extends DefaultExceptionReporter { private final Logger logger; public MyExceptionReporter(ExceptionReporter er) { super(er); // Calls superclass's constructor logger = Logger.getLogger("com.organization.Log"); // Obtain the default logger } public void report(Throwable t) { logger.log(Level.FINEST,"Loggable exception occurred", t); } }
Its constructor invokes the DefaultExceptionReporter
superclass's constructor (a mandatory first step), which publishes the exception reporter before the initialization of the subclass has concluded. Note that the subclass initialization consists of obtaining an instance of the default logger. Publishing the exception reporter is equivalent to setting it to receive and handle exceptions from that point on.
If an exception occurs before the call to Logger.getLogger()
in the MyExceptionReporter
subclass, it is not logged. Instead, a NullPointerException
is generated which could itself be consumed by the reporting mechanism without being logged.
This erroneous behavior results from the race condition between an oncoming exception and the initialization of MyExceptionReporter
. If the exception comes too soon, it finds MyExceptionReporter
in an inconsistent state. This behavior is especially counterintuitive because logger
is declared final
and is not expected to contain an unintialized value.
This problem can also occur when an event listener is published prematurely. Consequently, it starts receiving event notifications even before the subclass's initialization has concluded.
Compliant Solution
Instead of publishing the this
reference from the DefaultExceptionReporter
constructor, this compliant solution adds the publishExceptionReporter()
method to DefaultExceptionReporter
to set the exception reporter. This method can be invoked on a subclass instance, after the subclass's initialization has concluded.
public class DefaultExceptionReporter implements ExceptionReporter { public DefaultExceptionReporter(ExceptionReporter er) { // ... } // Should be called after subclass's initialization is over public void publishExceptionReporter() { setExceptionReporter(this); // Registers this exception reporter } // Implementation of setExceptionReporter() and report() }
The MyExceptionReporter
subclass inherits the publishExceptionReporter()
method, and a caller who instantiates MyExceptionReporter
can use its instance to set the exception reporter, after initialization is over.
// Class MyExceptionReporter derives from DefaultExceptionReporter public class MyExceptionReporter extends DefaultExceptionReporter { private final Logger logger; public MyExceptionReporter(ExceptionReporter er) { super(er); // Calls superclass's constructor logger = Logger.getLogger("com.organization.Log"); } // Implementations of publishExceptionReporter(), setExceptionReporter() and //report() are inherited }
This approach ensures that the reporter cannot be set before the constructor has fully initialized the subclass and enabled logging.
Noncompliant Code Example (Inner Class)
Inner classes maintain a copy of the this
reference of the outer object. Consequently, the this
reference could leak outside the scope [[Goetz 2002]]. This noncompliant code example uses a different implementation of the DefaultExceptionReporter
class. The constructor uses an anonymous inner class to publish a filter()
method.
public class DefaultExceptionReporter implements ExceptionReporter { public DefaultExceptionReporter(ExceptionReporter er) { er.setExceptionReporter(new DefaultExceptionReporter(er) { public void report(Throwable t) { filter(t); } }); } // Default implementations of setExceptionReporter() and report() }
The this
reference of the outer class is published by the inner class so that other threads can see it. Furthermore, if the class is subclassed, the issue described in the noncompliant code example for handlers resurfaces.
Compliant Solution
A private
constructor alongside a public static factory method can safely publish the filter()
method from within the constructor [[Goetz 2006]].
public class DefaultExceptionReporter implements ExceptionReporter { private final DefaultExceptionReporter defaultER; private DefaultExceptionReporter(ExceptionReporter excr) { defaultER = new DefaultExceptionReporter(excr) { public void report(Throwable t) { filter(t); } }; } public static DefaultExceptionReporter newInstance(ExceptionReporter excr) { DefaultExceptionReporter der = new DefaultExceptionReporter(excr); excr.setExceptionReporter(der.defaultER); return der; } // Default implementations of setExceptionReporter() and report() }
Because the constructor is private
, untrusted code cannot create instances of the class, prohibiting the this
reference from escaping. Using a public static
factory method to create new instances also protects against untrusted manipulation of internal object state and publication of partially initialized objects. (See guideline TSM03-J. Do not publish partially initialized objects.)
Noncompliant Code Example (Thread)
This noncompliant code example starts a thread from within the constructor.
final class ThreadStarter implements Runnable { public ThreadStarter() { Thread thread = new Thread(this); thread.start(); } @Override public void run() { // ... } }
The new thread can access the this
reference of the current object [[Goetz 2002]], [[Goetz 2006]]. Notably, the Thread()
constructor is [alien] to the ThreadStarter
class.
Compliant Solution (Thread)
This compliant solution creates and starts the thread in a method instead of the constructor.
final class ThreadStarter implements Runnable { public ThreadStarter() { // ... } public void startThread() { Thread thread = new Thread(this); thread.start(); } @Override public void run() { // ... } }
Exceptions
TSM01-EX1: It is safe to create a thread in the constructor, provided the thread is not started until object construction has completed. This is because a call to start()
on a thread happens before any actions in the started thread [[JLS 2005]].
In this code example, even though a thread referencing this
is created in the constructor, it is not started until its start()
method is called from the startThread()
method [[Goetz 2002]], [[Goetz 2006]].
final class ThreadStarter implements Runnable { Thread thread; public ThreadStarter() { thread = new Thread(this); } public void startThread() { thread.start(); } @Override public void run() { // ... } }
TSM01-EX2: The ObjectPreserver
pattern [[Grand 2002]] described in guideline TSM02-J. Do not use background threads during class initialization#CON03-EX1 is also a safe exception to this guideline.
Risk Assessment
Allowing the this
reference to escape could result in improper initialization and runtime exceptions.
Guideline |
Severity |
Likelihood |
Remediation Cost |
Priority |
Level |
---|---|---|---|---|---|
TSM01-J |
medium |
probable |
high |
P4 |
L3 |
Automated Detection
TODO
Related Vulnerabilities
Search for vulnerabilities resulting from the violation of this guideline on the CERT website.
References
[[JLS 2005]] Keyword "this"
[[Goetz 2002]]
[[Goetz 2006]] Section 3.2, "Publication and Escape"
[[Grand 2002]] Chapter 5, "Creational Patterns, Singleton"
Issue Tracking
Review List
null [!The CERT Oracle Secure Coding Standard for Java^button_arrow_up.png!] null