Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
a374540
JS: Range analysis library
asger-semmle Sep 12, 2018
73cbdee
JS: Compound assignments and update exprs in range analysis
asger-semmle Sep 19, 2018
09ca665
JS: Support return value of x++
asger-semmle Sep 19, 2018
064b109
JS: range analysis through phi nodes
asger-semmle Sep 20, 2018
6c53ad8
JS: add constant constraints in range analysis
asger-semmle Sep 20, 2018
9d8d953
JS: perform widening when adding operands of very different magnitude
asger-semmle Sep 25, 2018
20aa4e1
JS: handle sharp inequalities directly
asger-semmle Sep 28, 2018
feb8a8c
JS: restrict bias to 30-bit range to avoid overflow
asger-semmle Oct 4, 2018
43df953
JS: be conservative in presence of NaN comments
asger-semmle Oct 23, 2018
d813635
JS: Restrict constraint generation to relevant nodes
asger-semmle Oct 25, 2018
344bec3
JS: Add UselessRangeCheck.ql
asger-semmle Sep 21, 2018
84ea4cf
JS: manually reorder extendedEdge and negativeEdge
asger-semmle Nov 1, 2018
2d6bf0a
JS: improve join ordering in extendedEdge
asger-semmle Nov 1, 2018
5283c6c
JS: only warn about dead code
asger-semmle Nov 6, 2018
4a367d3
JS: more efficient encoding of unary constraints
asger-semmle Nov 9, 2018
f3020f7
JS: avoid extending self-edges
asger-semmle Nov 12, 2018
76a69f4
JS: address review comments
asger-semmle Nov 13, 2018
2870209
JS: fix links in qhelp file
asger-semmle Nov 15, 2018
2e65f6b
JS: address some style comments
asger-semmle Nov 15, 2018
477be26
JS: rename UselessRangeCheck -> UselessComparisonTest
asger-semmle Nov 15, 2018
6d7ac88
JS: add to correctness-more suite
asger-semmle Nov 20, 2018
2c51f86
JS: avoid joining on =0
asger-semmle Nov 21, 2018
8fd3a41
JS: address comments
asger-semmle Nov 28, 2018
d69e584
JS: fix bug in foldedComparisonEdge
asger-semmle Nov 28, 2018
959776b
JS: add test case
asger-semmle Nov 27, 2018
b2a82ae
JS: add 1.20 change note
asger-semmle Nov 15, 2018
d4023fe
JS: address review
asger-semmle Nov 29, 2018
3ed40d5
Merge branch 'master' into range-analysis
Nov 30, 2018
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 4 additions & 3 deletions change-notes/1.20/analysis-javascript.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,10 @@

## New queries

| **Query** | **Tags** | **Purpose** |
|-----------|----------|-------------|
| | | |
| **Query** | **Tags** | **Purpose** |
|-----------------------------------------------|------------------------------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| Useless comparison test | correctness | Highlights code that is unreachable due to a numeric comparison that is always true or always false. |


## Changes to existing queries

Expand Down
1 change: 1 addition & 0 deletions javascript/config/suites/javascript/correctness-more
Original file line number Diff line number Diff line change
Expand Up @@ -15,3 +15,4 @@
+ semmlecode-javascript-queries/Statements/ReturnOutsideFunction.ql: /Correctness/Statements
+ semmlecode-javascript-queries/Statements/SuspiciousUnusedLoopIterationVariable.ql: /Correctness/Statements
+ semmlecode-javascript-queries/Statements/UselessConditional.ql: /Correctness/Statements
+ semmlecode-javascript-queries/Statements/UselessComparisonTest.ql: /Correctness/Statements
47 changes: 47 additions & 0 deletions javascript/ql/src/Statements/UselessComparisonTest.qhelp
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
<!DOCTYPE qhelp PUBLIC
"-//Semmle//qhelp//EN"
"qhelp.dtd">
<qhelp>
<overview>
<p>
If a condition always evaluates to true or always evaluates to false, this often indicates
incomplete code or a latent bug, and it should be examined carefully.
</p>

</overview>
<recommendation>

<p>
Examine the surrounding code to determine why the condition is redundant. If it is no
longer needed, remove it.
</p>

<p>
If the check is needed to guard against <code>NaN</code> values, insert a comment explaning the possibility of <code>NaN</code>.
</p>

</recommendation>
<example>

<p>
The following example finds the index of an element in a given slice of the array:
</p>

<sample src="examples/UselessComparisonTest.js" />

<p>
The condition <code>i &lt; end</code> at the end is always false, however. The code can be clarified if the
redundant condition is removed:
</p>

<sample src="examples/UselessComparisonTestGood.js" />

</example>
<references>


<li>Mozilla Developer Network: <a href="https://developer.mozilla.org/en-US/docs/Glossary/Truthy">Truthy</a>,
<a href="https://developer.mozilla.org/en-US/docs/Glossary/Falsy">Falsy</a>.</li>

</references>
</qhelp>
60 changes: 60 additions & 0 deletions javascript/ql/src/Statements/UselessComparisonTest.ql
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
/**
* @name Useless comparison test
* @description A comparison that always evaluates to true or always evaluates to false may
* indicate faulty logic and dead code.
* @kind problem
* @problem.severity warning
* @id js/useless-comparison-test
* @tags correctness
* @precision high
*/

import javascript

/**
* Holds if there are any contradictory guard nodes in `container`.
*
* We use this to restrict reachability analysis to a small set of containers.
*/
predicate hasContradictoryGuardNodes(StmtContainer container) {
exists (ConditionGuardNode guard |
RangeAnalysis::isContradictoryGuardNode(guard) and
container = guard.getContainer())
}

/**
* Holds if `block` is reachable and is in a container with contradictory guard nodes.
*/
predicate isReachable(BasicBlock block) {
exists (StmtContainer container |
hasContradictoryGuardNodes(container) and
block = container.getEntryBB())
or
isReachable(block.getAPredecessor()) and
not RangeAnalysis::isContradictoryGuardNode(block.getANode())
}

/**
* Holds if `block` is unreachable, but could be reached if `guard` was not contradictory.
*/
predicate isBlockedByContradictoryGuardNodes(BasicBlock block, ConditionGuardNode guard) {
RangeAnalysis::isContradictoryGuardNode(guard) and
isReachable(block.getAPredecessor()) and // the guard itself is reachable
block = guard.getBasicBlock()
or
isBlockedByContradictoryGuardNodes(block.getAPredecessor(), guard) and
not isReachable(block)
}

/**
* Holds if the given guard node is contradictory and causes an expression or statement to be unreachable.
*/
predicate isGuardNodeWithDeadCode(ConditionGuardNode guard) {
exists (BasicBlock block |
isBlockedByContradictoryGuardNodes(block, guard) and
block.getANode() instanceof ExprOrStmt)
}

from ConditionGuardNode guard
where isGuardNodeWithDeadCode(guard)
select guard.getTest(), "The condition '" + guard.getTest() + "' is always " + guard.getOutcome().booleanNot() + "."
12 changes: 12 additions & 0 deletions javascript/ql/src/Statements/examples/UselessComparisonTest.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
function findValue(values, x, start, end) {
let i;
for (i = start; i < end; ++i) {
if (values[i] === x) {
return i;
}
}
if (i < end) {
return i;
}
return -1;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
function findValue(values, x, start, end) {
for (let i = start; i < end; ++i) {
if (values[i] === x) {
return i;
}
}
return -1;
}
1 change: 1 addition & 0 deletions javascript/ql/src/javascript.qll
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ import semmle.javascript.NPM
import semmle.javascript.Paths
import semmle.javascript.Promises
import semmle.javascript.CanonicalNames
import semmle.javascript.RangeAnalysis
import semmle.javascript.Regexp
import semmle.javascript.SSA
import semmle.javascript.StandardLibrary
Expand Down
Loading