Fix false positives in stream pipe analysis by improving error handler tracking via property access.

This commit is contained in:
Napalys Klicius
2025-05-30 18:08:04 +02:00
parent d3b2a57fbf
commit f843cc02f6
3 changed files with 24 additions and 6 deletions

View File

@@ -218,7 +218,17 @@ private DataFlow::SourceNode sourceStreamRef(PipeCall pipeCall) {
* Holds if the source stream of the given pipe call has an `error` handler registered.
*/
private predicate hasErrorHandlerRegistered(PipeCall pipeCall) {
sourceStreamRef(pipeCall).getAMethodCall(_) instanceof ErrorHandlerRegistration
exists(DataFlow::Node stream |
stream = sourceStreamRef(pipeCall).getALocalUse() and
(
stream.(DataFlow::SourceNode).getAMethodCall(_) instanceof ErrorHandlerRegistration
or
exists(DataFlow::SourceNode base, string propName |
stream = base.getAPropertyRead(propName) and
base.getAPropertyRead(propName).getAMethodCall(_) instanceof ErrorHandlerRegistration
)
)
)
or
hasPlumber(pipeCall)
}
@@ -262,8 +272,16 @@ private predicate hasNonStreamSourceLikeUsage(PipeCall pipeCall) {
* Holds if the pipe call destination stream has an error handler registered.
*/
private predicate hasErrorHandlerDownstream(PipeCall pipeCall) {
exists(ErrorHandlerRegistration handler |
handler.getReceiver().getALocalSource() = destinationStreamRef(pipeCall)
exists(DataFlow::SourceNode stream |
stream = destinationStreamRef(pipeCall) and
(
exists(ErrorHandlerRegistration handler | handler.getReceiver().getALocalSource() = stream)
or
exists(DataFlow::SourceNode base, string propName |
stream = base.getAPropertyRead(propName) and
base.getAPropertyRead(propName).getAMethodCall(_) instanceof ErrorHandlerRegistration
)
)
)
}

View File

@@ -12,9 +12,9 @@
| test.js:182:17:182:40 | notStre ... itable) | Stream pipe without error handling on the source stream. Errors won't propagate downstream and may be silently dropped. |
| test.js:192:5:192:32 | copyStr ... nation) | Stream pipe without error handling on the source stream. Errors won't propagate downstream and may be silently dropped. |
| tst.js:8:5:8:21 | source.pipe(gzip) | Stream pipe without error handling on the source stream. Errors won't propagate downstream and may be silently dropped. |
| tst.js:29:5:29:40 | wrapper ... Stream) | Stream pipe without error handling on the source stream. Errors won't propagate downstream and may be silently dropped. |
| tst.js:37:21:37:56 | wrapper ... Stream) | Stream pipe without error handling on the source stream. Errors won't propagate downstream and may be silently dropped. |
| tst.js:44:5:44:40 | wrapper ... Stream) | Stream pipe without error handling on the source stream. Errors won't propagate downstream and may be silently dropped. |
| tst.js:52:5:52:37 | source. ... Stream) | Stream pipe without error handling on the source stream. Errors won't propagate downstream and may be silently dropped. |
| tst.js:59:18:59:39 | stream. ... Stream) | Stream pipe without error handling on the source stream. Errors won't propagate downstream and may be silently dropped. |
| tst.js:73:5:73:40 | wrapper ... Stream) | Stream pipe without error handling on the source stream. Errors won't propagate downstream and may be silently dropped. |
| tst.js:111:5:111:26 | stream. ... Stream) | Stream pipe without error handling on the source stream. Errors won't propagate downstream and may be silently dropped. |

View File

@@ -26,7 +26,7 @@ function zip() {
function zip1() {
const zipStream = createWriteStream(zipPath);
let wrapper = new StreamWrapper();
wrapper.outputStream.pipe(zipStream); // $SPURIOUS:Alert
wrapper.outputStream.pipe(zipStream);
wrapper.outputStream.on('error', e);
zipStream.on('error', e);
}
@@ -49,7 +49,7 @@ function zip3() {
const zipStream = createWriteStream(zipPath);
let wrapper = new StreamWrapper();
let source = getStream();
source.pipe(wrapper.outputStream); // $MISSING:Alert
source.pipe(wrapper.outputStream); // $Alert
wrapper.outputStream.on('error', e);
}