Skip to end of metadata
Go to start of metadata

Programmers often suppress checked exceptions by catching exceptions with an empty or trivial catch block. Each catch block must ensure that the program continues only with valid invariants. Consequently, the catch block must either recover from the exceptional condition, rethrow the exception to allow the next nearest enclosing catch clause of a try statement to recover, or throw an exception that is appropriate to the context of the catch block.

Exceptions disrupt the expected control flow of the application. For example, no part of any expression or statement that occurs in the try block after the point from which the exception is thrown is evaluated. Consequently, exceptions must be handled appropriately. Many reasons for suppressing exceptions are invalid. For example, when the client cannot be expected to recover from the underlying problem, it is good practice to allow the exception to propagate outwards rather than to catch and suppress the exception.

Noncompliant Code Example

This noncompliant code example simply prints the exception's stack trace:

try {
  //...
} catch (IOException ioe) {
  ioe.printStackTrace();
}

Printing the exception's stack trace can be useful for debugging purposes, but the resulting program execution is equivalent to suppressing the exception. Printing the stack trace can also leak information about the structure and state of the process to an attacker (see ERR01-J. Do not allow exceptions to expose sensitive information for more information). Note that even though this noncompliant code example reacts to the exception by printing out a stack trace, it then proceeds as though the exception were not thrown. That is, the behavior of the application is unaffected by the exception being thrown except that any expressions or statements that occur in the try block after the point from which the exception is thrown are not evaluated.

Compliant Solution (Interactive)

This compliant solution handles a FileNotFoundException by requesting that the user specify another file name:

volatile boolean validFlag = false;
do {
  try {
    // If requested file does not exist, throws FileNotFoundException
    // If requested file exists, sets validFlag to true
    validFlag = true;
  } catch (FileNotFoundException e) {
    // Ask the user for a different file name
  }
} while (validFlag != true);
// Use the file

To comply with ERR01-J. Do not allow exceptions to expose sensitive information, the user should only be allowed to access files in a user-specific directory. This prevents any other IOException that escapes the loop from leaking sensitive file system information.

Compliant Solution (Exception Reporter)

Proper reporting of exceptional conditions is context-dependent. For example, GUI applications should report the exception in a graphical manner, such as in an error dialog box. Most library classes should be able to objectively determine how an exception should be reported to preserve modularity; they cannot rely on System.err, on any particular logger, or on the availability of the windowing environment. As a result, library classes that wish to report exceptions should specify the API they use to report exceptions. This compliant solution specifies both an interface for reporting exceptions, which exports the report() method, and a default exception reporter class that the library can use. The exception reporter can be overridden by subclasses.

public interface Reporter {
  public void report(Throwable t);
}

class ExceptionReporterPermission extends Permission {
  // ...
}

public class ExceptionReporter {

  // Exception reporter that prints the exception 
  // to the console (used as default)
  private static final Reporter PrintException = new Reporter() {
    public void report(Throwable t) {
      System.err.println(t.toString());
    }
  };

  // Stores the default reporter
  // The default reporter can be changed by the user
  private static Reporter Default = PrintException;

  // Helps change the default reporter back to 
  // PrintException in the future
  public static Reporter getPrintException() {
    return PrintException;
  }

  public static Reporter getExceptionReporter() {
    return Default;
  }

  // May throw a SecurityException (which is unchecked)
public static void setExceptionReporter(Reporter reporter) {
    // Custom permission
    ExceptionReporterPermission perm = new 
        ExceptionReporterPermission("exc.reporter"); 
    SecurityManager sm = System.getSecurityManager();
    if (sm != null) {
      // Check whether the caller has appropriate permissions
      sm.checkPermission(perm);
    }
    // Change the default exception reporter
    Default = reporter; 
  }
}

The setExceptionReporter() method prevents hostile code from maliciously installing a more verbose reporter that leaks sensitive information or that directs exception reports to an inappropriate location, such as the attacker's computer, by limiting attempts to change the exception reporter to callers that have the custom permission ExceptionReporterPermission with target exc.reporter.

The library may subsequently use the exception reporter in catch clauses:

try {
  // ...
} catch (IOException warning) {
  ExceptionReporter.getExceptionReporter().report(warning);
  // Recover from the exception...
}

Any client code that possesses the required permissions can override the ExceptionReporter with a handler that logs the error or provides a dialog box, or both. For example, a GUI client using Swing may require exceptions to be reported using a dialog box:

ExceptionReporter.setExceptionReporter(new ExceptionReporter() {
  public void report(Throwable exception) {
    JOptionPane.showMessageDialog(frame,
                                  exception.toString,
                                  exception.getClass().getName(),
                                  JOptionPane.ERROR_MESSAGE);
  }});

Compliant Solution (Subclass Exception Reporter and Filter-Sensitive Exceptions)

Sometimes exceptions must be hidden from the user for security reasons (see ERR01-J. Do not allow exceptions to expose sensitive information). In such cases, one acceptable approach is to subclass the ExceptionReporter class and add a filter() method in addition to overriding the default report() method.

class MyExceptionReporter extends ExceptionReporter {
  private static final Logger logger =
      Logger.getLogger("com.organization.Log");

  public static void report(Throwable t) {
    t = filter(t);
    if (t != null) {
      logger.log(Level.FINEST, "Loggable exception occurred", t);
    }
  }

  public static Exception filter(Throwable t) {
    if (t instanceof SensitiveException1) {
      // Too sensitive, return nothing (so that no logging happens)
      return null;
    } else if (t instanceof SensitiveException2) {
      // Return a default insensitive exception instead
      return new FilteredSensitiveException(t);
    }
    // ...
    // Return for reporting to the user
    return t;
  }
}

 
// ...Definitions for SensitiveException1, SensitiveException2
// and FilteredSensitiveException...

The report() method accepts a Throwable instance and consequently handles all errors, checked exceptions, and unchecked exceptions. The filtering mechanism is based on a whitelisting approach wherein only nonsensitive exceptions are propagated to the user. Exceptions that are forbidden to appear in a log file can be filtered in the same fashion (see FIO13-J. Do not log sensitive information outside a trust boundary). This approach provides the benefits of exception chaining by reporting exceptions tailored to the abstraction while also logging the low-level cause for future failure analysis [Bloch 2008].

Noncompliant Code Example

If a thread is interrupted while sleeping or waiting, it causes a java.lang.InterruptedException to be thrown. However, the run() method of interface Runnable cannot throw a checked exception and must handle InterruptedException. This noncompliant code example catches and suppresses InterruptedException:

class Foo implements Runnable {
  public void run() {
    try {
      Thread.sleep(1000);
    } catch (InterruptedException e) {
      // Ignore
    }
  }
}

This code prevents callers of the run() method from determining that an interrupted exception occurred. Consequently, caller methods such as Thread.start() cannot act on the exception [Goetz 2006]. Likewise, if this code were called in its own thread, it would prevent the calling thread from knowing that the thread was interrupted.

Compliant Solution

This compliant solution catches the InterruptedException and restores the interrupted status by calling the interrupt() method on the current thread:

class Foo implements Runnable {
  public void run() {
    try {
      Thread.sleep(1000);
    } catch (InterruptedException e) {
      Thread.currentThread().interrupt(); // Reset interrupted status
    }
  }
}

Consequently, calling methods (or code from a calling thread) can determine that an interrupt was issued [Goetz 2006].

Exceptions

ERR00-J-EX0: Exceptions that occur during the freeing of a resource may be suppressed in those cases where failure to free the resource cannot affect future program behavior. Examples of freeing resources include closing files, network sockets, shutting down threads, and so forth. Such resources are often freed in catch or finally blocks and never reused during subsequent execution. Consequently, the exception cannot influence future program behavior through any avenue other than resource exhaustion. When resource exhaustion is adequately handled, it is sufficient to sanitize and log the exception for future improvement; additional error handling is unnecessary in this case.

ERR00-J-EX1: When recovery from an exceptional condition is impossible at a particular abstraction level, code at that level must not handle that exceptional condition. In such cases, an appropriate exception must be thrown so that higher level code can catch the exceptional condition and attempt recovery. The most common implementation for this case is to omit a catch block and allow the exception to propagate normally:

// When recovery is possible at higher levels
private void doSomething() throws FileNotFoundException {
  // Requested file does not exist; throws FileNotFoundException
  // Higher level code can handle it by displaying a dialog box and asking
  // the user for the file name
}

Some APIs may limit the permissible exceptions thrown by particular methods. In such cases, it may be necessary to catch an exception and either wrap it in a permitted exception or translate it to one of the permitted exceptions:

public void myMethod() throws MyProgramException {
  // ...
  try {
    // Requested file does not exist
    // User is unable to supply the file name
  } catch (FileNotFoundException e) {
    throw new MyProgramException(e);
  }
  // ...
}

Alternatively, when higher level code is also unable to recover from a particular exception, the checked exception may be wrapped in an unchecked exception and rethrown.

ERR00-J-EX2: An InterruptedException may be caught and suppressed when extending class Thread [Goetz 2006]. An interruption request may also be suppressed by code that implements a thread's interruption policy [Goetz 2006, p. 143].

Risk Assessment

Ignoring or suppressing exceptions can result in inconsistent program state.

Rule

Severity

Likelihood

Remediation Cost

Priority

Level

ERR00-J

Low

Probable

Medium

P4

L3

Automated Detection

Detection of suppressed exceptions is straightforward. Sound determination of which specific cases represent violations of this rule and which represent permitted exceptions to the rule is infeasible. Heuristic approaches may be effective.

Tool
Version
Checker
Description
CodeSonar4.4FB.BAD_PRACTICE.DE_MIGHT_IGNOREMethod might ignore exception
Coverity7.5MISSING_THROWImplemented
Parasoft Jtest9.5SECURITY.UEHL.LGE, UC.UCATCHImplemented
SonarQube Java Plugin4.11S1166 

Related Vulnerabilities

AMQ-1272 describes a vulnerability in the ActiveMQ service. When ActiveMQ receives an invalid username and password from a Stomp client, a security exception is generated but is subsequently ignored, leaving the client connected with full and unrestricted access to ActiveMQ.

Related Guidelines

MITRE CWE

CWE-390, Detection of Error Condition without Action

Bibliography

[Bloch 2008]

Item 62, "Document All Exceptions Thrown by Each Method"
Item 65, "Don't Ignore Exceptions"

[Goetz 2006]

Section 5.4, "Blocking and Interruptible Methods"

[JLS 2015]

Chapter 11, "Exceptions"

 


25 Comments

  1. The "other antipatterns" should be other rules and recommendations.

    Perhaps we need a new section on exceptions.

    1. I was considering keeping a separate section. I think it is possible to deal with these antipatterns as separate rules/recommendations. I'll get to it. Thanks.

  2. Doshi [Doshi 03] says:

    "3. Do not suppress or ignore exceptions

    "When a method from an API throws a checked exception, it is trying to tell you that you should take some counter action. If the checked exception does not make sense to you, do not hesitate to convert it into an unchecked exception and throw it again, but do not ignore it by catching it with {} and then continue as if nothing had happened."

    This guideline should say essentially the same thing.

  3. This recommendation deals explicitly with checked exceptions, so the following discussion of unchecked exceptions maybe should go in a different rule/recommendation:

    "Although, not explicitly required by this recommendation, failure tolerant systems must also catch and handle unexpected unchecked exceptions resulting from programming errors. In all other cases, refrain from using the throws clause to force the client into dealing with unchecked exceptions Bloch 08."

    Also, what does the second sentence mean? That unchecked exceptions should not be explicitly listed in the definition of a method?

    1. Fixed now (IIRC earlier this guideline was broader i.e. it took into account unchecked exceptions too, which led to this error). The second sentence means what you say, however, it does not "force" the client to handle the exception.

  4. "EX2: It is also permissible to ignore the exception when the client cannot be expected to recover from the exception easily."

    This exception may be problematic. The thrown exception indicates something bad has happened and ignoring the exception, even if the client cannot recover from the exception, is still unlikely to leave the client in a state where continuing as if there was no problem will work. On the web I have seen several recommendations that in this case the client catches the checked exception and rethrows it as an unchecked exception indicating "an unrecoverable error occurred". The unchecked exception would then be handled by the application in the same way other unchecked exceptions (like NullPointerException) are handled, either by a high level catch that tries to gracefully degrade the application or by simply crashing the application.

    1. I've elaborated EX2. Does this address your comment?

      1. Yes, that looks good.

  5. Hmmm. EX1 here violates guideline EXC05-J. That seems rather odd.

    1. Fix: s/ignore/suppress/

      1. To be more verbose, 'suppress' means catch the exception and do nothing to address it. In a catch block, 'ignore' has the same meaning, but normally 'ignore' could also mean not to catch the exception. Because of this ambiguity, I would prefer the word 'suppress' over 'ignore' in normative text, although both are commonly used wrt exception handling.

        1. Even with the rewording, I'm not sure I agree with EXC00-EX1...what is so special about a finally block that exceptions can be suppressed in it? The closest answer I know of is that finally blocks are often used to close resources (files, processes etc), and exceptions that occur during resource deallocation often do not prevent normal resumption of the code. In which case EX1 is better off focussing on resource deallocation rather than on finally blocks. But listing resource deallocation functions is a daunting task, and w/o such a list, the rule would be non-normative.

          UPDATE: s/EX1/EX0/ in the above paragraph

          1. Rewrote EX0 to focus on resource freeing.

            1. tweaked EX0 in an attempt to emphasize that we're excepting only the cases that either

              • can't affect future operation, or
              • whose only future effect is due to resource exhaustion and where that possibility is adequately addressed. This caveat is intended to acknowledge that there may be cases where you just can't prevent resource exhaustion.
          2. Having exception handling in finally can be awkward because then you might need a finally inside finally and this can go on forever.

            1. I doubt it can go on forever, because the inner finally clause often will protect against a different exception than the outer clause. But it can certainly get complicated. That's why EX0 permits suppressing exceptions when closing resources, which are often the purpose of finally clauses.

  6. I'm not too crazy about the interactive solution:

    This compliant solution attempts to recover from a FileNotFoundException by requesting that the user specify another file name.

    The problem is that an interactive solution must also allow the user to cancel the operation, which is not really supported by the code.

    There is also this paragraph:

    The user is allowed to access only files in a user-specific directory. This prevents any other IOException that escapes the loop from leaking potentially sensitive file system information. See guideline ERR06-J. Do not allow exceptions to expose sensitive information for additional information.

    It seems to add a requirement to the problem (the user is allowed to access only files in a user-specific directory) here in the compliant solution. My solution would be to remove this paragraph, as I don't understand why it is here.

    1. The problem is that an interactive solution must also allow the user to cancel the operation, which is not really supported by the code.

      First, why must an interactive solution allow for canceling? (I've often wished to cancel entering my password only to find that impossible.) Second, I suppose a cancel operation would take the form of 'throw CancelledException', which propagates outside the code sample.

      It seems to add a requirement to the problem (the user is allowed to access only files in a user-specific directory) here in the compliant solution. My solution would be to remove this paragraph, as I don't understand why it is here.

      I reworded the paragraph. It does add a requirement to the program, that ssimply must be added in order to comply with ERR06-J.

    • ERR0 has a few places where method names are not followed by (). For example, "The
      setExceptionReporter method" vs. "The setExceptionReporter() method".
    • Broken link to SEC10J. I also think the security permission related stuff can be eliminated from the guideline.
    • If at all, migrate the example of security permissions to the rule in SEC that talks about using custom security permissions.
    • In ERR00-EX1, The last blue block should occur above the statement - "Alternatively, when higher level code is also unable to recover from a particular exception, the checked exception may be wrapped in an unchecked exception and rethrown."

    because IOException is NOT an unchecked exception. This is an example of a "permitted exception".

      • ERR0 has a few places where method names are not followed by (). For example, "The setExceptionReporter method" vs. "The setExceptionReporter() method".

      Fixed some. Don't want to put too much effort into fixing this, it's better to have a tech writer fix this globally.

      • Broken link to SEC10J. I also think the security permission related stuff can be eliminated from the guideline.

      Cut out the link. SEC10-J was a good rule but nonnormative BTW.

      • If at all, migrate the example of security permissions to the rule in SEC that talks about using custom security permissions.

      Not sure which rule this is, and I suspect it is nonnormative, so we can't link to it.

      • In ERR00-EX1, The last blue block should occur above the statement - "Alternatively, when higher level code is also unable to recover from a particular exception, the checked exception may be wrapped in an unchecked exception and rethrown."

      Done

  7. I disagree with ERR00-EX0. Suppose an exception did occur in a close, what are the possible reasons?

    It could be that part of the happy-case sequence of operations on the resource failed to complete. Flushed buffer, committed transactions, or whatever. In that case, you should generally exit with some kind of exception.

    Alternatively something may have gone badly wrong. Generally this would be an unchecked exception, although you can't be too rigid about check vs unchecked. In this case also want to exit with an exception.

    The only case I can see where you'd want to suppress such an exception is to make way for another exception (and it probably makes very little odds which one wins).

    1. This is a very old OOP problem with no good solution, it is very prevalent in C++ regarding destructors. I wouldn't be surprised if there's a paper talking about this in SIMULA. Good OOD includes minimizing the possibility of exceptions occuring during the closing of a resource. The raison d'etre for EX0 is that, occasionally, ignoring the exception is the Right Thing to do. I did some wordsmithing on the text...hopefully it is clearer now.

  8. ERR00-EX1 - Wrapping FileNotFoundException in a IOException is pointless as FileNotFoundException extends IOException.

    1. Agreed. Fixed code example.

  9. In the CS which implements the filtering reporter, is the logger line supposed to be logging the "filteredException" instead of "t"?  otherwise, the example doesn't make much sense.  (additionally, the code is not valid java as the filteredException variable as currently declared is not visible in the catch block).