Skip to content

Commit 854dc0c

Browse files
author
Max Schaefer
authored
Merge pull request #28 from esben-semmle/js/whitelist-empty-functions
JS: permit some calls with spurious arguments to empty functions
2 parents 1a5585c + 4e98ce2 commit 854dc0c

File tree

7 files changed

+66
-18
lines changed

7 files changed

+66
-18
lines changed

change-notes/1.18/analysis-javascript.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@
4444
| Missing X-Frame-Options HTTP header | Fewer false-positive results | This rule now treats header names case-insensitively. |
4545
| Reflected cross-site scripting | Fewer false-positive results | This rule now treats header names case-insensitively. |
4646
| Server-side URL redirect | More true-positive results | This rule now treats header names case-insensitively. |
47+
| Superfluous trailing arguments | Fewer false-positive results | This rule now ignores calls to some empty functions. |
4748
| Uncontrolled command line | More true-positive results | This rule now recognizes indirect command injection through `sh -c` and similar. |
4849
| Unused variable | Fewer results | This rule no longer flags class expressions that could be made anonymous. While technically true, these results are not interesting. |
4950
| Unused variable | Renamed | This rule has been renamed to "Unused variable, import, function or class" to reflect the fact that it flags different kinds of unused program elements. |

javascript/ql/src/LanguageFeatures/SpuriousArguments.ql

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -83,5 +83,14 @@ class SpuriousArguments extends Expr {
8383

8484
from SpuriousArguments args, Function f, string arguments
8585
where f = args.getCall().getACallee() and
86-
if args.getCount() = 1 then arguments = "argument" else arguments = "arguments"
86+
if args.getCount() = 1 then arguments = "argument" else arguments = "arguments" and
87+
(
88+
// exclude empty functions, they are probably commented out debug utilities ...
89+
exists(f.getABodyStmt()) or
90+
// ... but include: constructors, arrows and externals/ambients
91+
f instanceof Constructor or // unlikely to be a debug utility
92+
f instanceof ArrowFunctionExpr or // cannot be empty
93+
f instanceof ExternalFunction or // always empty
94+
f.isAmbient() // always empty
95+
)
8796
select args, "Superfluous " + arguments + " passed to $@.", f, f.describe()
Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,19 @@
11
| es2015.js:4:16:4:17 | 23 | Superfluous argument passed to $@. | es2015.js:2:14:2:32 | (x) { this.x = x; } | constructor of class Class1 |
22
| es2015.js:17:11:17:12 | 42 | Superfluous argument passed to $@. | es2015.js:15:13:15:12 | () {} | default constructor of class Other |
33
| es2015.js:21:3:21:4 | 42 | Superfluous argument passed to $@. | tst.js:1:1:4:1 | functio ... x+19;\\n} | function f |
4-
| globals.js:15:13:15:13 | x | Superfluous argument passed to $@. | globals.js:9:1:9:25 | functio ... al() {} | function otherglobal |
5-
| globals.js:16:24:16:24 | x | Superfluous argument passed to $@. | globals.js:9:1:9:25 | functio ... al() {} | function otherglobal |
6-
| globals.js:17:24:17:27 | x | Superfluous arguments passed to $@. | globals.js:9:1:9:25 | functio ... al() {} | function otherglobal |
7-
| reflection.js:6:15:6:15 | 1 | Superfluous argument passed to $@. | reflection.js:1:1:1:16 | function f0() {} | function f0 |
8-
| reflection.js:7:15:7:18 | 1 | Superfluous arguments passed to $@. | reflection.js:1:1:1:16 | function f0() {} | function f0 |
9-
| reflection.js:12:18:12:18 | 2 | Superfluous argument passed to $@. | reflection.js:2:1:2:17 | function f1(x) {} | function f1 |
10-
| thisparameter.ts:4:11:4:12 | 45 | Superfluous argument passed to $@. | thisparameter.ts:1:1:1:38 | functio ... ber) {} | function foo |
4+
| globals.js:15:13:15:13 | x | Superfluous argument passed to $@. | globals.js:9:1:9:32 | functio ... eturn;} | function otherglobal |
5+
| globals.js:16:24:16:24 | x | Superfluous argument passed to $@. | globals.js:9:1:9:32 | functio ... eturn;} | function otherglobal |
6+
| globals.js:17:24:17:27 | x | Superfluous arguments passed to $@. | globals.js:9:1:9:32 | functio ... eturn;} | function otherglobal |
7+
| reflection.js:6:15:6:15 | 1 | Superfluous argument passed to $@. | reflection.js:1:1:1:23 | functio ... eturn;} | function f0 |
8+
| reflection.js:7:15:7:18 | 1 | Superfluous arguments passed to $@. | reflection.js:1:1:1:23 | functio ... eturn;} | function f0 |
9+
| reflection.js:12:18:12:18 | 2 | Superfluous argument passed to $@. | reflection.js:2:1:2:24 | functio ... eturn;} | function f1 |
10+
| thisparameter.ts:4:11:4:12 | 45 | Superfluous argument passed to $@. | thisparameter.ts:1:1:1:45 | functio ... eturn;} | function foo |
1111
| tst.js:11:3:11:5 | g() | Superfluous argument passed to $@. | tst.js:1:1:4:1 | functio ... x+19;\\n} | function f |
1212
| tst.js:33:15:33:18 | 2 | Superfluous arguments passed to $@. | externs.js:34:1:34:27 | functio ... str) {} | function String |
13-
| tst.js:37:4:37:5 | 42 | Superfluous argument passed to $@. | tst.js:38:4:38:16 | function() {} | anonymous function |
13+
| tst.js:37:4:37:5 | 42 | Superfluous argument passed to $@. | tst.js:38:4:38:23 | function() {return;} | anonymous function |
1414
| tst.js:46:19:46:20 | 10 | Superfluous argument passed to $@. | externs.js:36:1:36:27 | functio ... num) {} | function parseFloat |
15+
| tst.js:70:11:70:12 | 42 | Superfluous argument passed to $@. | tst.js:49:2:51:2 | functio ... urn;\\n\\t} | function nonEmpty |
16+
| tst.js:75:13:75:14 | 42 | Superfluous argument passed to $@. | tst.js:63:19:63:33 | () => undefined | function emptyArrow |
17+
| tst.js:76:31:76:32 | 42 | Superfluous argument passed to $@. | tst.js:64:33:64:32 | () {} | default constructor of class ImplicitEmptyConstructor |
18+
| tst.js:77:31:77:32 | 42 | Superfluous argument passed to $@. | tst.js:67:14:68:3 | (){\\n\\t\\t} | constructor of class ExplicitEmptyConstructor |
19+
| tst.js:78:20:78:21 | 10 | Superfluous argument passed to $@. | externs.js:36:1:36:27 | functio ... num) {} | function parseFloat |

javascript/ql/test/query-tests/LanguageFeatures/SpuriousArguments/globals.js

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,15 @@
1-
function global() {}
1+
function global() {return;}
22

33
(function(window) {
4-
window.global = function (x) {};
4+
window.global = function (x) {return;};
55
})(this);
66

77
global(x); // OK: might refer to function on line 4
88

9-
function otherglobal() {}
9+
function otherglobal() {return;}
1010

1111
var o = {
12-
otherglobal: function (x) {}
12+
otherglobal: function (x) {return;}
1313
};
1414

1515
otherglobal(x); // NOT OK: can never refer to function on line 12

javascript/ql/test/query-tests/LanguageFeatures/SpuriousArguments/reflection.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
function f0() {}
2-
function f1(x) {}
1+
function f0() {return;}
2+
function f1(x) {return;}
33

44
f0.call();
55
f0.call(this);
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
function foo(this: void, x: number) {}
1+
function foo(this: void, x: number) {return;}
22

33
foo(45); // OK
44
foo(null, 45); // NOT OK

javascript/ql/test/query-tests/LanguageFeatures/SpuriousArguments/tst.js

Lines changed: 35 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,12 +35,45 @@ new String(1, 2, 3);
3535
(function(f) {
3636
// NOT OK
3737
f(42);
38-
})(function() {});
38+
})(function() {return;});
3939

4040
(function h(f) {
4141
// OK
4242
f(42);
4343
h(function(x) { return x; });
4444
})(function() {});
4545

46-
parseFloat("123", 10);
46+
parseFloat("123", 10);
47+
48+
(function testWhitelistEmptyFunctions(){
49+
function nonEmpty(){
50+
return;
51+
}
52+
function empty(){
53+
54+
}
55+
function emptyWithParam(p){
56+
}
57+
function commentedEmpty(){
58+
// doStuff(arguments);
59+
}
60+
function commentedEmptyWithSpreadParam(...args){
61+
// doStuff(args)
62+
}
63+
var emptyArrow = () => undefined;
64+
class ImplicitEmptyConstructor {
65+
}
66+
class ExplicitEmptyConstructor {
67+
constructor(){
68+
}
69+
}
70+
nonEmpty(42); // NOT OK
71+
empty(42); // OK
72+
emptyWithParam(42, 87); // OK
73+
commentedEmpty(42); // OK
74+
commentedEmptyWithSpreadParam(42, 87); // OK
75+
emptyArrow(42); // NOT OK
76+
new ImplicitEmptyConstructor(42); // NOT OK
77+
new ExplicitEmptyConstructor(42); // NOT OK
78+
parseFloat("123", 10); // NOT OK
79+
})

0 commit comments

Comments
 (0)