introduce backtracking, and also marking join/slice calls

This commit is contained in:
Erik Krogh Kristensen
2019-10-25 15:45:35 +02:00
parent 5489a80372
commit 5b26d03f1c
8 changed files with 55 additions and 48 deletions

View File

@@ -4,16 +4,18 @@
<qhelp>
<overview>
<p>
The <code>concat</code> method on is pure and does not modify any of the input
arrays. It is therefore generally an error to ignore the return value from a
call to <code>concat</code>.
The <code>concat</code>, <code>join</code> and <code>slice</code> methods are
pure and does not modify any of the inputs or the array the method was called
on. It is therefore generally an error to ignore the return value from a call
to one of these methods.
</p>
</overview>
<recommendation>
<p>
Use the returned value from the call to <code>concat</code>.
Use the returned value from the calls to <code>concat</code>, <code>join</code>
or <code>slice</code>.
</p>
</recommendation>
@@ -26,19 +28,21 @@ function uses the <code>concat</code> method to add elements to the
effect as the return value from <code>concat</code> is ignored.
</p>
<sample src="examples/IgnoreConcat.js" />
<sample src="examples/IgnoreArrayResult.js" />
<p>
Assigning the returned value from the call to <code>concat</code> to the
<code>arr</code> variable fixes the error.
</p>
<sample src="examples/IgnoreConcatFixed.js" />
<sample src="examples/IgnoreArrayResultFixed.js" />
</example>
<references>
<li>Mozilla Developer Network: <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/concat">Array concat</a>.</li>
<li>Mozilla Developer Network: <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/slice">Array slice</a>.</li>
<li>Mozilla Developer Network: <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/join">Array join</a>.</li>
</references>
</qhelp>

View File

@@ -0,0 +1,45 @@
/**
* @name Ignoring result from pure array method
* @description The array methods do not modify the array, ignoring the result of such a call is therefore generally an error.
* @kind problem
* @problem.severity warning
* @id js/ignore-array-result
* @tags maintainability,
* correctness
* @precision high
*/
import javascript
import Expressions.ExprHasNoEffect
DataFlow::SourceNode callsArray(DataFlow::TypeBackTracker t, DataFlow::MethodCallNode call) {
isIgnoredPureArrayCall(call) and
(
t.start() and
result = call.getReceiver()
or
exists(DataFlow::TypeBackTracker t2 | result = callsArray(t2, call).backtrack(t2, t))
)
}
DataFlow::SourceNode callsArray(DataFlow::MethodCallNode call) {
result = callsArray(DataFlow::TypeBackTracker::end(), call)
}
predicate isIgnoredPureArrayCall(DataFlow::MethodCallNode call) {
inVoidContext(call.asExpr()) and
(
call.getMethodName() = "concat" and
call.getNumArgument() = 1
or
call.getMethodName() = "join" and
call.getNumArgument() < 2
or
call.getMethodName() = "slice" and
call.getNumArgument() < 3
)
}
from DataFlow::MethodCallNode call
where callsArray(call) instanceof DataFlow::ArrayCreationNode
select call, "Result from call to " + call.getMethodName() + " ignored."

View File

@@ -1,42 +0,0 @@
/**
* @name Ignoring return from concat
* @description The concat method does not modify an array, ignoring the result of a call to concat is therefore generally an error.
* @kind problem
* @problem.severity warning
* @id js/ignore-result-from-concat
* @tags maintainability,
* correctness
* @precision high
*/
import javascript
import Expressions.ExprHasNoEffect
DataFlow::SourceNode array(DataFlow::TypeTracker t) {
t.start() and
result instanceof DataFlow::ArrayCreationNode
or
exists (DataFlow::TypeTracker t2 |
result = array(t2).track(t2, t)
)
}
DataFlow::SourceNode array() { result = array(DataFlow::TypeTracker::end()) }
predicate isArrayMethod(DataFlow::MethodCallNode call) {
call.getReceiver().getALocalSource() = array()
}
predicate isIncomplete(DataFlow::Node node) {
any(DataFlow::Incompleteness cause | node.analyze().getAValue().isIndefinite(cause)) != "global"
}
from DataFlow::CallNode call
where
isArrayMethod(call) and
call.getCalleeName() = "concat" and
call.getNumArgument() = 1 and
(call.getArgument(0).getALocalSource() = array() or isIncomplete(call.getArgument(0))) and
not call.getArgument(0).asExpr().(ArrayExpr).getSize() = 0 and
inVoidContext(call.asExpr())
select call, "Return value from call to concat ignored."