Skip to content

Commit a7d9a50

Browse files
authored
Merge pull request #1176 from xiemaisi/js/fix-socket-io-type-tracking
Approved by asger-semmle
2 parents 76caad0 + 62c895d commit a7d9a50

File tree

4 files changed

+38
-7
lines changed

4 files changed

+38
-7
lines changed

javascript/ql/src/semmle/javascript/dataflow/TypeTracking.qll

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,7 @@ class TypeTracker extends TTypeTracker {
126126

127127
TypeTracker() { this = MkTypeTracker(hasCall, prop) }
128128

129+
/** Gets the summary resulting from appending `step` to this type-tracking summary. */
129130
TypeTracker append(StepSummary step) {
130131
step = LevelStep() and result = this
131132
or
@@ -140,6 +141,7 @@ class TypeTracker extends TTypeTracker {
140141
)
141142
}
142143

144+
/** Gets a textual representation of this summary. */
143145
string toString() {
144146
exists(string withCall, string withProp |
145147
(if hasCall = true then withCall = "with" else withCall = "without") and
@@ -153,6 +155,9 @@ class TypeTracker extends TTypeTracker {
153155
*/
154156
predicate start() { hasCall = false and prop = "" }
155157

158+
/**
159+
* Holds if this is the end point of type tracking.
160+
*/
156161
predicate end() { prop = "" }
157162

158163
/**
@@ -162,7 +167,13 @@ class TypeTracker extends TTypeTracker {
162167
*/
163168
boolean hasCall() { result = hasCall }
164169

165-
string getProp() { result = prop }
170+
/**
171+
* Gets a type tracker that starts where this one has left off to allow continued
172+
* tracking.
173+
*
174+
* This predicate is only defined if the type has not been tracked into a property.
175+
*/
176+
TypeTracker continue() { prop = "" and result = this }
166177
}
167178

168179
module TypeTracker {
@@ -206,6 +217,7 @@ class TypeBackTracker extends TTypeBackTracker {
206217

207218
TypeBackTracker() { this = MkTypeBackTracker(hasReturn, prop) }
208219

220+
/** Gets the summary resulting from prepending `step` to this type-tracking summary. */
209221
TypeBackTracker prepend(StepSummary step) {
210222
step = LevelStep() and result = this
211223
or
@@ -220,6 +232,7 @@ class TypeBackTracker extends TTypeBackTracker {
220232
step = StoreStep(prop) and result = MkTypeBackTracker(hasReturn, "")
221233
}
222234

235+
/** Gets a textual representation of this summary. */
223236
string toString() {
224237
exists(string withReturn, string withProp |
225238
(if hasReturn = true then withReturn = "with" else withReturn = "without") and
@@ -233,6 +246,9 @@ class TypeBackTracker extends TTypeBackTracker {
233246
*/
234247
predicate start() { hasReturn = false and prop = "" }
235248

249+
/**
250+
* Holds if this is the end point of type tracking.
251+
*/
236252
predicate end() { prop = "" }
237253

238254
/**
@@ -242,7 +258,13 @@ class TypeBackTracker extends TTypeBackTracker {
242258
*/
243259
boolean hasReturn() { result = hasReturn }
244260

245-
string getProp() { result = prop }
261+
/**
262+
* Gets a type tracker that starts where this one has left off to allow continued
263+
* tracking.
264+
*
265+
* This predicate is only defined if the type has not been tracked into a property.
266+
*/
267+
TypeBackTracker continue() { prop = "" and result = this }
246268
}
247269

248270
module TypeBackTracker {

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

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ module SocketIO {
5151
// exclude getter versions
5252
exists(mcn.getAnArgument()) and
5353
result = mcn and
54-
t = t2
54+
t = t2.continue()
5555
)
5656
)
5757
}
@@ -110,7 +110,7 @@ module SocketIO {
110110
or
111111
// invocation of a chainable method
112112
result = pred.getAMethodCall(namespaceChainableMethod()) and
113-
t = t2
113+
t = t2.continue()
114114
or
115115
// invocation of chainable getter method
116116
exists(string m |
@@ -119,7 +119,7 @@ module SocketIO {
119119
m = "volatile"
120120
|
121121
result = pred.getAPropertyRead(m) and
122-
t = t2
122+
t = t2.continue()
123123
)
124124
)
125125
}
@@ -171,7 +171,7 @@ module SocketIO {
171171
m = EventEmitter::chainableMethod()
172172
|
173173
result = pred.getAMethodCall(m) and
174-
t = t2
174+
t = t2.continue()
175175
)
176176
or
177177
// invocation of a chainable getter method
@@ -182,7 +182,7 @@ module SocketIO {
182182
m = "volatile"
183183
|
184184
result = pred.getAPropertyRead(m) and
185-
t = t2
185+
t = t2.continue()
186186
)
187187
)
188188
}

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -149,6 +149,7 @@ test_ServerNode
149149
| tst.js:15:1:15:15 | io.attach(http) | tst.js:1:12:1:33 | socket.io server |
150150
| tst.js:16:1:16:15 | io.bind(engine) | tst.js:1:12:1:33 | socket.io server |
151151
| tst.js:17:1:17:23 | io.onco ... socket) | tst.js:1:12:1:33 | socket.io server |
152+
| tst.js:79:1:79:10 | obj.server | tst.js:1:12:1:33 | socket.io server |
152153
test_ClientSendNode_getAReceiver
153154
| client2.js:14:1:14:32 | sock.em ... there") | tst.js:72:3:72:43 | socket. ... => {}) |
154155
| client2.js:16:1:16:36 | sock.wr ... => {}) | tst.js:70:3:70:35 | socket. ... => {}) |

javascript/ql/test/library-tests/frameworks/SocketIO/tst.js

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,3 +71,11 @@ ns.on('connection', (socket) => {
7171
socket.once('message', (data1, data2) => {});
7272
socket.addListener(eventName(), () => {});
7373
});
74+
75+
var obj = {
76+
server: io,
77+
serveClient: function() { return null; }
78+
};
79+
obj.server; // SocketIO::ServerNode
80+
obj.serveClient(false); // not a SocketIO::ServerNode
81+
obj.serveClient(false).server; // not a SocketIO::ServerNode

0 commit comments

Comments
 (0)