зеркало из https://github.com/github/codeql.git
Merge pull request #3627 from asger-semmle/js/unneeded-defensive-return
Approved by erik-krogh
This commit is contained in:
Коммит
cf0cd00458
|
@ -63,6 +63,7 @@
|
||||||
| Uncontrolled command line (`js/command-line-injection`) | More results | This query now recognizes additional command execution calls. |
|
| Uncontrolled command line (`js/command-line-injection`) | More results | This query now recognizes additional command execution calls. |
|
||||||
| Uncontrolled data used in path expression (`js/path-injection`) | More results | This query now recognizes additional file system calls. |
|
| Uncontrolled data used in path expression (`js/path-injection`) | More results | This query now recognizes additional file system calls. |
|
||||||
| Unknown directive (`js/unknown-directive`) | Fewer results | This query no longer flags directives generated by the Babel compiler. |
|
| Unknown directive (`js/unknown-directive`) | Fewer results | This query no longer flags directives generated by the Babel compiler. |
|
||||||
|
| Unneeded defensive code (`js/unneeded-defensive-code`) | Fewer false-positive results | This query now recognizes checks meant to handle the `document.all` object. |
|
||||||
| Unused property (`js/unused-property`) | Fewer results | This query no longer flags properties of objects that are operands of `yield` expressions. |
|
| Unused property (`js/unused-property`) | Fewer results | This query no longer flags properties of objects that are operands of `yield` expressions. |
|
||||||
| Zip Slip (`js/zipslip`) | More results | This query now recognizes additional vulnerabilities. |
|
| Zip Slip (`js/zipslip`) | More results | This query now recognizes additional vulnerabilities. |
|
||||||
|
|
||||||
|
|
|
@ -13,19 +13,43 @@
|
||||||
import javascript
|
import javascript
|
||||||
import semmle.javascript.DefensiveProgramming
|
import semmle.javascript.DefensiveProgramming
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Holds if `e` looks like a check for `document.all`, which is an unusual browser object which coerces
|
||||||
|
* to `false` and has typeof `undefined`.
|
||||||
|
*/
|
||||||
|
predicate isFalsyObjectCheck(LogicalBinaryExpr e) {
|
||||||
|
exists(Variable v |
|
||||||
|
e.getAnOperand().(DefensiveExpressionTest::TypeofUndefinedTest).getOperand() = v.getAnAccess() and
|
||||||
|
e.getAnOperand().(DefensiveExpressionTest::UndefinedComparison).getOperand() = v.getAnAccess()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Holds if `e` is part of a check for `document.all`.
|
||||||
|
*/
|
||||||
|
predicate isPartOfFalsyObjectCheck(Expr e) {
|
||||||
|
exists(LogicalBinaryExpr binary |
|
||||||
|
isFalsyObjectCheck(binary) and
|
||||||
|
e = binary.getAnOperand()
|
||||||
|
)
|
||||||
|
or
|
||||||
|
isFalsyObjectCheck(e)
|
||||||
|
}
|
||||||
|
|
||||||
from DefensiveExpressionTest e, boolean cv
|
from DefensiveExpressionTest e, boolean cv
|
||||||
where
|
where
|
||||||
|
not isPartOfFalsyObjectCheck(e.asExpr()) and
|
||||||
e.getTheTestResult() = cv and
|
e.getTheTestResult() = cv and
|
||||||
// whitelist
|
// whitelist
|
||||||
not (
|
not (
|
||||||
// module environment detection
|
// module environment detection
|
||||||
exists(VarAccess access, string name | name = "exports" or name = "module" |
|
exists(VarAccess access, string name | name = "exports" or name = "module" |
|
||||||
e.asExpr().(Internal::TypeofUndefinedTest).getOperand() = access and
|
e.asExpr().(DefensiveExpressionTest::TypeofUndefinedTest).getOperand() = access and
|
||||||
access.getName() = name and
|
access.getName() = name and
|
||||||
not exists(access.getVariable().getADeclaration())
|
not exists(access.getVariable().getADeclaration())
|
||||||
)
|
)
|
||||||
or
|
or
|
||||||
// too benign in practice
|
// too benign in practice
|
||||||
e instanceof Internal::DefensiveInit
|
e instanceof DefensiveExpressionTest::DefensiveInit
|
||||||
)
|
)
|
||||||
select e, "This guard always evaluates to " + cv + "."
|
select e, "This guard always evaluates to " + cv + "."
|
||||||
|
|
|
@ -14,9 +14,9 @@ abstract class DefensiveExpressionTest extends DataFlow::ValueNode {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* INTERNAL: Do not use directly; use `DefensiveExpressionTest` instead.
|
* Provides classes for specific kinds of defensive programming patterns.
|
||||||
*/
|
*/
|
||||||
module Internal {
|
module DefensiveExpressionTest {
|
||||||
/**
|
/**
|
||||||
* A defensive truthiness check that may be worth keeping, even if it
|
* A defensive truthiness check that may be worth keeping, even if it
|
||||||
* is strictly speaking useless.
|
* is strictly speaking useless.
|
||||||
|
@ -187,6 +187,13 @@ module Internal {
|
||||||
override Expr getOperand() { result = operand }
|
override Expr getOperand() { result = operand }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Comparison against `undefined`, such as `x === undefined`.
|
||||||
|
*/
|
||||||
|
class UndefinedComparison extends NullUndefinedComparison {
|
||||||
|
UndefinedComparison() { op2type = TTUndefined() }
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An expression that throws an exception if one of its subexpressions evaluates to `null` or `undefined`.
|
* An expression that throws an exception if one of its subexpressions evaluates to `null` or `undefined`.
|
||||||
*
|
*
|
||||||
|
@ -380,7 +387,7 @@ module Internal {
|
||||||
/**
|
/**
|
||||||
* A test for `undefined` using a `typeof` expression.
|
* A test for `undefined` using a `typeof` expression.
|
||||||
*
|
*
|
||||||
* Example: `typeof x === undefined'.
|
* Example: `typeof x === "undefined"'.
|
||||||
*/
|
*/
|
||||||
class TypeofUndefinedTest extends UndefinedNullTest {
|
class TypeofUndefinedTest extends UndefinedNullTest {
|
||||||
TypeofTest test;
|
TypeofTest test;
|
||||||
|
|
|
@ -1,4 +1,6 @@
|
||||||
| module-environment-detection.js:23:8:23:36 | typeof ... efined' | This guard always evaluates to true. |
|
| module-environment-detection.js:23:8:23:36 | typeof ... efined' | This guard always evaluates to true. |
|
||||||
|
| regression.js:9:9:9:12 | date | This guard always evaluates to true. |
|
||||||
|
| regression.js:13:25:13:40 | obj != undefined | This guard always evaluates to true. |
|
||||||
| tst2.js:4:12:4:35 | typeof ... efined" | This guard always evaluates to true. |
|
| tst2.js:4:12:4:35 | typeof ... efined" | This guard always evaluates to true. |
|
||||||
| tst.js:18:5:18:5 | u | This guard always evaluates to false. |
|
| tst.js:18:5:18:5 | u | This guard always evaluates to false. |
|
||||||
| tst.js:19:5:19:5 | n | This guard always evaluates to false. |
|
| tst.js:19:5:19:5 | n | This guard always evaluates to false. |
|
||||||
|
|
|
@ -0,0 +1,15 @@
|
||||||
|
function getDate() {
|
||||||
|
var date;
|
||||||
|
if (something()) {
|
||||||
|
date = new Date();
|
||||||
|
} else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
console.log(date);
|
||||||
|
return date && date.getTime(); // NOT OK
|
||||||
|
}
|
||||||
|
|
||||||
|
function isNotNullOrString(obj) {
|
||||||
|
return obj != null && obj != undefined && // NOT OK
|
||||||
|
typeof obj != 'string';
|
||||||
|
}
|
|
@ -8,3 +8,11 @@
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const isFalsyObject = (v) => typeof v === 'undefined' && v !== undefined; // OK
|
||||||
|
|
||||||
|
function f(v) {
|
||||||
|
if (typeof v === 'undefined' && v !== undefined) { // OK
|
||||||
|
doSomething(v);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
Загрузка…
Ссылка в новой задаче