54

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?
Charles
  • 50,943
  • 13
  • 104
  • 142
IUnknown
  • 9,301
  • 15
  • 50
  • 76

4 Answers4

32
  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.

Bax
  • 4,260
  • 5
  • 43
  • 65
SLaks
  • 868,454
  • 176
  • 1,908
  • 1,964
  • The code "may" assume that the class is fully initialized, but the method's contract could explicitly forbid such inference. In some cases, the base-class constructor may need information about the derived class, and the most practical way for it to get that information may be for it to call a virtual method whose *documented purpose* would be to be called during base-class construction. In such cases, it may be helpful for the base-class constructor to accept some kind of object, and pass it through to the virtual method; this will make it possible for the derived-class constructor... – supercat Dec 09 '13 at 18:38
  • ...to encapsulate information about its own parameters into an object, and then use that information in computing the data needed by the base-class constructor. Note that the design of sub-derived classes may be somewhat tricky, but there are some patterns that would allow such things do be handled cleanly and consistently. Note too that such a design would rely upon derived classes to abide by their contracts, but that reliance is hardly unique to this situation. Very few unsealed classes can behave robustly if derived classes don't abide by their contracts. – supercat Dec 09 '13 at 18:39
28

"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.

chrylis -cautiouslyoptimistic-
  • 75,269
  • 21
  • 115
  • 152
13

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.

Sotirios Delimanolis
  • 274,122
  • 60
  • 696
  • 724
6

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.

Woot4Moo
  • 23,987
  • 16
  • 94
  • 151
  • I would argue that a better pattern for your `Publisher` class would be to use a factory of some form (perhaps a `static` method) that creates an instance and assigns the `published` field. This would be especially important if `Publisher` was not `final`. – Jeffrey Dec 09 '13 at 15:47
  • @Jeffrey it isn't my publisher class, it was taken directly from the secure coding site. – Woot4Moo Dec 09 '13 at 15:48