You are viewing an old version of this page. View the current version.

Compare with Current View Page History

« Previous Version 69 Next »

Overriding thread-safe methods with methods that are not thread-safe can result in improper synchronization, if the client inadvertently operates on an instance of the subclass. An overridden synchronized method's contract can be violated, if a subclass provides an implementation that is not safe for concurrent use.

Overriding thread-safe methods with methods that are not thread-safe is not, in itself, an error. However. it is disallowed by this guideline, because it may easily result in errors that are difficult to diagnose.

The locking strategy of classes designed for inheritance should always be documented. This information can subsequently be used to determine an appropriate locking strategy for subclasses (see LCK00-J. Use private final lock objects to synchronize classes that may interact with untrusted code).

Noncompliant Code Example (Synchronized Method)

This noncompliant code example overrides the synchronized doSomething() method in the Base class with an unsynchronized method in the derived Derived class.

class Base {
  public synchronized void doSomething() {
    // ...
  }
}

class Derived extends Base {
  public void doSomething() {
    // ...
  }
}

The doSomething() method of the Base class can be safely used by multiple threads, but instances of the Derived subclass cannot.

This programming error can be difficult to diagnose, because threads that accept instances of Base can also accept instances of its subclasses. Consequently, clients could be unaware that they are operating on an instance of the subclass of a thread-safe class that is not in fact thread-safe.

Compliant Solution (Synchronized Method)

This compliant solution synchronizes the doSomething() method of the subclass.

class Base {
  public synchronized void doSomething() {
    // ...
  }
}

class Derived extends Base {
  public synchronized void doSomething() {
    // ...
  }
}

This compliant solution does not violate LCK00-J. Use private final lock objects to synchronize classes that may interact with untrusted code, because the accessibility of the class is package-private. That type of accessibility is allowable when untrusted code cannot infiltrate the package.

Compliant Solution (Private Final Lock Object)

This compliant solution ensures that the Derived class is thread-safe by overriding the synchronized doSomething() method of the Base class with a method that synchronizes on a private final lock object.

class Base {

  public synchronized void doSomething() {
    // ...
  }
}

class Derived extends Base {

  private final Object lock = new Object();

  public void doSomething() {
    synchronized (lock) {
      // ...
    }
  }
}

This is an acceptable solution, provided the Derived class has a consistent locking policy.

Noncompliant Code Example (Private Lock)

This noncompliant code example defines a doSomething() method in the Base class that uses a private final lock, in accordance with LCK00-J. Use private final lock objects to synchronize classes that may interact with untrusted code.

class Base {
  private final Object lock = new Object();

  public void doSomething() {
    synchronized (lock) {
      // ...
    }
  }
}

class Derived extends Base {
  public void doSomething() {
    try {
      super.doSomething();
    } finally {
      logger.log(Level.FINE, "Did something");
    }
  }
}

It is possible for multiple threads to cause the entries to be logged in an order that differs from the order in which the tasks are performed. Consequently, the doSomething() method of the Derived class cannot be used safely by multiple threads, because it is not thread-safe.

Compliant Solution (Private Lock)

This compliant solution synchronizes the doSomething() method of the subclass using a private final lock object.

class Base {
  private final Object lock = new Object();

  public void doSomething() {
    synchronized (lock) {
      // ...
    }
  }
}

class Derived extends Base {
  private final Object lock = new Object();

  public void doSomething() {
    synchronized (lock) {
      try {
        super.doSomething();
      } finally {
        logger.log(Level.FINE, "Did something");
      }
    }
  }
}

Note that the Base and Derived objects maintain distinct locks that are inaccessible from each others' classes. Consequently, Derived can provide thread-safety guarantees independent of Base.

Risk Assessment

Overriding thread-safe methods with methods that are not thread-safe can result in unexpected behavior.

Rule

Severity

Likelihood

Remediation Cost

Priority

Level

CON15- J

low

probable

medium

P4

L3

Automated Detection

TODO

Related Vulnerabilities

Any vulnerabilities resulting from the violation of this rule are listed on the CERT website.

References

[[API 06]]
[[SDN 08]] Sun bug database, Bug ID 4294756


      11. Concurrency (CON)      TSM01-J. Do not let the (this) reference escape during object construction

  • No labels