Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.
Comment: minor
Wiki Markup
Method chaining is a convenience mechanism that allows multiple method invocations on the same object to occur in a single statement. A method chaining implementation consists of a series of methods that return the {{this}} reference. This allows a caller to invoke methods in a chain by performing the next method invocation on the return value of the previous method in the chain.

While the methods used in method chaining may be atomic, a chain of method calls is inherently non-atomic. Consequently methods that are involved in method chaining should not be invoked by multiple threads unless the caller provides sufficient locking as illustrated in [CON07-J. Do not assume that a group of calls to independently atomic methods is atomic]. 
 

h2. Noncompliant Code Example

Method chaining is a useful design pattern for building an object and setting its optional fields. A class that supports method chaining provides several setter methods that each return the {{this}} reference.  However, in a multithreaded environment, a thread may observe shared fields to contain inconsistent values. This noncompliant code example shows the JavaBeans pattern which is not safe for multithreaded use.

{code:bgColor=#FFcccc}
final class USCurrency {
  // Change requested, denomination (optional fields)
  private int quarters = 0;
  private int dimes = 0;
  private int nickels = 0;
  private int pennies = 0;

  public USCurrency() {}

  // Setter methods 
  public USCurrency setQuarters(int quantity) { 
    quarters = quantity; 
    return this;
  } 
  public USCurrency setDimes(int quantity) { 
    dimes = quantity; 
    return this;
  }
  public USCurrency setNickels(int quantity) { 
    nickels = quantity;
    return this;
  }
  public USCurrency setPennies(int quantity) { 
    pennies = quantity;
    return this;
  }
}

// Client code:
private final USCurrency currency = new USCurrency(); 
// ...

new Thread(new Runnable() {
  @Override public void run() {    
    currency.setQuarters(1).setDimes(1);
  }
}).start();

new Thread(new Runnable() {
  @Override public void run() {    
    currency.setQuarters(2).setDimes(2);
  }
}).start();
{code}

The JavaBeans pattern uses a no-argument constructor and a series of parallel setter methods to build an object. This pattern is not thread-safe and can lead to inconsistent object state if the object is modified concurrently. In this noncompliant code example, the client constructs a {{USCurrency}} object and starts two threads that use method chaining to buildset the optional values of the {{USCurrency}} object. This might result in inconsistent state, for example, {{currency}} might be left with two quarters and one dime or one quarter and two dimes.


h2. Compliant Solution

This compliant solution uses the variant of the Builder pattern \[[Gamma 95|AA. Java References#Gamma 95]\] suggested by Bloch \[[Bloch 08|AA. Java References#Bloch 08]\] to ensure thread safety and atomicity of object creation.  {mc} What does this mean? It can be accessible to any number of threads ~DM => The method chaining is actually constrained to the {{USCurrency.Builder}} class which is only accessible from a single thread. {mc}


{code:bgColor=#ccccff}
final class USCurrency {
  private final int quarters;
  private final int dimes;
  private final int nickels;
  private final int pennies;

  public USCurrency(Builder builder) {
    this.quarters = builder.quarters;
    this.dimes = builder.dimes;
    this.nickels = builder.nickels;
    this.pennies = builder.pennies;
  }

  // Static class member 
  public static class Builder {
    private int quarters = 0;
    private int dimes = 0;
    private int nickels = 0;
    private int pennies = 0;

    public static Builder newInstance() {
      return new Builder();
    } 

    private Builder() {}
    
    // Setter methods 
    public Builder setQuarters(int quantity) { 
      this.quarters = quantity; 
      return this;
    } 
    public Builder setDimes(int quantity) { 
      this.dimes = quantity; 
      return this;
    }
    public Builder setNickels(int quantity) { 
      this.nickels = quantity;
      return this;
    }
    public Builder setPennies(int quantity) { 
      this.pennies = quantity;
      return this;
    }

    public USCurrency build() {
      return new USCurrency(this);
    }
  }
}

  // Client code: 
private volatile USCurrency currency;
// ...

new Thread(new Runnable() {
  @Override public void run() {    
    currency = USCurrency.Builder.newInstance().setQuarters(1).setDimes(1).build();
  }
}).start();

new Thread(new Runnable() {
  @Override public void run() {    
    currency = USCurrency.Builder.newInstance().setQuarters(2).setDimes(2).build();
  }
}).start();
{code}

The {{Builder.newInstance()}} factory method is called with the _required_ arguments (if any) to obtain a {{Builder}} object. The _optional_ parameters are set using the setter methods of the builder. The object construction concludes with the invocation of the {{build()}} method. This pattern makes the class {{USCurrency}} immutable, and consequently, thread-safe.

Note that the {{currency}} field cannot be declared as final because it is set to a new immutable object from the threads. It is declared volatile in compliance with [CON09-J. Ensure visibility of shared references to immutable objects].

If input needs to be validated, ensure that the values are defensively copied prior to validation (see [FIO00-J. Defensively copy mutable inputs and mutable internal components] for more information). The builder class does not violate [SCP03-J. Do not expose sensitive private members of the outer class from within a nested class] because it maintains a copy of the variables defined in the scope of the containing class. These take precedence and as a result, do not break encapsulation.


h2. Risk Assessment

Using method chaining in multithreaded environments without performing external locking can lead to non-deterministic behavior.

|| Rule || Severity || Likelihood || Remediation Cost || Priority || Level ||
| CON30- J | low | probable | medium | {color:green}{*}P4{*}{color} | {color:green}{*}L3{*}{color} |

h3. Automated Detection

TODO

h3. Related Vulnerabilities

Search for vulnerabilities resulting from the violation of this rule on the [CERT website|https://www.kb.cert.org/vulnotes/bymetric?searchview&query=FIELD+KEYWORDS+contains+FIO38-J].

h2. References

\[[API 06|AA. Java References#API 06]\] 
\[[Bloch 08|AA. Java References#Bloch 08]\] Item 2: "Consider a builder when faced with many constructor parameters"

----
[!The CERT Sun Microsystems Secure Coding Standard for Java^button_arrow_left.png!|CON29-J. Do not execute interdependent tasks in a bounded thread pool]      [!The CERT Sun Microsystems Secure Coding Standard for Java^button_arrow_up.png!|11. Concurrency (CON)]      [!The CERT Sun Microsystems Secure Coding Standard for Java^button_arrow_right.png!|CON31-J. Avoid client-side locking when using classes that do not commit to their locking strategy]