Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 2c62337

Browse files
authored
Merge pull request #2405 from esbena/js/another-bind-model
Approved by asgerf
2 parents dbe885f + 23d29a8 commit 2c62337

3 files changed

Lines changed: 50 additions & 27 deletions

File tree

change-notes/1.24/analysis-javascript.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
| **Query** | **Expected impact** | **Change** |
1515
|--------------------------------|------------------------------|---------------------------------------------------------------------------|
1616
| Clear-text logging of sensitive information (`js/clear-text-logging`) | More results | More results involving `process.env` and indirect calls to logging methods are recognized. |
17+
| Unbound event handler receiver (`js/unbound-event-handler-receiver`) | Fewer false positive results | This query now recognizes additional ways event handler receivers can be bound. |
1718

1819
## Changes to libraries
1920

javascript/ql/src/Expressions/UnboundEventHandlerReceiver.ql

Lines changed: 31 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -14,47 +14,51 @@ import javascript
1414
* Holds if the receiver of `method` is bound.
1515
*/
1616
private predicate isBoundInMethod(MethodDeclaration method) {
17-
exists(DataFlow::ThisNode thiz, MethodDeclaration bindingMethod |
17+
exists(DataFlow::ThisNode thiz, MethodDeclaration bindingMethod, string name |
1818
bindingMethod.getDeclaringClass() = method.getDeclaringClass() and
1919
not bindingMethod.isStatic() and
20-
thiz.getBinder().getAstNode() = bindingMethod.getBody()
20+
thiz.getBinder().getAstNode() = bindingMethod.getBody() and
21+
name = method.getName()
2122
|
23+
// binding assignments: `this[x] = <expr>.bind(...)`
2224
exists(DataFlow::MethodCallNode bind, DataFlow::PropWrite w |
23-
// this[x] = <expr>.bind(...)
25+
not exists(w.getPropertyName()) or // unknown name, assume everything is bound
26+
w.getPropertyName() = name
27+
|
2428
w = thiz.getAPropertyWrite() and
25-
not exists(w.getPropertyName()) and
2629
bind.getMethodName() = "bind" and
2730
bind.flowsTo(w.getRhs())
2831
)
2932
or
30-
// require("auto-bind")(this)
33+
// library binders
3134
exists(string mod |
3235
mod = "auto-bind" or
3336
mod = "react-autobind"
3437
|
3538
thiz.flowsTo(DataFlow::moduleImport(mod).getACall().getArgument(0))
36-
)
37-
or
38-
exists(string name | name = method.getName() |
39-
exists(DataFlow::MethodCallNode bind |
40-
// this.<methodName> = <expr>.bind(...)
41-
bind = thiz.getAPropertySource(name) and
42-
bind.getMethodName() = "bind"
43-
)
39+
) or
40+
// heuristic reflective binders
41+
exists(DataFlow::CallNode binder, string calleeName |
42+
(
43+
binder.(DataFlow::MethodCallNode).getMethodName() = calleeName or
44+
binder.getCalleeNode().asExpr().(VarAccess).getVariable().getName() = calleeName
45+
) and
46+
calleeName.regexpMatch("(?i).*bind.*") and
47+
thiz.flowsTo(binder.getAnArgument()) and
48+
// exclude the binding assignments
49+
not thiz.getAPropertySource() = binder
50+
|
51+
// `myBindAll(this)`
52+
binder.getNumArgument() = 1
4453
or
45-
exists(DataFlow::MethodCallNode bindAll |
46-
bindAll.getMethodName() = "bindAll" and
47-
thiz.flowsTo(bindAll.getArgument(0))
48-
|
49-
// _.bindAll(this, <name1>)
50-
bindAll.getArgument(1).mayHaveStringValue(name)
51-
or
52-
// _.bindAll(this, [<name1>, <name2>])
53-
exists(DataFlow::ArrayCreationNode names |
54-
names.flowsTo(bindAll.getArgument(1)) and
55-
names.getAnElement().mayHaveStringValue(name)
56-
)
54+
// `myBindSome(this, [<name1>, <name2>])`
55+
exists(DataFlow::ArrayCreationNode names |
56+
names.flowsTo(binder.getAnArgument()) and
57+
names.getAnElement().mayHaveStringValue(name)
5758
)
59+
or
60+
// `myBindSome(this, <name1>, <name2>)`
61+
binder.getAnArgument().mayHaveStringValue(name)
5862
)
5963
)
6064
or
@@ -66,10 +70,10 @@ private predicate isBoundInMethod(MethodDeclaration method) {
6670
) and
6771
name.regexpMatch("(?i).*(bind|bound).*")
6872
|
69-
// @autobind
73+
// `@autobind`
7074
decoration.(Identifier).getName() = name
7175
or
72-
// @action.bound
76+
// `@action.bound`
7377
decoration.(PropAccess).getPropertyName() = name
7478
)
7579
}

javascript/ql/test/query-tests/Expressions/UnboundEventHandlerReceiver/tst.js

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -172,3 +172,21 @@ class Component4 extends React.Component {
172172
this.setState({ });
173173
}
174174
}
175+
176+
class Component5 extends React.Component {
177+
178+
render() {
179+
return <div>
180+
<div onClick={this.bound_throughSomeBinder}/> // OK
181+
</div>
182+
}
183+
184+
constructor(props) {
185+
super(props);
186+
someBind(this, "bound_throughSomeBinder");
187+
}
188+
189+
bound_throughSomeBinder() {
190+
this.setState({ });
191+
}
192+
}

0 commit comments

Comments
 (0)