mirror of
https://github.com/github/codeql.git
synced 2026-04-20 22:44:52 +02:00
Query for uncaught NumberFormatException
This commit is contained in:
@@ -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
|
||||
}
|
||||
@@ -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>
|
||||
@@ -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'."
|
||||
|
||||
|
||||
Reference in New Issue
Block a user