The merits of exception handling are challenged when programmers do not realize how exceptions should be treated. Imprecise handling can lead to loss of critical information, on the other hand, being too specific can result in verbose (unreadable) code.
Noncompliant Code Example
In this noncompliant code example, a divide by zero exception was handled initially. Instead of the specific exception type ArithmeticException
, a more generic type Exception
was caught. This is dangerous since any future exception updates to the method signature (such as, addition of IOException
here) may no longer require the developer to provide a handler. Consequently, the recovery process may not be tailored to the specific exception type that gets thrown.
Additionally, unchecked exceptions under RuntimeException
are also unintentionally caught when the top level Exception
class is caught. See [[EXC32-J. Do not catch RuntimeException]] for details.
import java.io.IOException; public class DivideException { public static void main(String[] args) { try { division(200,5); division(200,0); //divide by zero } catch (Exception e) { System.out.println("Divide by zero exception : " + e.getMessage()); } } public static void division(int totalSum, int totalNumber) throws ArithmeticException, IOException { int average = totalSum/totalNumber; System.out.println("Average: "+ average); } }
Compliant Solution
To be compliant, catching specific exception types is advisable especially when the types differ significantly. Here, Arithmetic Exception
and IOException
have been unbundled as they belong to very diverse categories.
import java.io.IOException; public class DivideException { public static void main(String[] args) { try { division(200,5); division(200,0); //divide by zero } catch (ArithmeticException ae) { System.out.println("Divide by zero exception : " + ae.getMessage()); } catch (IOException ie) { System.out.println("I/O Exception occurred :" + ie.getMessage()); } } public static void division(int totalSum, int totalNumber) throws ArithmeticException, IOException { int average = totalSum/totalNumber; System.out.println("Average: "+ average); } }
There are several other antipatterns that must be avoided:
- Do not supress/ignore exceptions: This happens when an empty catch block is defined. The program catches the exception but does not perform any recovery or notification
- Masking of original exception by a new one: A new exception within a block may in certain cases mask the original exception
- Logging the same exception more than once: This creates ambiguity while tracing
- Throwing
Exception
andThrowable
- Encapsulating the original exception and throwing a completely new exception from the block
Risk Assessment
Not handling exceptions properly may result in information being lost, problems being overlooked, or too much information being passed to the user.
Rule |
Severity |
Likelihood |
Remediation Cost |
Priority |
Level |
---|---|---|---|---|---|
EXC00-J |
medium |
probable |
high |
P4 |
L3 |
Automated Detection
TODO
Related Vulnerabilities
Search for vulnerabilities resulting from the violation of this rule on the CERT website.
References
[[JLS 05]] Chapter 11, Exceptions
[[Tutorials 08]] Exceptions
[[Doshi 03]]
[[Müller 02]]
[[MITRE 09]] CWE ID 396 "Declaration of Catch for Generic Exception", CWE ID 390 "Detection of Error Condition Without Action"
10. Exceptional Behavior (EXC) 10. Exceptional Behavior (EXC) EXC01-J. Do not allow exceptions to transmit sensitive information