Skip to content

Commit 09220fc

Browse files
committed
Fixed issue where pipe calls from rxjs package would been identified as pipe calls on streams
1 parent d7f86db commit 09220fc

File tree

4 files changed

+29
-6
lines changed

4 files changed

+29
-6
lines changed

javascript/ql/lib/ext/rxjs.model.yml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
extensions:
2+
- addsTo:
3+
pack: codeql/javascript-all
4+
extensible: typeModel
5+
data:
6+
- ["NonNodeStream", "rxjs", "Fuzzy"]
7+
- ["NonNodeStream", "rxjs/operators", "Fuzzy"]

javascript/ql/src/Quality/UnhandledStreamPipe.ql

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,8 @@ class PipeCall extends DataFlow::MethodCallNode {
1919
this.getMethodName() = "pipe" and
2020
this.getNumArgument() = [1, 2] and
2121
not this.getArgument(0).asExpr() instanceof Function and
22-
not this.getArgument(0).asExpr() instanceof ObjectExpr
22+
not this.getArgument(0).asExpr() instanceof ObjectExpr and
23+
not this.getArgument(0).getALocalSource() = getNonNodeJsStreamType()
2324
}
2425

2526
/** Gets the source stream (receiver of the pipe call). */
@@ -29,6 +30,14 @@ class PipeCall extends DataFlow::MethodCallNode {
2930
DataFlow::Node getDestinationStream() { result = this.getArgument(0) }
3031
}
3132

33+
/**
34+
* Gets a reference to a value that is known to not be a Node.js stream.
35+
* This is used to exclude pipe calls on non-stream objects from analysis.
36+
*/
37+
DataFlow::Node getNonNodeJsStreamType() {
38+
result = ModelOutput::getATypeNode("NonNodeStream").asSource()
39+
}
40+
3241
/**
3342
* Gets the method names used to register event handlers on Node.js streams.
3443
* These methods are used to attach handlers for events like `error`.
@@ -181,9 +190,18 @@ predicate hasErrorHandlerRegistered(PipeCall pipeCall) {
181190
)
182191
}
183192

193+
/**
194+
* Holds if the source or destination of the given pipe call is identified as a non-Node.js stream.
195+
*/
196+
predicate hasNonNodeJsStreamSource(PipeCall pipeCall) {
197+
streamRef(pipeCall) = getNonNodeJsStreamType() or
198+
pipeResultRef(pipeCall) = getNonNodeJsStreamType()
199+
}
200+
184201
from PipeCall pipeCall
185202
where
186203
not hasErrorHandlerRegistered(pipeCall) and
187-
not isPipeFollowedByNonStreamAccess(pipeCall)
204+
not isPipeFollowedByNonStreamAccess(pipeCall) and
205+
not hasNonNodeJsStreamSource(pipeCall)
188206
select pipeCall,
189207
"Stream pipe without error handling on the source stream. Errors won't propagate downstream and may be silently dropped."

javascript/ql/test/query-tests/Quality/UnhandledStreamPipe/rxjsStreams.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,6 @@ const { of, from } = rx;
55
const { map, filter } = ops;
66

77
function f(){
8-
of(1, 2, 3).pipe(map(x => x * 2)); // $SPURIOUS:Alert
9-
someNonStream().pipe(map(x => x * 2)); // $SPURIOUS:Alert
8+
of(1, 2, 3).pipe(map(x => x * 2));
9+
someNonStream().pipe(map(x => x * 2));
1010
}

javascript/ql/test/query-tests/Quality/UnhandledStreamPipe/test.expected

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
| rxjsStreams.js:8:3:8:35 | of(1, 2 ... x * 2)) | Stream pipe without error handling on the source stream. Errors won't propagate downstream and may be silently dropped. |
2-
| rxjsStreams.js:9:3:9:39 | someNon ... x * 2)) | Stream pipe without error handling on the source stream. Errors won't propagate downstream and may be silently dropped. |
31
| test.js:4:5:4:28 | stream. ... nation) | Stream pipe without error handling on the source stream. Errors won't propagate downstream and may be silently dropped. |
42
| test.js:19:5:19:17 | s2.pipe(dest) | Stream pipe without error handling on the source stream. Errors won't propagate downstream and may be silently dropped. |
53
| test.js:45:5:45:30 | stream2 ... ation2) | Stream pipe without error handling on the source stream. Errors won't propagate downstream and may be silently dropped. |

0 commit comments

Comments
 (0)