Java: Add new query for large left shifts and bugfix ConstantExpAppearsNonConstant.

This commit is contained in:
Anders Schack-Mulligen
2020-01-23 15:33:49 +01:00
parent 8c00671f24
commit 4cb28d9b1d
12 changed files with 156 additions and 55 deletions

View File

@@ -14,10 +14,6 @@ Some expressions always evaluate to the same result, no matter what their subexp
</li>
<li><code>x % 1</code> always evaluates to <code>0</code>.
</li>
<li><code>x &lt;&lt; 64</code> (when <code>x</code> is of type <code>long</code>) always evaluates to <code>0</code>.
</li>
<li><code>x &lt;&lt; 32</code> (when <code>x</code> is not of type <code>long</code>) always evaluates to <code>0</code>.
</li>
<li><code>x &amp; 0</code> always evaluates to <code>0</code>.
</li>
<li><code>x || true</code> always evaluates to <code>true</code>.
@@ -58,7 +54,7 @@ an integer. The correct check is <code>x % 2 == 0</code>.
<li>
The Java Language Specification:
<a href="http://docs.oracle.com/javase/specs/jls/se7/html/jls-15.html#jls-15.17.1">Multiplication operator *</a>, <a href="http://docs.oracle.com/javase/specs/jls/se7/html/jls-15.html#jls-15.17.3">Remainder operator %</a>, <a href="http://docs.oracle.com/javase/specs/jls/se7/html/jls-15.html#jls-15.19">Left shift operator &lt;&lt;</a>, <a href="http://docs.oracle.com/javase/specs/jls/se7/html/jls-15.html#jls-15.22.1">Bitwise AND operator &amp;</a>, <a href="http://docs.oracle.com/javase/specs/jls/se7/html/jls-15.html#jls-15.23">Conditional-and operator &amp;&amp;</a> and <a href="http://docs.oracle.com/javase/specs/jls/se7/html/jls-15.html#jls-15.24">Conditional-or operator ||</a>.
<a href="http://docs.oracle.com/javase/specs/jls/se7/html/jls-15.html#jls-15.17.1">Multiplication operator *</a>, <a href="http://docs.oracle.com/javase/specs/jls/se7/html/jls-15.html#jls-15.17.3">Remainder operator %</a>, <a href="http://docs.oracle.com/javase/specs/jls/se7/html/jls-15.html#jls-15.22.1">Bitwise AND operator &amp;</a>, <a href="http://docs.oracle.com/javase/specs/jls/se7/html/jls-15.html#jls-15.23">Conditional-and operator &amp;&amp;</a> and <a href="http://docs.oracle.com/javase/specs/jls/se7/html/jls-15.html#jls-15.24">Conditional-or operator ||</a>.
</li>

View File

@@ -11,10 +11,6 @@
import java
int integralTypeWidth(IntegralType t) {
if t.hasName("long") or t.hasName("Long") then result = 64 else result = 32
}
int eval(Expr e) { result = e.(CompileTimeConstantExpr).getIntValue() }
predicate isConstantExp(Expr e) {
@@ -48,13 +44,6 @@ predicate isConstantExp(Expr e) {
eval(r.getRightOperand().getProperExpr()) = 1
)
or
// Left shift by 64 (longs) or 32 (all other integer types) is constant.
exists(LShiftExpr s | s = e |
exists(IntegralType t | t = s.getLeftOperand().getType() |
eval(s.getRightOperand().getProperExpr()) = integralTypeWidth(t)
)
)
or
exists(AndBitwiseExpr a | a = e | eval(a.getAnOperand().getProperExpr()) = 0)
or
exists(AndLogicalExpr a | a = e |

View File

@@ -0,0 +1 @@
long longVal = intVal << 32; // BAD

View File

@@ -0,0 +1,47 @@
<!DOCTYPE qhelp PUBLIC
"-//Semmle//qhelp//EN"
"qhelp.dtd">
<qhelp>
<overview>
<p>
The left shift operator only uses the lowest 5 bits of its right-hand side
when the promoted type of its left-hand side is <code>int</code> and the
lowest 6 bits when the type is <code>long</code>.
</p>
</overview>
<recommendation>
<p>
Restrict the shift amount of <code>int</code>s to the range 0-31, or cast to <code>long</code> before left-shifting.
</p>
</recommendation>
<example>
<p>
The following line tries to left-shift an <code>int</code> 32 bits.
</p>
<sample src="LShiftLargerThanTypeWidth.java" />
<p>
However, left-shifting an <code>int</code> 32 bits is equivalent to
left-shifting 0 bits, that is, not shifting at all. Instead the value should
be cast to <code>long</code> before shifting to actually left-shift 32 bits.
</p>
<sample src="LShiftLargerThanTypeWidthGood.java" />
</example>
<references>
<li>
The Java Language Specification:
<a href="https://docs.oracle.com/javase/specs/jls/se7/html/jls-15.html#jls-15.19">Shift Operators</a>.
</li>
</references>
</qhelp>

View File

@@ -0,0 +1,26 @@
/**
* @name Left shift by more than the type width
* @description Left-shifting an integer by more than its type width indicates a mistake.
* @kind problem
* @problem.severity warning
* @precision very-high
* @id java/lshift-larger-than-type-width
* @tags correctness
*/
import java
int integralTypeWidth(IntegralType t) {
if t.hasName("long") or t.hasName("Long") then result = 64 else result = 32
}
from LShiftExpr shift, IntegralType t, int v, string typname, int width
where
shift.getLeftOperand().getType() = t and
shift.getRightOperand().(CompileTimeConstantExpr).getIntValue() = v and
width = integralTypeWidth(t) and
v >= width and
typname = ("a " + t.toString()).regexpReplaceAll("a ([aeiouAEIOU])", "an $1")
select shift,
"Left-shifting " + typname + " by more than " + width + " truncates the shift amount from " + v +
" to " + (v % width)

View File

@@ -0,0 +1 @@
long longVal = ((long)intVal) << 32; // GOOD