Skip to content

Commit cb16116

Browse files
committed
adjust type-tracking on custom EventEmitters
1 parent 082967a commit cb16116

File tree

3 files changed

+38
-11
lines changed

3 files changed

+38
-11
lines changed

javascript/ql/src/semmle/javascript/frameworks/NodeJSLib.qll

Lines changed: 10 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -892,11 +892,6 @@ module NodeJSLib {
892892
* Get a Node that refers to a NodeJS EventEmitter instance.
893893
*/
894894
DataFlow::SourceNode ref() { result = EventEmitter::trackEventEmitter(this) }
895-
896-
/**
897-
* Gets the node that will used for comparison when determining whether one EventEmitter can send an event to another EventEmitter.
898-
*/
899-
DataFlow::SourceNode getBaseEmitter() {result = this}
900895
}
901896

902897
/**
@@ -932,12 +927,18 @@ module NodeJSLib {
932927
class CustomEventEmitter extends NodeJSEventEmitter {
933928
EventEmitterSubClass clazz;
934929
CustomEventEmitter() {
935-
this = clazz.getAnInstanceReference()
930+
if exists(clazz.getAClassReference().getAnInstantiation()) then
931+
this = clazz.getAClassReference().getAnInstantiation()
932+
else
933+
// In case there are no explicit instantiations of the clazz, then we still want to track data flow between `this` nodes.
934+
// This cannot produce false flow as the `.ref()` method below is always used when creating event-registrations/event-dispatches.
935+
this = clazz
936936
}
937937

938-
// we define that events can flow between all instances of the same class, as we thereby support the `this` references in the class itself.
939-
override DataFlow::SourceNode getBaseEmitter() {
940-
result = clazz
938+
override DataFlow::SourceNode ref() {
939+
result = NodeJSEventEmitter.super.ref() and not this = clazz
940+
or
941+
result = clazz.getAReceiverNode()
941942
}
942943
}
943944

@@ -959,8 +960,6 @@ module NodeJSLib {
959960
override NodeJSEventEmitter emitter;
960961

961962
NodeJSEventDispatch() { this = emitter.ref().getAMethodCall("emit") }
962-
963-
override EventRegistration::Range getAReceiver() { emitter.getBaseEmitter() = result.getEmitter().(NodeJSEventEmitter).getBaseEmitter() }
964963
}
965964

966965
/**
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
const EventEmitter = require("events");
2+
3+
class MyEmitter extends EventEmitter {
4+
foo() {
5+
this.emit("foo", "bar");
6+
this.on("foo", (data) => {});
7+
}
8+
}
9+
10+
class MySecondEmitter extends EventEmitter {
11+
foo() {
12+
this.emit("bar", "baz");
13+
this.on("bar", (data) => {});
14+
}
15+
}
16+
17+
var x = new MySecondEmitter();
18+
x.emit("bar", "baz2");
19+
20+
var y = new MySecondEmitter();
21+
y.emit("bar", "baz3");
22+
y.on("bar", (yData) => {})

javascript/ql/test/library-tests/frameworks/EventEmitter/test.expected

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,9 @@
1+
| customEmitter.js:5:20:5:24 | "bar" | customEmitter.js:6:19:6:22 | data |
2+
| customEmitter.js:12:21:12:25 | "baz" | customEmitter.js:13:23:13:26 | data |
3+
| customEmitter.js:12:21:12:25 | "baz" | customEmitter.js:22:14:22:18 | yData |
4+
| customEmitter.js:18:15:18:20 | "baz2" | customEmitter.js:13:23:13:26 | data |
5+
| customEmitter.js:21:15:21:20 | "baz3" | customEmitter.js:13:23:13:26 | data |
6+
| customEmitter.js:21:15:21:20 | "baz3" | customEmitter.js:22:14:22:18 | yData |
17
| tst.js:9:23:9:33 | 'FirstData' | tst.js:6:40:6:44 | first |
28
| tst.js:10:24:10:35 | 'SecondData' | tst.js:7:32:7:37 | second |
39
| tst.js:15:24:15:39 | 'OtherFirstData' | tst.js:14:41:14:50 | otherFirst |

0 commit comments

Comments
 (0)