...
This noncompliant code example simply prints the exception's stack trace.
Code Block | ||
---|---|---|
| ||
try {
//...
} catch (IOException ioe) {
ioe.printStackTrace();
}
|
...
This compliant solution handles a FileNotFoundException
by requesting that the user specify another file name.
Code Block | ||
---|---|---|
| ||
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
|
...
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.
Code Block | ||
---|---|---|
| ||
public interface Reporter {
public void report(Throwable t);
}
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 library may subsequently use the exception reporter in catch
clauses:
Code Block | ||
---|---|---|
| ||
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:
Code Block | ||
---|---|---|
| ||
ExceptionReporter.setExceptionReporter(new ExceptionReporter() {
public void report(Throwable exception) {
JOptionPane.showMessageDialog(frame,
exception.toString,
exception.getClass().getName(),
JOptionPane.ERROR_MESSAGE);
}});
|
...
Sometimes exceptions must be hidden from the user for security reasons (see rule 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.
Code Block | ||
---|---|---|
| ||
class MyExceptionReporter extends ExceptionReporter {
private static final Logger logger =
Logger.getLogger("com.organization.Log");
public static void report(Throwable t) {
try {
final Throwable filteredException =
(t instanceof NonSensitiveException_1) ? t : filter(t);
} finally {
// Do any necessary user reporting
// (show dialog box or send to console)
if (filteredException instanceof NonSensitiveCommonException) {
logger.log(Level.FINEST, "Loggable exception occurred", t);
}
}
}
public static Exception filter(Throwable t) {
if (t instanceof SensitiveForLoggingException_1) {
// Do not log sensitive information (whitelist)
return SensitiveCommonException();
}
// ...
// Return for reporting to the user
return new NonSensitiveCommonException();
}
}
|
...
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
.
Code Block | ||
---|---|---|
| ||
class Foo implements Runnable {
public void run() {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// Ignore
}
}
}
|
...
This compliant solution catches the InterruptedException
and restores the interrupted status by calling the interrupt()
method on the current thread.
Code Block | ||
---|---|---|
| ||
class Foo implements Runnable {
public void run() {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
Thread.currentThread().interrupt(); // Reset interrupted status
}
}
}
|
...
ERR00-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 can attempt recovery. The most common implementation for this case is to omit a catch
block and allow the exception to propagate normally:
Code Block | ||
---|---|---|
| ||
// 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.
Code Block | ||
---|---|---|
| ||
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);
}
// ...
}
|
...
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 |
---|---|---|---|
Coverity | 7.5 | MISSING_THROW | Implemented |
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.
...
Item 65. Don't ignore exceptions; Item 62. Document all exceptions thrown by each method | |
5.4, Blocking and interruptible methods | |
[JLS 2005] |
06. Exceptional Behavior (ERR) 06. Exceptional Behavior (ERR)