According to the Java Language Specification \[[JLS 05|AA. Java References#JLS 05]\], the keyword {{this}} denotes: |
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 of this is the class C within which the keyword this occurs. At run time, the class of the actual object referred to may be the class C or any subclass of C.
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:
this
from a non-private methodthis
as a parameter to a method belonging to another classthis
from the constructor of an object under constructionthis
such that pieces of code beyond its current scope can obtain its referenceThis guideline primarily focuses on the ill effects of this
escaping during object construction. Potential consequences include race conditions and improper initialization.
This noncompliant example defines the ExceptionReporter
interface that is implemented by the class ExceptionReporters
. This class is useful for reporting exceptions after filtering out any sensitive information (EXC05-J. Use a class dedicated to reporting exceptions). The constructor of ExceptionReporters
, incorrectly publishes the this
reference before construction of the object has concluded. This is because it sets the exception reporter in the constructor (statement er.setExceptionReporter(this)
). It is misleading that, since it is the last statement in the constructor, it must be benign.
Consider the class MyExceptionReporter
, that subclasses ExceptionReporters
with the intent of adding a logging mechanism that logs critical messages before an exception is reported. Its constructor invokes the 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. As a result, the exception handler is set and if any exception occurs before the call to Logger.getLogger
in the subclass, it is not logged. Instead, a NullPointerException
is generated which may again get swallowed by the reporting mechanism. In summary, this behavior is due to the race condition between an oncoming exception and the initialization of the subclass. If the exception comes too soon, it finds the subclass in a compromised state. This behavior is even more counter intuitive because logger
is declared final
and is not expected to contain an unintialized value.
// Interface ExceptionReporter public interface ExceptionReporter { public void setExceptionReporter(ExceptionReporter er); public void report(Throwable exception); } // Class ExceptionReporters public class ExceptionReporters implements ExceptionReporter { public ExceptionReporters(ExceptionReporter er) { /* Carry out initialization */ er.setExceptionReporter(this); // incorrectly publishes the "this" reference } public void report(Throwable exception) { /* default implementation */ } public final void setExceptionReporter(ExceptionReporter er) { /* sets the reporter */ } } // Class MyExceptionReporter derives from ExceptionReporters public class MyExceptionReporter extends ExceptionReporters { private final Logger logger; public MyExceptionReporter(ExceptionReporter er) { super(er); // calls superclass's constructor logger = Logger.getLogger("com.organization.Log"); } public void report(Throwable t) { logger.log(Level.FINEST,"Loggable exception occurred",t); } } |
This compliant solution declares the setReporter()
method in class MyExceptionReporter
. It explicitly calls the superclass's setExceptionReporter()
method, publishing a reference to its own class object. It is not permissible to publish the reference in the constructor for MyExceptionReporter
for reasons noted earlier in the noncompliant code example.
public class MyExceptionReporter extends ExceptionReporters { // ... public void setReporter(ExceptionReporter er) { super.setExceptionReporter(this); } } |
In general, detect cases where the this
reference can leak out beyond the scope of the current context. In particular, be careful while using public
variables and methods.
It is possible for the {{this}} reference to implicitly get leaked outside the scope \[[Goetz 02|AA. Java References#Goetz 02]\]. Consider inner classes that maintain a copy of the {{this}} reference of the outer object. |
In this noncompliant code example, the constructor for class BadExceptionReporter
uses an anonymous inner class to publish a filter()
method. The problem surfaces as the this
reference of the outer class is published by the inner class so that other threads can see it. If this class were to be subclasses, the behavior mentioned in the first noncompliant code example would reoccur.
public class BadExceptionReporter implements ExceptionReporter { public BadExceptionReporter(ExceptionReporter er) { er.setExceptionReporter(new ExceptionReporters(er) { public void report(Throwable t) { filter(t); } }); } public void filter(Throwable t) { /* filters sensitive exceptions */ } public void report(Throwable exception) { /* default implementation */ } public void setExceptionReporter(ExceptionReporter er) { /* sets the reporter */ } } |
A {{private}} constructor alongside a {{public}} factory method may be used when it is desirable to publish from within the constructor. \[[Goetz 06|AA. Java References#Goetz 06]\] |
public class GoodExceptionReporter implements ExceptionReporter { private final ExceptionReporters er; private GoodExceptionReporter(ExceptionReporter excr) { er = new ExceptionReporters(excr) { public void report(Throwable t) { filter(t); } }; } public static GoodExceptionReporter newInstance(ExceptionReporter excr) { GoodExceptionReporter ger = new GoodExceptionReporter(excr); excr.setExceptionReporter(ger.er); return ger; } public void filter(Throwable t) { } public void report(Throwable exception) { } public void setExceptionReporter(ExceptionReporter er) { } } |
This noncompliant code example starts a thread from within the constructor. This allows the new thread to access the {{this}} reference of the current object. \[[Goetz 02|AA. Java References#Goetz 02]\] and \[[Goetz 06|AA. Java References#Goetz 06]\] |
public someConstructor() { thread = new MyThread(this); thread.start(); } |
In this compliant solution, even though the thread is created in the constructor, it is not started unless the {{start()}} method is called from somewhere other than the constructor. This behavior is permissible. \[[Goetz 02|AA. Java References#Goetz 02]\] and \[[Goetz 06|AA. Java References#Goetz 06]\] |
public someConstructor() { thread = new MyThread(this); } public void start() { thread.start(); } |
Allowing the this
reference to escape may result in improper initialization and runtime exceptions. The problem is aggravated if the class is sensitive.
Rule |
Severity |
Likelihood |
Remediation Cost |
Priority |
Level |
---|---|---|---|---|---|
CON40-J |
medium |
probable |
high |
P4 |
L3 |
TODO
Search for vulnerabilities resulting from the violation of this rule on the CERT website.
\[[JLS 05|AA. Java References#JLS 05]\] Keyword "this" \[[Goetz 02|AA. Java References#Goetz 02]\] \[[Goetz 06|AA. Java References#Goetz 06]\] 3.2. Publication and Escape |
CON39-J. Ensure atomicity of 64-bit operations 08. Concurrency (CON) 08. Concurrency (CON)