Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Java concurrency guidelines.pdf
Скачиваний:
17
Добавлен:
23.05.2015
Размер:
1.35 Mб
Скачать

TSM01-J

6.2.1Noncompliant 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 “OBJ04-J. Do not allow partially initialized objects to be accessed.”11)

6.2.2Noncompliant 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.

11

This guideline is described at https://www.securecoding.cert.org/confluence/display/java/.

 

CMU/SEI-2010-TR-015 | 150

TSM01-J

6.2.3Compliant 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” on page 162). 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 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.

6.2.4Compliant 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;

}

}

CMU/SEI-2010-TR-015 | 151

TSM01-J

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.

6.2.5Noncompliant 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 “EXC01-J. Use a class dedicated to reporting exceptions.”12)

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);

}

}

12

This guideline is described at https://www.securecoding.cert.org/confluence/display/java/.

 

CMU/SEI-2010-TR-015 | 152

TSM01-J

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 may, 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 uninitialized 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.

6.2.6Compliant 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");

CMU/SEI-2010-TR-015 | 153

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]