Merge pull request #351 from nystrom/master

Approved by pavgust
This commit is contained in:
semmle-qlci
2018-10-26 19:09:02 +01:00
committed by GitHub
7 changed files with 312 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>Methods such as <code>Integer.parseInt</code> that parse strings into numbers
throw
<code>NumberFormatException</code> if their arguments 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 8, API Specification:
<a href="https://docs.oracle.com/javase/8/docs/api/java/lang/Integer.html#valueOf-java.lang.String-">Integer.valueOf</a>,
<a href="https://docs.oracle.com/javase/8/docs/api/java/lang/Integer.html#parseInt-java.lang.String-">Integer.parseInt</a>,
<a href="https://docs.oracle.com/javase/8/docs/api/java/lang/Long.html#parseLong-java.lang.String-">Long.parseLong</a>,
<a href="https://docs.oracle.com/javase/8/docs/api/java/lang/NumberFormatException.html">NumberFormatException</a>.
</li>
</references>
</qhelp>

View File

@@ -0,0 +1,91 @@
/**
* @name Missing catch of NumberFormatException
* @description Calling a string to number conversion method without handling
* 'NumberFormatException' may cause unexpected runtime exceptions.
* @kind problem
* @problem.severity recommendation
* @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) {
this.getType().(RefType).hasQualifiedName("java.lang", klass) and
this.getAnArgument().getType().(RefType).hasQualifiedName("java.lang", "String") and
this.getNumArgument() = 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")
}
}
class NumberFormatException extends RefType {
NumberFormatException() { this.hasQualifiedName("java.lang", "NumberFormatException") }
}
private predicate catchesNFE(TryStmt t) {
exists(CatchClause cc, LocalVariableDeclExpr v |
t.getACatchClause() = cc and
cc.getVariable() = v and
v.getType().(RefType).getASubtype*() instanceof 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*() instanceof NumberFormatException
)
select e, "Potential uncaught 'java.lang.NumberFormatException'."