Allowing the this reference to escape

JavaConcurrency

Java Problem Overview


I would appreciate help in understanding the following from 'Java Concurrency in Practice':

> Calling an overrideable instance method(one that is neither > private nor final) from the constructor can also allow the > this reference to escape.

  1. Does 'escape' here simply mean that we may probably be calling an instance method,before the instance is fully constructed?
    I do not see 'this' escaping the scope of the instance in any other way.
  2. How does 'final' prevent this from happening?Is there some aspect of 'final' in instance creation that I am missing?

Java Solutions


Solution 1 - Java

  1. It means calling code outside the class, and passing this.
    That code will assume that the instance is fully initialized, and may break if it isn't.
    Similarly, your class might assume that some methods will only be called after the instance is fully initialized, but the external code is likely to break those assumptions.

  2. final methods cannot be overridden, so you can trust them to not pass this around.
    If you call any non-final method in the constructor for a non-final class, a derived class might override that method and pass this anywhere.
     
    Even when you call final methods, you still need to make sure that they are safely written – that they do not pass this anywhere, and that themselves don't call any non-final methods.

Solution 2 - Java

"Escape" means that a reference to the partially-constructed this object might be passed to some other object in the system. Consider this scenario:

public Foo {
    public Foo() {
        setup();
    }

    protected void setup() {
       // do stuff
    }
}

public Bar extends Foo implements SomeListener {
    @Override protected void setup() {
        otherObject.addListener(this);
    }
}

The problem is that the new Bar object is being registered with otherObject before its construction is completed. Now if otherObject starts calling methods on barObject, fields might not have been initialized, or barObject might otherwise be in an inconsistent state. A reference to the barObject (this to itself) has "escaped" into the rest of the system before it's ready.

Instead, if the setup() method is final on Foo, the Bar class can't put code in there that will make the object visible before the Foo constructor finishes.

Solution 3 - Java

I believe the example is something like

public class Foo {
    public Foo() {
        doSomething();
    }
    
    public void doSomething() {
        System.out.println("do something acceptable");
    }
}

public class Bar extends Foo {
    public void doSomething() {
        System.out.println("yolo");
        Zoom zoom = new Zoom(this); // at this point 'this' might not be fully initialized
    }
}

Because the super constructor is always called first (either implicitly or explicitly), the doSomething will always get called for a child class. Because the above method is neither final nor private, you can override it in a child class and do whatever you want, which may conflict with what Foo#doSomething() was meant to do.

Solution 4 - Java

Per secure coding

Example BAD code:

final class Publisher {
  public static volatile Publisher published;
  int num;
 
  Publisher(int number) {
    published = this;
    // Initialization
    this.num = number;
    // ...
  }
}   

If an object's initialization (and consequently, its construction) depends on a security check within the constructor, the security check can be bypassed when an untrusted caller obtains the partially initialized instance. See rule OBJ11-J. Be wary of letting constructors throw exceptions for more information.

final class Publisher {
  public static Publisher published;
  int num;
 
  Publisher(int number) {
    // Initialization
    this.num = number;
    // ...
    published = this;
  }
}

> Because the field is nonvolatile and nonfinal, 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.

Correct code:

final class Publisher {
  static volatile Publisher published;
  int num;
 
  Publisher(int number) {
    // Initialization
    this.num = number;
    // ...
    published = this;
  }
}

> The this reference is said to have escaped when it is made available > beyond its current scope. Following are common ways by which the this > reference can escape: > > 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 rule MET05-J. Ensure that > constructors do not call overridable methods.) > Returning this from a nonprivate method of a mutable class, which allows the caller to manipulate the object's state indirectly. This > commonly occurs in method-chaining implementations; see rule 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. > Throwing an exception from a constructor. Doing so may cause code to be vulnerable to a finalizer attack; see rule OBJ11-J. Be wary of > letting constructors throw exceptions for more information. > Passing internal object state to an alien method. This enables the method to retrieve the this reference of the internal member object. > > This rule 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 ordinarily ensures that all threads see the field in a fully > initialized state; however, allowing the this reference to escape > during object construction can expose the field to other threads in an > uninitialized or partially initialized state. Rule TSM03-J. Do not > publish partially initialized objects, which describes the guarantees > provided by various mechanisms for safe publication, relies on > conformance to this rule. Consequently, programs must not allow the > this reference to escape during object construction. > > In general, it is important to detect cases in which the this > reference can leak out beyond the scope of the current context. In > particular, public variables and methods should be carefully > scrutinized.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionIUnknownView Question on Stackoverflow
Solution 1 - JavaSLaksView Answer on Stackoverflow
Solution 2 - Javachrylis -cautiouslyoptimistic-View Answer on Stackoverflow
Solution 3 - JavaSotirios DelimanolisView Answer on Stackoverflow
Solution 4 - JavaWoot4MooView Answer on Stackoverflow