Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.
Comment: Parasoft Jtest 2021.1

When certain kinds of errors are detected, such as irrecoverable logic errors, rather than risk data corruption by continuing to execute in an indeterminate state, the appropriate strategy may be for the system to quickly shut down, allowing the operator to start it afresh in a determinate state.
Section 6.46, "Termination Strategy [REU]," [ISO/IEC TR 24772:2010] says:

When a fault is detected, there are many ways in which a system can react. The quickest and most noticeable way is to fail hard, also known as fail fast or fail stop. The reaction to a detected fault is to immediately halt the system. Alternatively, the reaction to a detected fault could be to fail soft. The system would keep working with the faults present, but the performance of the system would be degraded. Systems used in a high availability environment such as telephone switching centers, e-commerce, or other "always available" applications would likely use a fail soft approach. What is actually done in a fail soft approach can vary depending on whether the system is used for safety critical or security critical purposes. For fail-safe systems, such as flight controllers, traffic signals, or medical monitoring systems, there would be no effort to meet normal operational requirements, but rather to limit the damage or danger caused by the fault. A system that fails securely, such as cryptologic systems, would maintain maximum security when a fault is detected, possibly through a denial of service.

And:

The reaction to a fault in a system can depend on the criticality of the part in which the fault originates. When a program consists of several tasks, each task may be critical, or not. If a task is critical, it may or may not be restartable by the rest of the program. Ideally, a task that detects a fault within itself should be able to halt leaving its resources available for use by the rest of the program, halt clearing away its resources, or halt the entire program. The latency of task termination and whether tasks can ignore termination signals should be clearly specified. Having inconsistent reactions to a fault can potentially be a vulnerability.

Java provides two options for program termination: Runtime.exit() (which is equivalent to System.exit()) and Runtime.halt().

Runtime.exit()

Runtime.exit() is the typical way of exiting a program. According to the Java API [API 2014], Runtime.exit():

terminates the currently running Java virtual machine by initiating its shutdown sequence. This method never returns normally. The argument serves as a status code; by convention, a nonzero status code indicates abnormal termination.

The virtual machine's shutdown sequence consists of two phases. In the first phase all registered shutdown hooks, if any, are started in some unspecified order and allowed to run concurrently until they finish. In the second phase all uninvoked finalizers are run if finalization-on-exit has been enabled. Once this is performed the virtual machine halts.

If this method is invoked after the virtual machine has begun its shutdown sequence, then if shutdown hooks are being run, this method will block indefinitely. If shutdown hooks have already been run and on-exit finalization has been enabled, then this method halts the virtual machine with the given status code if the status is nonzero; otherwise, it blocks indefinitely.

The System.exit() method is the conventional and convenient means of invoking this method.

The Runtime.addShutdownHook() method can be used to customize Runtime.exit() to perform additional actions at program termination. This method uses a Thread, which must be initialized but unstarted. The thread starts when the Java Virtual Machine (JVM) begins to shut down. Because the JVM usually has a fixed time to shut down, these threads should not be long-running and should not attempt user interaction.

Runtime.halt()

Runtime.halt() is similar to Runtime.exit() but does not run shutdown hooks or finalizers. According to the ava API [API 2014], Runtime.halt()

forcibly terminates the currently running Java virtual machine. This method never returns normally.
This method should be used with extreme caution. Unlike the exit method, this method does not cause shutdown hooks to be started and does not run uninvoked finalizers if finalization-on-exit has been enabled. If the shutdown sequence has already been initiated, then this method does not wait for any running shutdown hooks or finalizers to finish their work.

Java programs do not flush unwritten buffered data or close open files when they exit, so programs must perform these operations manually. Programs must also perform any other cleanup that involves external resources, such as releasing shared locks.

Noncompliant Code Example

This example creates a new file, outputs some text to it, and abruptly exits using Runtime.exit(). Consequently, the file may be closed without the text actually being written.

Code Block
bgColor#ffcccc
public class CreateFile {
  public static void main(String[] args)
                          throws FileNotFoundException {
    final PrintStream out =
        new PrintStream(new BufferedOutputStream(
                        new FileOutputStream("foo.txt")));
    out.println("hello");
    Runtime.getRuntime().exit(1);
  }
}

Compliant Solution (close())

This solution explicitly closes the file before exiting:

Code Block
bgColor#ccccff
public class CreateFile {
  public static void main(String[] args)
                          throws FileNotFoundException {
    final PrintStream out =
    new PrintStream(new BufferedOutputStream(
        new FileOutputStream("foo.txt")));
    try {
      out.println("hello");
    } finally {
    try {
      out.close();
   } catch (IOException x) {
     // Handle error
   }
    }
    Runtime.getRuntime().exit(1);
  }
}

Compliant Solution (Shutdown Hook)

This compliant solution adds a shutdown hook to close the file. This hook is invoked by Runtime.exit() and is called before the JVM is halted.

Code Block
bgColor#ccccff
public class CreateFile {
  public static void main(String[] args)
                          throws FileNotFoundException {
    final PrintStream out =
        new PrintStream(new BufferedOutputStream(
                        new FileOutputStream("foo.txt")));
    Runtime.getRuntime().addShutdownHook(new Thread(new Runnable() {
        public void run() {

Wiki Markup
Some errors, such as out-of-range values, might be the result of erroneous user input. Interactive programs typically handle such errors by rejecting the input and prompting the user for an acceptable value. Servers reject invalid user input by indicating an error to the client while at the same continuing to respond to other clients. All robust programs must be prepared to gracefully handle resource exhaustion such as low memory or disk space conditions, at a minimum by preventing the loss of user data kept in volatile storage. Interactive programs may give the user the option to save data on an alternate medium, while network servers may respond by reducing throughput or otherwise degrading the quality of service.  However, when certain kinds of errors are detected, such as irrecoverable logic errors, rather than risk data corruption by continuing to execute in an indeterminate state, the appropriate strategy may be for the system to quickly shut down, allowing the operator to start it afresh in a determinate state.
\[[ISO/IEC PDTR 24772|AA. Bibliography#ISO/IEC PDTR 24772]\] Section 6.47, "REU Termination strategy," says:

When a fault is detected, there are many ways in which a system can react. The quickest and most noticeable way is to fail hard, also known as fail fast or fail stop. The reaction to a detected fault is to immediately halt the system. Alternatively, the reaction to a detected fault could be to fail soft. The system would keep working with the faults present, but the performance of the system would be degraded. Systems used in a high availability environment such as telephone switching centers, e-commerce, etc. would likely use a fail soft approach. What is actually done in a fail soft approach can vary depending on whether the system is used for safety critical or security critical purposes. For fail safe systems, such as flight controllers, traffic signals, or medical monitoring systems, there would be no effort to meet normal operational requirements, but rather to limit the damage or danger caused by the fault. A system that fails securely, such as cryptologic systems, would maintain maximum security when a fault is detected, possibly through a denial of service.

And also:

The reaction to a fault in a system can depend on the criticality of the part in which the fault originates. When a program consists of several tasks, the tasks each may be critical, or not. If a task is critical, it may or may not be restartable by the rest of the program. Ideally, a task which detects a fault within itself should be able to halt leaving its resources available for use by the rest of the program, halt clearing away its resources, or halt the entire program. The latency of any such communication, and whether other tasks can ignore such a communication, should be clearly specified. Having inconsistent reactions to a fault, such as the fault reaction to a crypto fault, can potentially be a vulnerability.

Java provides two options for program termination: Runtime.exit() (this is equivalent to System.exit()) and Runtime.halt().

Runtime.exit()

Runtime.exit() is the typical way of exiting a program:

Terminates the currently running Java virtual machine by initiating its shutdown sequence. This method never returns normally. The argument serves as a status code; by convention, a nonzero status code indicates abnormal termination.
The virtual machine's shutdown sequence consists of two phases. In the first phase all registered shutdown hooks, if any, are started in some unspecified order and allowed to run concurrently until they finish. In the second phase all uninvoked finalizers are run if finalization-on-exit has been enabled. Once this is done the virtual machine halts.

If this method is invoked after the virtual machine has begun its shutdown sequence then if shutdown hooks are being run this method will block indefinitely. If shutdown hooks have already been run and on-exit finalization has been enabled then this method halts the virtual machine with the given status code if the status is nonzero; otherwise, it blocks indefinitely.

The System.exit method is the conventional and convenient means of invoking this method.

The Runtime.addShutdownHook() method can be used to customize Runtime.exit() to perform additional actions at program termination.
This method takes a single Thread, which must be initalized but unstarted. Then, when the JVM begins to shut down, the thread will be run. Since the JVM usually has a fixed time to shut down, these threads should not be long-running and should not attempt user interaction.

Runtime.halt()

Runtime.halt() works similarly but does NOT run shutdown hooks or finalizers:

Forcibly terminates the currently running Java virtual machine. This method never returns normally.
This method should be used with extreme caution. Unlike the exit method, this method does not cause shutdown hooks to be started and does not run uninvoked finalizers if finalization-on-exit has been enabled. If the shutdown sequence has already been initiated then this method does not wait for any running shutdown hooks or finalizers to finish their work.

In contrast with C and C++, Java does not flush unwritten buffered data or close open files when it exits, so programs must do this manually. Programs must also do any other cleanup that involves external resources, such as releasing shared locks.

Noncompliant Code Example

This example creates a new file, outputs some text to it, and abruptly exits using Runtime.exit(). Consequently, the file is closed without the text actually being written to it.

Code Block
bgColor#ffcccc

public class CreateFile {
  public static void main(String[] args) throws FileNotFoundException {
    final PrintStream out = new PrintStream( new BufferedOutputStream(
                            out.close();
        }
    new FileOutputStream("foo.txt")}));
    out.println("hello");
    Runtime.getRuntime().exit(1);
  }
}

Compliant Solution (close())

Noncompliant Code Example (Runtime.halt())

This noncompliant code example calls Runtime.halt() instead of Runtime.exit(). The Runtime.halt() method stops the JVM without invoking any shutdown hooks; consequently, the file is not properly written to or closed.This solution explicitly closes the file before exiting

Code Block
bgColor#ccccff#ffcccc

public class CreateFile {
  public static void main(String[] args))
                          throws FileNotFoundException {
    final PrintStream out = new PrintStream( new BufferedOutputStream(
          new PrintStream(new BufferedOutputStream(
                            new FileOutputStream("foo.txt")));
    out.println("hello");
    out.close();
    Runtime.getRuntime().exit(1)));
   }
}

Compliant Solution (Shutdown Hook)

This compliant solution adds a shutdown hook to close the file. This hook is invoked by Runtime.exit() is called before the JVM is halted.

Code Block
bgColor#ccccff

public class CreateFile {
  public static void main(String[] args) throws FileNotFoundException  Runtime.getRuntime().addShutdownHook(new Thread(new Runnable() {
        public void run() {
    final PrintStream out = new PrintStream( new BufferedOutputStream( out.close();
        }
    }));
    out.println("hello");
                        new FileOutputStream("foo.txt")));
    Runtime.getRuntime().addShutdownHook(new Thread(new Runnable()Runtime.getRuntime().halt(1);
  }
}

Noncompliant Code Example (Signal)

When a user forcefully exits a program, for example by pressing the Ctrl+C keys or by using the kill command, the JVM terminates abruptly. Although this event cannot be captured, the program should nevertheless perform any mandatory cleanup operations before exiting. This noncompliant code example fails to do so.

Code Block
bgColor#FFcccc
public class InterceptExit {
  public static     public void runmain(String[] args) {
          out.close();
        }
      }));
  throws  out.println("hello");FileNotFoundException {
    Runtime.getRuntime().exit(1);
  }
}

Noncompliant Code Example (Runtime.halt())

This noncompliant code example calls Runtime.halt() instead of Runtime.exit(). Runtime.halt() stops the JVM without invoking any shutdown hooks; consequently the file is not properly written to or closed.

Code Block
bgColor#ffcccc

public class CreateFile {
  public static void main(String[] args) throws FileNotFoundException {
    final PrintStream out = new PrintStream( new BufferedOutputStream(InputStream in = null;
    try {
      in = new FileInputStream("file");
      System.out.println("Regular code block");
      // Abrupt exit such as ctrl + c key pressed
      System.out.println("This never executes");
    } finally {
      if (in != null) {
        try {
         new FileOutputStream("foo.txt"))in.close();
    Runtime.getRuntime().addShutdownHook(new Thread(new Runnable() {// This never executes either
        public} voidcatch run(IOException x) {
          //  out.close();Handle error
        }
      }));
    out.println("hello");
    Runtime.getRuntime().halt(1);  }
  }
}

Noncompliant Code Example (signal)

When a user forcefully exits a program by pressing the ctrl + c key or by using the kill command, the JVM terminates abruptly. Although this event cannot be captured, the program should nevertheless perform any mandatory clean-up operations before exiting. This noncompliant code example fails to do so.

Code Block
bgColor#FFcccc

public class InterceptExit {
  public static void main(String[] args) {
    System.out.println("Regular code block");
    // Abrupt exit such as ctrl + c key pressed
    System.out.println("This never executes");
  }
}

Compliant Solution (addShutdownHook())

Use the addShutdownHook() method of java.lang.Runtime to assist with performing clean-up operations in the event of abrupt termination. The JVM starts the shutdown hook thread when abrupt termination is initiated; the shutdown hook runs concurrently with other JVM threads.

Wiki Markup
According to the Java API \[[API 2006|AA. Bibliography#API 06]\] Class {{Runtime}}, method {{addShutdownHook}}

A shutdown hook is simply an initialized but unstarted thread. When the virtual machine begins its shutdown sequence it will start all registered shutdown hooks in some unspecified order and let them run concurrently. When all the hooks have finished it will then run all uninvoked finalizers if finalization-on-exit has been enabled. Finally, the virtual machine will halt. Once the shutdown sequence has begun it can be stopped only by invoking the halt method, which forcibly terminates the virtual machine. Once the shutdown sequence has begun it is impossible to register a new shutdown hook or de-register a previously-registered hook.

Some precautions must be taken because the JVM is in a sensitive state during shutdown. Shutdown hook threads should:

  • be light-weight and simple
  • be thread safe
  • hold locks when accessing data and release those locks when done
  • Wiki Markup
    lack reliance on system services, as the services themselves may be shutting down (for example, the logger may shutdown from another hook). Instead of one service it may be better to run a series of shutdown tasks from one thread by using a single shutdown hook \[[Goetz 2006|AA. Bibliography#Goetz 06]\].

This compliant solution shows the standard method to install a hook.

Compliant Solution (addShutdownHook())

Use the addShutdownHook() method of java.lang.Runtime to assist with performing cleanup operations in the event of abrupt termination. The JVM starts the shutdown hook thread when abrupt termination is initiated; the shutdown hook runs concurrently with other JVM threads.

According to the Java API [API 2014], class Runtime, method addShutdownHook(),

A shutdown hook is simply an initialized but unstarted thread. When the virtual machine begins its shutdown sequence it will start all registered shutdown hooks in some unspecified order and let them run concurrently. When all the hooks have finished it will then run all uninvoked finalizers if finalization-on-exit has been enabled. Finally, the virtual machine will halt. Once the shutdown sequence has begun it can be stopped only by invoking the halt method, which forcibly terminates the virtual machine....
Once the shutdown sequence has begun it is impossible to register a new shutdown hook or de-register a previously registered hook.

Some precautions must be taken because the JVM might be in a sensitive state during shutdown. Shutdown hook threads should

  • Be lightweight and simple.
  • Be thread-safe.
  • Hold locks when accessing data and release those locks when done.
  • Avoid relying on system services, because the services themselves may be shut down (for example, the logger may be shut down from another hook).

To avoid race conditions or deadlock between shutdown actions, it may be better to run a series of shutdown tasks from one thread by using a single shutdown hook [Goetz 2006].

This compliant solution shows the standard method to install a hook:

Code Block
bgColor#ccccff
public class Hook {

  public static void main(String[] args) {
    try {
      final InputStream in = new FileInputStream("file");
      Runtime.getRuntime().addShutdownHook(new Thread() {
          public void run() {
            // Log shutdown and close all resources
            in.close();
          }
      });

     // ...
    } catch (IOException x) {
      // Handle error
    } catch (FileNotFoundException x) {
      // Handle error
    }
Code Block
bgColor#ccccff

public class Hook {
  public static void main(String[] args) {
    Runtime.getRuntime().addShutdownHook(new Thread() {
      public void run() {
        hookShutdown();
      }
    });
		
   // ...
  }

  public static void hookShutdown() {
    // Log shutdown and close all resources
  }
}

The JVM can abort for external reasons, such as an external SIGKILL signal (UNIXPOSIX) or the TerminateProcess() call (Microsoft Windows), or because of memory corruption caused by native methods. Shutdown hooks may fail to execute as expected in such cases , because the JVM cannot guarantee that they will be executed as intended.

Risk Assessment

Using Runtime.halt() in place of Runtime.exit() may not perform necessary cleanup, potentially leaving sensitive data exposed or leaving data in an inconsistent state.

Recommendation

Severity

Likelihood

Remediation Cost

Priority

Level

FIO16-J

medium

low

medium

P4

L3

Other Languages

...

Failure to perform necessary cleanup at program termination may leave the system in an inconsistent state.

Rule

Severity

Likelihood

Remediation Cost

Priority

Level

FIO14-J

Medium

Likely

Medium

P12

L1

Automated Detection

ToolVersionCheckerDescription
Parasoft Jtest
Include Page
Parasoft_V
Parasoft_V
CERT.FIO14.CIO
CERT.FIO14.CCR
CERT.FIO14.CRWD
Close input and output resources in "finally" blocks
Close all "java.io.Closeable" resources in a "finally" block
Close resources as early as possible

Related Guidelines

...

...

...

...

ISO/IEC TR 24772:2010

Termination Strategy [REU]

MITRE CWE

CWE-705, Incorrect Control Flow Scoping

Android Implementation Details

Although most of the code examples are not applicable to the Android platform, the principle is applicable to Android. Aprocess on Android can be terminated in a number of ways: android.app.Activity.finish() and the related finish() methods, android.app.Activity.moveTaskToBack(boolean flag), android.os.Process.killProcess(int pid), and System.exit().

Bibliography

[API 2014]

Class Runtime.exit() 

[ISO/IEC TR 24772:2010]

Section 6.46, "Termination Strategy [REU]"


...

Image Added Image Added Image Added

Bibliography

Wiki Markup
\[[ISO/IEC PDTR 24772|AA. Bibliography#ISO/IEC PDTR 24772]\] "REU Termination strategy"
\[[MITRE 07|AA. Bibliography#MITRE 07]\] [CWE ID 705|http://cwe.mitre.org/data/definitions/705.html], "Incorrect Control Flow Scoping"

ERR15-J. Do not catch NullPointerException      06. Exceptional Behavior (ERR)      07. Visibility and Atomicity (VNA)