Skip to content

Commit 825a3d2

Browse files
authored
Merge pull request #1954 from asger-semmle/type-tracking-through-captured-vars
Approved by xiemaisi
2 parents e2c941c + 69a88c4 commit 825a3d2

File tree

13 files changed

+125
-5
lines changed

13 files changed

+125
-5
lines changed

javascript/ql/src/meta/analysis-quality/CallGraphQuality.qll

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -173,12 +173,20 @@ SourceNode nodeLeadingToInvocation() {
173173
)
174174
}
175175

176+
/**
177+
* Holds if there is a call edge `invoke -> f` between a relevant invocation
178+
* and a relevant function.
179+
*/
180+
predicate relevantCall(RelevantInvoke invoke, RelevantFunction f) {
181+
FlowSteps::calls(invoke, f)
182+
}
183+
176184
/**
177185
* A call site that can be resolved to a function in the same project.
178186
*/
179187
class ResolvableCall extends RelevantInvoke {
180188
ResolvableCall() {
181-
FlowSteps::calls(this, _)
189+
relevantCall(this, _)
182190
or
183191
this = resolvableCallback().getAnInvocation()
184192
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
/**
2+
* @name DOM value references
3+
* @description The number of references to a DOM value.
4+
* @kind metric
5+
* @metricType project
6+
* @metricAggregate sum
7+
* @tags meta
8+
* @id js/meta/dom-value-refs
9+
*/
10+
11+
import javascript
12+
import CallGraphQuality
13+
14+
select projectRoot(), count(DOM::domValueRef())

javascript/ql/src/meta/analysis-quality/ResolvableCallCandidates.ql

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,4 +11,4 @@
1111
import javascript
1212
import CallGraphQuality
1313

14-
select projectRoot(), count(NonExternalCall call)
14+
select projectRoot(), count(RelevantInvoke call)

javascript/ql/src/meta/analysis-quality/ResolvableCallRatio.ql

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,4 +11,4 @@
1111
import javascript
1212
import CallGraphQuality
1313

14-
select projectRoot(), 100.0 * count(ResolvableCall call) / count(NonExternalCall call).(float)
14+
select projectRoot(), 100.0 * count(ResolvableCall call) / count(RelevantInvoke call).(float)

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

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -709,7 +709,8 @@ class ClassNode extends DataFlow::SourceNode {
709709
result = getAClassReference(t.continue()).getAnInstantiation()
710710
or
711711
t.start() and
712-
result.(AnalyzedNode).getAValue() = getAbstractInstanceValue()
712+
result.(AnalyzedNode).getAValue() = getAbstractInstanceValue() and
713+
not result = any(DataFlow::ClassNode cls).getAReceiverNode()
713714
or
714715
t.start() and
715716
result = getAReceiverNode()

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

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,27 @@ module StepSummary {
107107
pred = DataFlow::globalAccessPathRootPseudoNode() and
108108
summary = LoadStep(name)
109109
)
110+
or
111+
// Summarize calls with flow directly from a parameter to a return.
112+
exists(DataFlow::ParameterNode param, DataFlow::FunctionNode fun |
113+
(
114+
param.flowsTo(fun.getAReturn()) and
115+
summary = LevelStep()
116+
or
117+
exists(string prop |
118+
param.getAPropertyRead(prop).flowsTo(fun.getAReturn()) and
119+
summary = LoadStep(prop)
120+
)
121+
) and
122+
if param = fun.getAParameter() then (
123+
// Step from argument to call site.
124+
argumentPassing(succ, pred, fun.getFunction(), param)
125+
) else (
126+
// Step from captured parameter to local call sites
127+
pred = param and
128+
succ = fun.getAnInvocation()
129+
)
130+
)
110131
}
111132
}
112133

javascript/ql/test/library-tests/TypeTracking/ClassStyle.expected

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,20 @@ test_Connection
2424
| tst.js:63:38:63:77 | api.cha ... ction() |
2525
| tst.js:67:14:67:47 | MyAppli ... nection |
2626
| tst.js:78:35:78:49 | getConnection() |
27+
| tst.js:80:16:80:19 | conn |
28+
| tst.js:84:22:84:22 | x |
29+
| tst.js:88:3:88:16 | innerCapture() |
30+
| tst.js:89:3:89:17 | innerCall(conn) |
31+
| tst.js:93:5:93:18 | innerCapture() |
32+
| tst.js:99:7:99:21 | getConnection() |
33+
| tst.js:100:12:100:26 | getConnection() |
34+
| tst.js:103:17:103:17 | x |
35+
| tst.js:104:10:106:6 | (functi ... \\n })() |
36+
| tst.js:108:1:108:23 | shared( ... tion()) |
37+
| tst.js:108:8:108:22 | getConnection() |
38+
| tst.js:112:10:112:14 | obj.x |
39+
| tst.js:114:1:114:28 | getX({ ... on() }) |
40+
| tst.js:114:11:114:25 | getConnection() |
2741
| tst_conflict.js:6:38:6:77 | api.cha ... ction() |
2842
test_DataCallback
2943
| client.js:3:28:3:34 | x => {} |
@@ -35,6 +49,7 @@ test_DataCallback
3549
| tst.js:40:32:40:45 | getDataCurry() |
3650
| tst.js:45:19:45:20 | cb |
3751
| tst.js:48:32:48:60 | identit ... llback) |
52+
| tst.js:51:1:51:37 | functio ... ata) {} |
3853
| tst.js:58:16:58:22 | x => {} |
3954
| tst.js:68:16:70:3 | data => ... a);\\n } |
4055
test_DataValue
@@ -43,5 +58,6 @@ test_DataValue
4358
| tst.js:25:19:25:22 | data |
4459
| tst.js:33:17:33:20 | data |
4560
| tst.js:38:10:38:13 | data |
61+
| tst.js:51:30:51:33 | data |
4662
| tst.js:58:16:58:16 | x |
4763
| tst.js:68:16:68:19 | data |

javascript/ql/test/library-tests/TypeTracking/PredicateStyle.expected

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,16 @@ apiObject
1212
connection
1313
| type tracker with call steps | tst.js:7:15:7:18 | conn |
1414
| type tracker with call steps | tst.js:11:5:11:19 | this.connection |
15+
| type tracker with call steps | tst.js:80:16:80:19 | conn |
16+
| type tracker with call steps | tst.js:84:22:84:22 | x |
17+
| type tracker with call steps | tst.js:88:3:88:16 | innerCapture() |
18+
| type tracker with call steps | tst.js:89:3:89:17 | innerCall(conn) |
19+
| type tracker with call steps | tst.js:93:5:93:18 | innerCapture() |
20+
| type tracker with call steps | tst.js:103:17:103:17 | x |
21+
| type tracker with call steps | tst.js:104:10:106:6 | (functi ... \\n })() |
22+
| type tracker with call steps | tst.js:112:10:112:14 | obj.x |
1523
| type tracker with call steps with property connection | tst.js:7:14:7:13 | this |
24+
| type tracker with call steps with property x | tst.js:111:15:111:17 | obj |
1625
| type tracker without call steps | client.js:1:10:1:27 | exportedConnection |
1726
| type tracker without call steps | tst.js:16:10:16:49 | api.cha ... ction() |
1827
| type tracker without call steps | tst.js:19:7:19:21 | getConnection() |
@@ -25,11 +34,18 @@ connection
2534
| type tracker without call steps | tst.js:63:38:63:77 | api.cha ... ction() |
2635
| type tracker without call steps | tst.js:67:14:67:47 | MyAppli ... nection |
2736
| type tracker without call steps | tst.js:78:35:78:49 | getConnection() |
37+
| type tracker without call steps | tst.js:99:7:99:21 | getConnection() |
38+
| type tracker without call steps | tst.js:100:12:100:26 | getConnection() |
39+
| type tracker without call steps | tst.js:108:1:108:23 | shared( ... tion()) |
40+
| type tracker without call steps | tst.js:108:8:108:22 | getConnection() |
41+
| type tracker without call steps | tst.js:114:1:114:28 | getX({ ... on() }) |
42+
| type tracker without call steps | tst.js:114:11:114:25 | getConnection() |
2843
| type tracker without call steps | tst_conflict.js:6:38:6:77 | api.cha ... ction() |
2944
| type tracker without call steps with property MyApplication.namespace.connection | file://:0:0:0:0 | global access path |
3045
| type tracker without call steps with property conflict | tst.js:63:3:63:25 | MyAppli ... mespace |
3146
| type tracker without call steps with property conflict | tst_conflict.js:6:3:6:25 | MyAppli ... mespace |
3247
| type tracker without call steps with property connection | tst.js:62:3:62:25 | MyAppli ... mespace |
48+
| type tracker without call steps with property x | tst.js:114:6:114:27 | { x: ge ... ion() } |
3349
dataCallback
3450
| client.js:3:28:3:34 | x => {} |
3551
| tst.js:10:11:10:12 | cb |
@@ -40,6 +56,7 @@ dataCallback
4056
| tst.js:40:32:40:45 | getDataCurry() |
4157
| tst.js:45:19:45:20 | cb |
4258
| tst.js:48:32:48:60 | identit ... llback) |
59+
| tst.js:51:1:51:37 | functio ... ata) {} |
4360
| tst.js:58:16:58:22 | x => {} |
4461
| tst.js:68:16:70:3 | data => ... a);\\n } |
4562
dataValue
@@ -48,5 +65,6 @@ dataValue
4865
| tst.js:25:19:25:22 | data |
4966
| tst.js:33:17:33:20 | data |
5067
| tst.js:38:10:38:13 | data |
68+
| tst.js:51:30:51:33 | data |
5169
| tst.js:58:16:58:16 | x |
5270
| tst.js:68:16:68:19 | data |

javascript/ql/test/library-tests/TypeTracking/tst.js

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,3 +76,40 @@ function useConnection() {
7676
}
7777

7878
export const exportedConnection = getConnection();
79+
80+
function outer(conn) {
81+
function innerCapture() {
82+
return conn;
83+
}
84+
function innerCall(x) {
85+
return x;
86+
}
87+
88+
innerCapture();
89+
innerCall(conn);
90+
innerCall(somethingElse());
91+
92+
function otherInner() {
93+
innerCapture();
94+
}
95+
return class {
96+
get() { return conn }
97+
}
98+
}
99+
outer(getConnection());
100+
new (outer(getConnection())).get();
101+
new (outer(somethingElse())).get();
102+
103+
function shared(x) {
104+
return (function() {
105+
return x;
106+
})();
107+
}
108+
shared(getConnection());
109+
shared(somethingElse());
110+
111+
function getX(obj) {
112+
return obj.x;
113+
}
114+
getX({ x: getConnection() });
115+
getX({ x: somethingElse() });

javascript/ql/test/library-tests/frameworks/Electron/BrowserObject.expected

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,9 @@
66
| electron.js:4:10:4:46 | new Bro ... s: {}}) |
77
| electron.js:35:14:35:14 | x |
88
| electron.js:36:12:36:12 | x |
9+
| electron.js:39:1:39:7 | foo(bw) |
910
| electron.js:39:5:39:6 | bw |
11+
| electron.js:40:1:40:7 | foo(bv) |
1012
| electron.js:40:5:40:6 | bv |
1113
| electron.ts:3:12:3:13 | bw |
1214
| electron.ts:3:40:3:41 | bv |

0 commit comments

Comments
 (0)