...
More information about deprecated methods is available in MET15-J. Do not use deprecated or obsolete methods.
Noncompliant Code Example (Deprecated Thread.stop()
)
This noncompliant code example shows a thread that fills a vector with pseudorandom numbers. The thread is stopped after a fixed amount of time.
...
Wiki Markup |
---|
However, the {{Thread.stop()}} method causes the thread to stop what it is doing and throw a {{ThreadDeath}} exception. All acquired locks are subsequently released \[[API 06|AA. Java References#API 06]\]. If the thread is in the process of adding a new integer to the vector when it is stopped, the vector may become accessible while it is in an inconsistent state. For example, {{Vector.size()}} may return two while the vector contains three elements (the element count is incremented after adding the element). |
Compliant Solution (volatile
flag)
This compliant solution stops the thread by using a volatile
flag. An accessor method shutdown()
is used to set the flag to true
. The thread's run()
method polls the done
flag, and shuts down when it becomes true
.
Code Block | ||
---|---|---|
| ||
public class Container implements Runnable { private final Vector<Integer> vector = new Vector<Integer>(); private volatile boolean done = false; public Vector<Integer> getVector() { return vector; } public void shutdown() { done = true; } public synchronized void run() { Random number = new Random(123L); int i = 10; while (!done && i > 0) { vector.add(number.nextInt(100)); i--; } } public static void main(String[] args) throws InterruptedException { Container container = new Container(); Thread thread = new Thread(container); thread.start(); Thread.sleep(5000); container.shutdown(); } } |
Compliant Solution (Interruptible)
This compliant solution stops the thread by using the Thread.interrupted()
method.
...
Upon receiving the interruption, the interrupted status of the thread is cleared and an InterruptedException
is thrown. No guarantees are provided by the JVM on when the interruption will be detected by blocking methods such as Thread.sleep()
and Object.wait()
. A thread may use interruption for performing tasks other than cancellation and shutdown. Consequently, a thread should not be interrupted unless its interruption policy is known in advance. Failure to follow this advice can result in the corruption of mutable shared state.
Compliant Solution (RuntimePermission stopThread
)
Remove the default permission java.lang.RuntimePermission
stopThread
from the security policy file to deny the Thread.stop()
invoking code, the required privileges.
Noncompliant Code Example (blocking IO, volatile flag)
This noncompliant code example uses a volatile done
flag to indicate that it is safe to shutdown the thread, as suggested above. However, this does not help in terminating the thread because it is blocked on some network IO as a consequence of using the readLine()
method.
...
Note that the Runnable
object prevents itself from being run in multiple threads using an isRunning
flag. If one thread tries to invoke run()
after another thread has already done so, an unchecked exception is thrown.
Noncompliant Code Example (blocking IO, interruptible)
This noncompliant code example uses thread interruption to indicate that it is safe to shutdown the thread, as suggested above. However, this is not useful because the thread is blocked on some network IO as a consequence of using the readLine()
method. Network I/O is not responsive to thread interruption.
Code Block | ||
---|---|---|
| ||
class SocketReader implements Runnable { // ... public void execute() throws IOException { String string; while (!Thread.interrupted() && (string = in.readLine()) != null) { // Blocks until end of stream (null) } } public static void main(String[] args) throws IOException, InterruptedException { SocketReader reader = new SocketReader(); Thread thread = new Thread(reader); thread.start(); Thread.sleep(1000); thread.interrupt(); } } |
Compliant Solution (close socket connection)
This compliant solution closes the socket connection, by having the shutdown()
method close the socket. As a result, the thread is bound to stop because of a SocketException
. Note that there is no way to keep the connection alive if the thread is to be cleanly halted immediately.
...
A boolean
flag can be used (as described earlier) if additional clean-up operations need to be performed. When performing asynchronous I/O, a java.nio.channels.Selector
may also be brought out of the blocked state by either invoking its close()
or wakeup()
method.
Compliant Solution (interruptible channel)
This compliant solution uses an interruptible channel, SocketChannel
instead of a Socket
connection. If the thread performing the network IO is interrupted using the Thread.interrupt()
method, for instance, while reading the data, the thread receives a ClosedByInterruptException
and the channel is closed immediately. The thread's interrupt status is also set.
...
This method interrupts the current thread, however, it only stops the thread because the code polls the interrupted flag using the method Thread.interrupted()
, and shuts down the thread when it is interrupted. Invoking the interrupt()
method of a thread that is blocked because of a java.nio.channels.Selector
also causes the thread to awaken.
Noncompliant Code Example (database connection)
This noncompliant code example shows a thread-safe class DBConnector
that creates a JDBC connection per thread, that is, the connection belonging to one thread is not shared by other threads. This is a common use-case because JDBC connections are not meant to be shared by multiple-threads.
...
Unfortunately database connections, like sockets, are not inherently interruptible. So this design does not permit a client to cancel a task by closing it if the corresponding thread is blocked on a long running activity such as a join query. Furthermore, it is important to provide a mechanism to close connections to prevent thread starvation caused because of the limited number of database connections available in the pool. Similar task cancellation mechanisms are required when using objects local to a method, such as sockets.
Compliant Solution (ThreadLocal)
This compliant solution uses a ThreadLocal
wrapper around the connection so that a thread that calls initialValue()
obtains a unique connection instance. The advantage of this approach is that a shutdownConnection()
method can be provided so that clients external to the class can also close the connection when the corresponding thread is blocked, or is performing some time consuming activity.
Code Block | ||
---|---|---|
| ||
class DBConnector implements Runnable { final String query; DBConnector(String query) { this.query = query; } private static ThreadLocal<Connection> connectionHolder = new ThreadLocal<Connection>() { Connection connection = null; @Override public Connection initialValue() { try { // Username and password are hard coded for brevity connection = DriverManager.getConnection ("jdbc:driver:name", "username","password"); } catch (SQLException e) { // Forward to handler } return connection; } @Override public void set(Connection con) { if(connection == null) { // Shuts down connection when null value is passed try { connection.close(); } catch (SQLException e) { // Forward to handler } } else { connection = con; } } }; public static Connection getConnection() { return connectionHolder.get(); } public static void shutdownConnection() { // Allows client to close connection anytime connectionHolder.set(null); } public void run() { Connection dbConnection = getConnection(); Statement stmt; try { stmt = dbConnection.createStatement(); ResultSet rs = stmt.executeQuery(query); } catch (SQLException e) { // Forward to handler } // ... } public static void main(String[] args) throws InterruptedException { DBConnector connector = new DBConnector(/* suitable query */); Thread thread = new Thread(connector); thread.start(); Thread.sleep(5000); connector.shutdown(); } } |
Noncompliant Code Example (database connection)
This noncompliant code example shows a thread-safe class DBConnector
that creates a JDBC connection per thread, that is, the connection belonging to one thread is not shared by other threads. This is a common use-case because JDBC connections are not meant to be shared by multiple-threads.
...
Unfortunately database connections, like sockets, are not inherently interruptible. So this design does not permit a client to cancel a task by closing it if the corresponding thread is blocked on a long running activity such as a join query. Furthermore, it is important to provide a mechanism to close connections to prevent thread starvation caused because of the limited number of database connections available in the pool. Similar task cancellation mechanisms are required when using objects local to a method, such as sockets.
Compliant Solution (ThreadLocal)
This compliant solution uses a ThreadLocal
wrapper around the connection so that a thread that calls initialValue()
obtains a unique connection instance. The advantage of this approach is that a shutdownConnection()
method can be provided so that clients external to the class can also close the connection when the corresponding thread is blocked, or is performing some time consuming activity.
Code Block | ||
---|---|---|
| ||
class DBConnector implements Runnable { final String query; DBConnector(String query) { this.query = query; } private static ThreadLocal<Connection> connectionHolder = new ThreadLocal<Connection>() { Connection connection = null; @Override public Connection initialValue() { try { // Username and password are hard coded for brevity connection = DriverManager.getConnection ("jdbc:driver:name", "username","password"); } catch (SQLException e) { // Forward to handler } return connection; } @Override public void set(Connection con) { if(connection == null) { // Shuts down connection when null value is passed try { connection.close(); } catch (SQLException e) { // Forward to handler } } else { connection = con; } } }; public static Connection getConnection() { return connectionHolder.get(); } public static void shutdownConnection() { // Allows client to close connection anytime connectionHolder.set(null); } public void run() { Connection dbConnection = getConnection(); Statement stmt; try { stmt = dbConnection.createStatement(); ResultSet rs = stmt.executeQuery(query); } catch (SQLException e) { // Forward to handler } // ... } public static void main(String[] args) throws InterruptedException { DBConnector connector = new DBConnector(/* suitable query */); Thread thread = new Thread(connector); thread.start(); Thread.sleep(5000); connector.shutdown(); } } |
Noncompliant Code Example (Interrupting thread executing in thread pool)
This noncompliant code example uses a runnable task shown below:
...
Wiki Markup |
---|
However, the interruption has no effect on the execution of the task because it is executing in a thread pool. Furthermore, note that it is unknown which tasks would be running in the thread pool at the time the interruption notification is delivered \[[Goetz 06|AA. Java References#Goetz 06]\]. |
Compliant Solution (Cancel using the Future)
This compliant solution obtains the return value of the task (future) and invokes the cancel()
method on it.
Code Block | ||
---|---|---|
| ||
class PoolService { private final ExecutorService pool; public PoolService(int poolSize) { pool = Executors.newFixedThreadPool(poolSize); } public void doSomething() throws InterruptedException { Future<?> future = null; try { future = pool.submit(new Task()); // ... } catch(Throwable t) { future.cancel(true); // Forward to handler } } } |
Noncompliant Code Example (shutting down thread pools)
Wiki Markup |
---|
According to the Java API \[[API 06|AA. Java References#API 06]\], interface {{java.util.concurrent.ExecutorService}}, method {{shutdownNow()}} documentation: |
...
Because the task does not support interruption through the use of Thread.interrupted()
, there is no guarantee that the shutdownNow()
method will shutdown the thread pool. Using the shutdown()
method does not fix the problem either because it waits until all executing tasks have finished. Likewise, tasks that check a volatile
flag to determine whether it is safe to shutdown are not responsive to these methods.
Compliant Solution (submit interruptible tasks)
Tasks that do not support interruption using Thread.interrupt()
should not be submitted to a thread pool. This compliant solution submits the interruptible version of SocketReader
discussed in Compliant Solution (interruptible channel) to the thread pool.
...
Similarly, when trying to cancel individual tasks within the thread pool using the Future.cancel()
method, ensure that the task supports interruption. If it does, pass a boolean
argument true
to cancel()
, otherwise pass false
. The value false
indicates that the task will be canceled if it has not already started.
Risk Assessment
Trying to force thread shutdown can result in inconsistent object state and corrupt the object. Critical resources may also leak if cleanup operations are not carried out as required.
Rule | Severity | Likelihood | Remediation Cost | Priority | Level |
---|---|---|---|---|---|
CON13- J | low | probable | medium | P4 | L3 |
Automated Detection
TODO
Related Vulnerabilities
Search for vulnerabilities resulting from the violation of this rule on the CERT website.
References
Wiki Markup |
---|
\[[API 06|AA. Java References#API 06]\] Class Thread, method {{stop}}, interface ExecutorService \[[Darwin 04|AA. Java References#Darwin 04]\] 24.3 Stopping a Thread \[[JDK7 08|AA. Java References#JDK7 08]\] Concurrency Utilities, More information: Java Thread Primitive Deprecation \[[JPL 06|AA. Java References#JPL 06]\] 14.12.1. Don't stop and 23.3.3. Shutdown Strategies \[[JavaThreads 04|AA. Java References#JavaThreads 04]\] 2.4 Two Approaches to Stopping a Thread \[[Goetz 06|AA. Java References#Goetz 06]\] Chapter 7: Cancellation and shutdown |
...