mirror of
https://github.com/github/codeql.git
synced 2026-04-29 10:45:15 +02:00
Merge pull request #2116 from erik-krogh/arrayCBRet
Approved by max-schaefer
This commit is contained in:
@@ -82,17 +82,87 @@ predicate alwaysThrows(Function f) {
|
||||
)
|
||||
}
|
||||
|
||||
from DataFlow::CallNode call
|
||||
where
|
||||
not call.isIndefinite(_) and
|
||||
forex(Function f | f = call.getACallee() |
|
||||
/**
|
||||
* Holds if the last statement in the function is flagged by the js/useless-expression query.
|
||||
*/
|
||||
predicate lastStatementHasNoEffect(Function f) {
|
||||
hasNoEffect(f.getExit().getAPredecessor())
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `func` is a callee of `call`, and all possible callees of `call` never return a value.
|
||||
*/
|
||||
predicate callToVoidFunction(DataFlow::CallNode call, Function func) {
|
||||
not call.isIncomplete() and
|
||||
func = call.getACallee() and
|
||||
forall(Function f | f = call.getACallee() |
|
||||
returnsVoid(f) and not isStub(f) and not alwaysThrows(f)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `name` is the name of a method from `Array.prototype` or Lodash,
|
||||
* where that method takes a callback as parameter,
|
||||
* and the callback is expected to return a value.
|
||||
*/
|
||||
predicate hasNonVoidCallbackMethod(string name) {
|
||||
name = "every" or
|
||||
name = "filter" or
|
||||
name = "find" or
|
||||
name = "findIndex" or
|
||||
name = "flatMap" or
|
||||
name = "map" or
|
||||
name = "reduce" or
|
||||
name = "reduceRight" or
|
||||
name = "some" or
|
||||
name = "sort"
|
||||
}
|
||||
|
||||
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()) }
|
||||
|
||||
/**
|
||||
* Holds if `call` is an Array or Lodash method accepting a callback `func`,
|
||||
* where the `call` expects a callback that returns an expression,
|
||||
* but `func` does not return a value.
|
||||
*/
|
||||
predicate voidArrayCallback(DataFlow::CallNode call, Function func) {
|
||||
hasNonVoidCallbackMethod(call.getCalleeName()) and
|
||||
exists(int index |
|
||||
index = min(int i | exists(call.getCallback(i))) and
|
||||
func = call.getCallback(index).getFunction()
|
||||
) and
|
||||
returnsVoid(func) and
|
||||
not isStub(func) and
|
||||
not alwaysThrows(func) and
|
||||
(
|
||||
call.getReceiver().getALocalSource() = array()
|
||||
or
|
||||
call.getCalleeNode().getALocalSource() instanceof LodashUnderscore::Member
|
||||
)
|
||||
}
|
||||
|
||||
from DataFlow::CallNode call, Function func, string name, string msg
|
||||
where
|
||||
(
|
||||
callToVoidFunction(call, func) and
|
||||
msg = "the $@ does not return anything, yet the return value is used." and
|
||||
name = func.describe()
|
||||
or
|
||||
voidArrayCallback(call, func) and
|
||||
msg = "the $@ does not return anything, yet the return value from the call to " + call.getCalleeName() + " is used." and
|
||||
name = "callback function"
|
||||
) and
|
||||
|
||||
not benignContext(call.asExpr()) and
|
||||
|
||||
not lastStatementHasNoEffect(func) and
|
||||
// anonymous one-shot closure. Those are used in weird ways and we ignore them.
|
||||
not oneshotClosure(call.asExpr())
|
||||
select
|
||||
call, "the function $@ does not return anything, yet the return value is used.", call.getACallee(), call.getCalleeName()
|
||||
|
||||
call, msg, func, name
|
||||
|
||||
Reference in New Issue
Block a user