Query for uncaught NumberFormatException

This commit is contained in:
Nate Nystrom
2018-10-23 19:03:15 +02:00
parent 1f390f2f77
commit e174ca6ed8
3 changed files with 141 additions and 0 deletions

View File

@@ -0,0 +1,10 @@
String s = ...;
int n;
n = Integer.parseInt(s); // BAD: NumberFormatException is not caught.
try {
n = Integer.parseInt(s);
} catch (NumberFormatException e) { // GOOD: The exception is caught.
// Handle the exception
}

View File

@@ -0,0 +1,43 @@
<!DOCTYPE qhelp PUBLIC
"-//Semmle//qhelp//EN"
"qhelp.dtd">
<qhelp>
<overview>
<p>Method such as <code>Integer.parseInt</code> that parse strings into numbers
throw
<code>NumberFormatException</code> if the its argument cannot be parsed.
This exception should be caught so that any parse errors can be handled.
</p>
</overview>
<recommendation>
<p>It is usually best to handle <code>NumberFormatException</code> in a <code>catch</code> clause
surrounding the call to the parsing method.</p>
</recommendation>
<example>
<p>In the following example, the first call to <code>Integer.parseInt</code> does not catch the exception.
The second call does.
</p>
<sample src="NumberFormatException.java" />
</example>
<references>
<li>
Java Platform, Standard Edition 6, API Specification:
<a href="http://docs.oracle.com/javase/6/docs/api/java/lang/Integer.html#valueOf(java.lang.String)">Integer.valueOf</a>,
<a href="http://docs.oracle.com/javase/6/docs/api/java/lang/Integer.html#parseInt(java.lang.String)">Integer.parseInt</a>,
<a href="http://docs.oracle.com/javase/6/docs/api/java/lang/Long.html#parseLong(java.lang.String)">Long.parseLong</a>,
<a href="http://docs.oracle.com/javase/6/docs/api/java/lang/NumberFormatException.html">NumberFormatException</a>.
</li>
</references>
</qhelp>

View File

@@ -0,0 +1,88 @@
/**
* @name Missing catch of NumberFormatException
* @description Calling 'Integer.parseInt' without handling 'NumberFormatException'.
* @kind problem
* @problem.severity warning
* @precision high
* @id java/uncaught-number-format-exception
* @tags reliability
* external/cwe/cwe-248
*/
import java
private class SpecialMethodAccess extends MethodAccess {
predicate isValueOfMethod(string klass) {
this.getMethod().getName() = "valueOf" and
this.getQualifier().getType().(RefType).hasQualifiedName("java.lang", klass) and
this.getAnArgument().getType().(RefType).hasQualifiedName("java.lang", "String")
}
predicate isParseMethod(string klass, string name) {
this.getMethod().getName() = name and
this.getQualifier().getType().(RefType).hasQualifiedName("java.lang", klass)
}
predicate throwsNFE() {
this.isParseMethod("Byte", "parseByte") or
this.isParseMethod("Short", "parseShort") or
this.isParseMethod("Integer", "parseInt") or
this.isParseMethod("Long", "parseLong") or
this.isParseMethod("Float", "parseFloat") or
this.isParseMethod("Double", "parseDouble") or
this.isParseMethod("Byte", "decode") or
this.isParseMethod("Short", "decode") or
this.isParseMethod("Integer", "decode") or
this.isParseMethod("Long", "decode") or
this.isValueOfMethod("Byte") or
this.isValueOfMethod("Short") or
this.isValueOfMethod("Integer") or
this.isValueOfMethod("Long") or
this.isValueOfMethod("Float") or
this.isValueOfMethod("Double")
}
}
private class SpecialClassInstanceExpr extends ClassInstanceExpr {
predicate isStringConstructor(string klass) {
cie.getType().(RefType).hasQualifiedName("java.lang", klass) and
cie.getAnArgument().getType().(RefType).hasQualifiedName("java.lang", "String") and
cie.getNumberOfParameters() = 1
}
predicate throwsNFE() {
this.isStringConstructor("Byte") or
this.isStringConstructor("Short") or
this.isStringConstructor("Integer") or
this.isStringConstructor("Long") or
this.isStringConstructor("Float") or
this.isStringConstructor("Double")
}
}
private predicate catchesNFE(TryStmt t) {
exists(CatchClause cc, LocalVariableDeclExpr v |
t.getACatchClause() = cc and
cc.getVariable() = v and
v.getType().(RefType).getASubtype*().hasQualifiedName("java.lang", "NumberFormatException")
)
}
private predicate throwsNFE(Expr e) {
e.(SpecialClassInstanceExpr).throwsNFE() or e.(SpecialMethodAccess).throwsNFE()
}
from Expr e
where
throwsNFE(e) and
not exists(TryStmt t |
t.getBlock() = e.getEnclosingStmt().getParent*() and
catchesNFE(t)
) and
not exists(Callable c |
e.getEnclosingCallable() = c and
c.getAThrownExceptionType().getASubtype*().hasQualifiedName("java.lang", "NumberFormatException")
)
select
e, "Potential uncaught 'java.lang.NumberFormatException'."