mirror of
https://github.com/github/codeql.git
synced 2026-04-29 18:55:14 +02:00
Merge pull request #900 from esben-semmle/js/defuse-default
Approved by xiemaisi
This commit is contained in:
@@ -19,7 +19,7 @@ import DeadStore
|
||||
*/
|
||||
predicate deadStoreOfLocal(VarDef vd, PurelyLocalVariable v) {
|
||||
v = vd.getAVariable() and
|
||||
exists(vd.getSource()) and
|
||||
(exists(vd.getSource()) or exists(vd.getDestructuringSource())) and
|
||||
// the definition is not in dead code
|
||||
exists(ReachableBasicBlock rbb | vd = rbb.getANode()) and
|
||||
// but it has no associated SSA definition, that is, it is dead
|
||||
|
||||
@@ -12,6 +12,7 @@ import javascript
|
||||
* <tr><td><code>x = y</code><td><code>x = y</code><td><code>x</code><td><code>y</code></tr>
|
||||
* <tr><td><code>var a = b</code><td><code>var a = b</code><td><code>a</code><td><code>b</code></tr>
|
||||
* <tr><td><code>function f { ... }</code><td><code>f</code><td><code>f</code><td><code>function f { ... }</code></tr>
|
||||
* <tr><td><code>function f ( x = y ){ ... }</code><td><code>x</code><td><code>x</code><td><code>y</code></tr>
|
||||
* <tr><td><code>class C { ... }</code><td><code>C</code><td><code>C</code><td><code>class C { ... }</code></tr>
|
||||
* <tr><td><code>namespace N { ... }</code><td><code>N</code><td><code>N</code><td><code>namespace N { ... }</code></tr>
|
||||
* <tr><td><code>enum E { ... }</code><td><code>E</code><td><code>E</code><td><code>enum E { ... }</code></tr>
|
||||
@@ -42,6 +43,8 @@ private predicate defn(ControlFlowNode def, Expr lhs, AST::ValueNode rhs) {
|
||||
exists(EnumMember member | def = member.getIdentifier() |
|
||||
lhs = def and rhs = member.getInitializer()
|
||||
)
|
||||
or
|
||||
lhs = def and def.(Parameter).getDefault() = rhs
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -187,9 +190,23 @@ class VarDef extends ControlFlowNode {
|
||||
* the value that this definition assigns to its target.
|
||||
*
|
||||
* This predicate is not defined for `VarDef`s where the source is implicit,
|
||||
* such as `for-in` loops or parameters.
|
||||
* such as `for-in` loops, parameters or destructuring assignments.
|
||||
*/
|
||||
AST::ValueNode getSource() { defn(this, _, result) }
|
||||
AST::ValueNode getSource() {
|
||||
exists(Expr target |
|
||||
not target instanceof DestructuringPattern and defn(this, target, result)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the source that this definition destructs, that is, the
|
||||
* right hand side of a destructuring assignment.
|
||||
*/
|
||||
AST::ValueNode getDestructuringSource() {
|
||||
exists(Expr target |
|
||||
target instanceof DestructuringPattern and defn(this, target, result)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if this definition of `v` is overwritten by another definition, that is,
|
||||
|
||||
@@ -104,7 +104,12 @@ module RangeAnalysis {
|
||||
pragma[noinline]
|
||||
private predicate hasUniquePredecessor(DataFlow::Node node) {
|
||||
isRelevant(node) and
|
||||
strictcount(node.getAPredecessor()) = 1
|
||||
strictcount(node.getAPredecessor()) = 1 and
|
||||
// exclude parameters with default values
|
||||
not exists (Parameter p |
|
||||
DataFlow::parameterNode(p) = node and
|
||||
exists(p.getDefault())
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -992,7 +992,9 @@ module DataFlow {
|
||||
* flow through IIFE calls into account.
|
||||
*/
|
||||
private AST::ValueNode defSourceNode(VarDef def) {
|
||||
result = def.getSource() or localArgumentPassing(result, def)
|
||||
result = def.getSource() or
|
||||
result = def.getDestructuringSource() or
|
||||
localArgumentPassing(result, def)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1002,15 +1004,19 @@ module DataFlow {
|
||||
private Node defSourceNode(VarDef def, SsaSourceVariable v) {
|
||||
exists(BindingPattern lhs, VarRef r |
|
||||
lhs = def.getTarget() and r = lhs.getABindingVarRef() and r.getVariable() = v
|
||||
|
|
||||
|
|
||||
// follow one step of the def-use chain if the lhs is a simple variable reference
|
||||
lhs = r and
|
||||
result = TValueNode(defSourceNode(def))
|
||||
or
|
||||
// handle destructuring assignments
|
||||
exists(PropertyPattern pp | r = pp.getValuePattern() | result = TPropNode(pp))
|
||||
exists(PropertyPattern pp | r = pp.getValuePattern() |
|
||||
result = TPropNode(pp) or result = pp.getDefault().flow()
|
||||
)
|
||||
or
|
||||
result = TElementPatternNode(_, r)
|
||||
or
|
||||
exists(ArrayPattern ap, int i | ap.getElement(i) = r and result = ap.getDefault(i).flow())
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -53,9 +53,7 @@ private class SsaVarAccessWithNonLocalAnalysis extends SsaVarAccessAnalysis {
|
||||
exists(VarDef varDef |
|
||||
varDef = def.(SsaExplicitDefinition).getDef() and
|
||||
varDef.getSource().flow() = src and
|
||||
src instanceof CallWithNonLocalAnalyzedReturnFlow and
|
||||
// avoid relating `v` and `f()` in `var {v} = f();`
|
||||
not varDef.getTarget() instanceof DestructuringPattern
|
||||
src instanceof CallWithNonLocalAnalyzedReturnFlow
|
||||
)
|
||||
}
|
||||
|
||||
@@ -145,7 +143,7 @@ private class AnalyzedParameter extends AnalyzedVarDef, @vardecl {
|
||||
|
||||
override DataFlow::AnalyzedNode getRhs() {
|
||||
getFunction().argumentPassing(this, result.asExpr()) or
|
||||
result = this.(Parameter).getDefault().analyze()
|
||||
result = AnalyzedVarDef.super.getRhs()
|
||||
}
|
||||
|
||||
override AbstractValue getAnRhsValue() {
|
||||
|
||||
Reference in New Issue
Block a user