Skip to content

Commit cf3a4ac

Browse files
authored
Merge pull request #767 from esben-semmle/js/unknown-bound-event-handler-receiver
Approved by xiemaisi
2 parents 8655e5a + 7f5dd1a commit cf3a4ac

File tree

3 files changed

+31
-1
lines changed

3 files changed

+31
-1
lines changed

change-notes/1.20/analysis-javascript.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
| Incomplete URL substring sanitization | correctness, security, external/cwe/cwe-020 | Highlights URL sanitizers that are likely to be incomplete, indicating a violation of [CWE-020](https://cwe.mitre.org/data/definitions/20.html). Results shown on LGTM by default. |
2020
| Incorrect suffix check (`js/incorrect-suffix-check`) | correctness, security, external/cwe/cwe-020 | Highlights error-prone suffix checks based on `indexOf`, indicating a potential violation of [CWE-20](https://cwe.mitre.org/data/definitions/20.html). Results are shown on LGTM by default. |
2121
| Loop iteration skipped due to shifting (`js/loop-iteration-skipped-due-to-shifting`) | correctness | Highlights code that removes an element from an array while iterating over it, causing the loop to skip over some elements. Results are shown on LGTM by default. |
22+
| Unbound event handler receiver (`js/unbound-event-handler-receiver`) | Fewer false positive results | Additional ways that class methods can be bound are recognized. |
2223
| Useless comparison test (`js/useless-comparison-test`) | correctness | Highlights code that is unreachable due to a numeric comparison that is always true or always false. Results are shown on LGTM by default. |
2324

2425
## Changes to existing queries

javascript/ql/src/Expressions/UnboundEventHandlerReceiver.ql

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,15 @@ private predicate isBoundInMethod(MethodDeclaration method) {
1818
bindingMethod.getDeclaringClass() = method.getDeclaringClass() and
1919
not bindingMethod.isStatic() and
2020
thiz.getBinder().getAstNode() = bindingMethod.getBody()
21-
|
21+
|
22+
exists (DataFlow::MethodCallNode bind, DataFlow::PropWrite w |
23+
// this[x] = <expr>.bind(...)
24+
w = thiz.getAPropertyWrite() and
25+
not exists(w.getPropertyName()) and
26+
bind.getMethodName() = "bind" and
27+
bind.flowsTo(w.getRhs())
28+
)
29+
or
2230
// require("auto-bind")(this)
2331
thiz.flowsTo(DataFlow::moduleImport("auto-bind").getACall().getArgument(0))
2432
or

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

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -134,4 +134,25 @@ class Component2 extends React.Component {
134134
}
135135

136136
}
137+
138+
class Component3 extends React.Component {
139+
140+
render() {
141+
return <div>
142+
<div onClick={this.bound_throughIterator}/> // OK
143+
</div>
144+
}
145+
146+
constructor(props) {
147+
super(props);
148+
Object.getOwnPropertyNames( Component3.prototype )
149+
.filter( prop => typeof this[ prop ] === 'function' )
150+
.forEach( prop => ( this[ prop ] = this[ prop ].bind( this ) ) );
151+
}
152+
153+
bound_throughIterator() {
154+
this.setState({ });
155+
}
156+
}
157+
137158
// semmle-extractor-options: --experimental

0 commit comments

Comments
 (0)