Skip to content

Commit 3d5d178

Browse files
authored
Merge pull request github#2439 from erik-krogh/useOfReturnlessFunctionHotfix
Approved by max-schaefer
2 parents 1a07f21 + fed2675 commit 3d5d178

File tree

6 files changed

+40
-7
lines changed

6 files changed

+40
-7
lines changed

javascript/ql/src/Statements/UseOfReturnlessFunction.ql

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,9 @@ predicate benignContext(Expr e) {
3333
inVoidContext(e) or
3434

3535
// A return statement is often used to just end the function.
36-
e = any(Function f).getAReturnedExpr()
36+
e = any(Function f).getBody()
37+
or
38+
e = any(ReturnStmt r).getExpr()
3739
or
3840
exists(ConditionalExpr cond | cond.getABranch() = e and benignContext(cond))
3941
or
@@ -42,7 +44,6 @@ predicate benignContext(Expr e) {
4244
exists(Expr parent | parent.getUnderlyingValue() = e and benignContext(parent))
4345
or
4446
any(VoidExpr voidExpr).getOperand() = e
45-
4647
or
4748
// weeds out calls inside HTML-attributes.
4849
e.getParent().(ExprStmt).getParent() instanceof CodeInAttribute or
@@ -70,8 +71,8 @@ predicate benignContext(Expr e) {
7071
e = any(ResolvedPromiseDefinition promise).getValue().asExpr()
7172
}
7273

73-
predicate oneshotClosure(InvokeExpr call) {
74-
call.getCallee().getUnderlyingValue() instanceof ImmediatelyInvokedFunctionExpr
74+
predicate oneshotClosure(DataFlow::CallNode call) {
75+
call.getCalleeNode().asExpr().getUnderlyingValue() instanceof ImmediatelyInvokedFunctionExpr
7576
}
7677

7778
predicate alwaysThrows(Function f) {
@@ -149,6 +150,12 @@ predicate voidArrayCallback(DataFlow::CallNode call, Function func) {
149150
)
150151
}
151152

153+
predicate hasNonVoidReturnType(Function f) {
154+
exists(TypeAnnotation type | type = f.getReturnTypeAnnotation() |
155+
not type.isVoid()
156+
)
157+
}
158+
152159

153160
/**
154161
* Provides classes for working with various Deferred implementations.
@@ -214,6 +221,8 @@ where
214221
not benignContext(call.getEnclosingExpr()) and
215222
not lastStatementHasNoEffect(func) and
216223
// anonymous one-shot closure. Those are used in weird ways and we ignore them.
217-
not oneshotClosure(call.getEnclosingExpr())
224+
not oneshotClosure(call) and
225+
not hasNonVoidReturnType(func) and
226+
not call.getEnclosingExpr() instanceof SuperCall
218227
select
219228
call, msg, func, name

javascript/ql/test/query-tests/Statements/UseOfReturnlessFunction/UseOfReturnlessFunction.expected

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,3 +6,4 @@
66
| tst.js:53:10:53:34 | bothOnl ... fects() | the $@ does not return anything, yet the return value is used. | tst.js:48:2:50:5 | functio ... )\\n } | function onlySideEffects2 |
77
| tst.js:76:12:76:46 | [1,2,3] ... n, 3)}) | the $@ does not return anything, yet the return value from the call to filter is used. | tst.js:76:27:76:45 | n => {equals(n, 3)} | callback function |
88
| tst.js:80:12:80:50 | filter( ... 3) } ) | the $@ does not return anything, yet the return value from the call to filter is used. | tst.js:80:28:80:48 | x => { ... x, 3) } | callback function |
9+
| tst.ts:6:13:6:25 | returnsVoid() | the $@ does not return anything, yet the return value is used. | tst.ts:1:1:1:38 | declare ... : void; | function returnsVoid |
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
{}

javascript/ql/test/query-tests/Statements/UseOfReturnlessFunction/tst.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
}
1313
</script>
1414
</head>
15-
<body>
15+
<body onload="return addHandlers();">
1616
<object id="container" data="editor/svg-editor.html" onload="addHandlers()"></object>
1717
<a href="javascript:addHandlers()">Foo</a>
1818
<div onclick="addHandlers()">Click me</div>

javascript/ql/test/query-tests/Statements/UseOfReturnlessFunction/tst.js

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -88,4 +88,20 @@
8888
}
8989

9090
new Deferred().resolve(onlySideEffects()); // OK
91-
})();
91+
})();
92+
93+
+function() {
94+
console.log("FOO");
95+
}.call(this);
96+
97+
class Foo {
98+
constructor() {
99+
console.log("FOO");
100+
}
101+
}
102+
103+
class Bar extends Foo {
104+
constructor() {
105+
console.log(super()); // OK.
106+
}
107+
}
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
declare function returnsVoid() : void;
2+
declare function returnsSomething(): number;
3+
4+
console.log(returnsSomething());
5+
6+
console.log(returnsVoid()); // NOT OK!

0 commit comments

Comments
 (0)