Skip to content

Commit fd7cfed

Browse files
committed
JS: Add AdditionalTypeTrackingStep
1 parent 7698240 commit fd7cfed

File tree

7 files changed

+102
-45
lines changed

7 files changed

+102
-45
lines changed

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

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,9 @@ module StepSummary {
8686
basicLoadStep(pred, succ, prop) and
8787
summary = LoadStep(prop)
8888
)
89+
or
90+
any(AdditionalTypeTrackingStep st).step(pred, succ) and
91+
summary = LevelStep()
8992
}
9093
}
9194

@@ -338,3 +341,20 @@ module TypeBackTracker {
338341
*/
339342
TypeBackTracker end() { result.end() }
340343
}
344+
345+
/**
346+
* A data flow edge that should be followed by type tracking.
347+
*
348+
* Unlike `AdditionalFlowStep`, this type of edge does not affect
349+
* the local data flow graph, and is not used by data-flow configurations.
350+
*
351+
* Note: For performance reasons, all subclasses of this class should be part
352+
* of the standard library. For query-specific steps, consider including the
353+
* custom steps in the type-tracking predicate itself.
354+
*/
355+
abstract class AdditionalTypeTrackingStep extends DataFlow::Node {
356+
/**
357+
* Holds if type-tracking should step from `pred` to `succ`.
358+
*/
359+
abstract predicate step(DataFlow::Node pred, DataFlow::Node succ);
360+
}
Lines changed: 26 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,30 @@
11
test_ApiObject
2-
| tst.js:3:11:3:21 | new myapi() |
3-
| tst.js:15:10:15:21 | api.chain1() |
4-
| tst.js:15:10:15:30 | api.cha ... hain2() |
2+
| tst.js:4:11:4:21 | new myapi() |
3+
| tst.js:16:10:16:21 | api.chain1() |
4+
| tst.js:16:10:16:30 | api.cha ... hain2() |
55
test_Connection
6-
| tst.js:6:15:6:18 | conn |
7-
| tst.js:10:5:10:19 | this.connection |
8-
| tst.js:15:10:15:49 | api.cha ... ction() |
9-
| tst.js:18:7:18:21 | getConnection() |
10-
| tst.js:30:9:30:23 | getConnection() |
11-
| tst.js:39:7:39:21 | getConnection() |
12-
| tst.js:47:7:47:21 | getConnection() |
6+
| tst.js:7:15:7:18 | conn |
7+
| tst.js:11:5:11:19 | this.connection |
8+
| tst.js:16:10:16:49 | api.cha ... ction() |
9+
| tst.js:19:7:19:21 | getConnection() |
10+
| tst.js:31:9:31:23 | getConnection() |
11+
| tst.js:40:7:40:21 | getConnection() |
12+
| tst.js:48:7:48:21 | getConnection() |
13+
| tst.js:54:37:54:51 | getConnection() |
14+
| tst.js:57:14:57:48 | config. ... ction') |
1315
test_DataCallback
14-
| tst.js:9:11:9:12 | cb |
15-
| tst.js:20:1:22:1 | functio ... ata);\\n} |
16-
| tst.js:29:26:29:27 | cb |
17-
| tst.js:32:17:32:26 | data => {} |
18-
| tst.js:37:10:37:19 | data => {} |
19-
| tst.js:39:32:39:45 | getDataCurry() |
20-
| tst.js:44:19:44:20 | cb |
21-
| tst.js:47:32:47:60 | identit ... llback) |
16+
| tst.js:10:11:10:12 | cb |
17+
| tst.js:21:1:23:1 | functio ... ata);\\n} |
18+
| tst.js:30:26:30:27 | cb |
19+
| tst.js:33:17:33:26 | data => {} |
20+
| tst.js:38:10:38:19 | data => {} |
21+
| tst.js:40:32:40:45 | getDataCurry() |
22+
| tst.js:45:19:45:20 | cb |
23+
| tst.js:48:32:48:60 | identit ... llback) |
24+
| tst.js:58:16:58:22 | x => {} |
2225
test_DataValue
23-
| tst.js:20:18:20:21 | data |
24-
| tst.js:24:19:24:22 | data |
25-
| tst.js:32:17:32:20 | data |
26-
| tst.js:37:10:37:13 | data |
26+
| tst.js:21:18:21:21 | data |
27+
| tst.js:25:19:25:22 | data |
28+
| tst.js:33:17:33:20 | data |
29+
| tst.js:38:10:38:13 | data |
30+
| tst.js:58:16:58:16 | x |

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import javascript
2+
import CustomStep
23

34
string chainableMethod() {
45
result = "chain1" or
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
import javascript
2+
private import DataFlow
3+
4+
predicate configStep(Node pred, Node succ) {
5+
exists(CallNode setter, CallNode getter |
6+
getter = moduleMember("@test/myconfig", "getConfigValue").getACall() and
7+
setter = moduleMember("@test/myconfig", "setConfigValue").getACall() and
8+
getter.getArgument(0).getStringValue() = setter.getArgument(0).getStringValue() and
9+
pred = setter.getArgument(1) and
10+
succ = getter
11+
)
12+
}
13+
14+
class CustomStep extends AdditionalTypeTrackingStep, Node {
15+
override predicate step(Node pred, Node succ) {
16+
pred = this and
17+
configStep(pred, succ)
18+
}
19+
}
Lines changed: 27 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,31 @@
11
apiObject
2-
| tst.js:3:11:3:21 | new myapi() |
3-
| tst.js:15:10:15:21 | api.chain1() |
4-
| tst.js:15:10:15:30 | api.cha ... hain2() |
2+
| tst.js:4:11:4:21 | new myapi() |
3+
| tst.js:16:10:16:21 | api.chain1() |
4+
| tst.js:16:10:16:30 | api.cha ... hain2() |
55
connection
6-
| type tracker with call steps | tst.js:6:15:6:18 | conn |
7-
| type tracker with call steps | tst.js:10:5:10:19 | this.connection |
8-
| type tracker with call steps with property connection | tst.js:6:14:6:13 | this |
9-
| type tracker without call steps | tst.js:15:10:15:49 | api.cha ... ction() |
10-
| type tracker without call steps | tst.js:18:7:18:21 | getConnection() |
11-
| type tracker without call steps | tst.js:30:9:30:23 | getConnection() |
12-
| type tracker without call steps | tst.js:39:7:39:21 | getConnection() |
13-
| type tracker without call steps | tst.js:47:7:47:21 | getConnection() |
6+
| type tracker with call steps | tst.js:7:15:7:18 | conn |
7+
| type tracker with call steps | tst.js:11:5:11:19 | this.connection |
8+
| type tracker with call steps with property connection | tst.js:7:14:7:13 | this |
9+
| type tracker without call steps | tst.js:16:10:16:49 | api.cha ... ction() |
10+
| type tracker without call steps | tst.js:19:7:19:21 | getConnection() |
11+
| type tracker without call steps | tst.js:31:9:31:23 | getConnection() |
12+
| type tracker without call steps | tst.js:40:7:40:21 | getConnection() |
13+
| type tracker without call steps | tst.js:48:7:48:21 | getConnection() |
14+
| type tracker without call steps | tst.js:54:37:54:51 | getConnection() |
15+
| type tracker without call steps | tst.js:57:14:57:48 | config. ... ction') |
1416
dataCallback
15-
| tst.js:9:11:9:12 | cb |
16-
| tst.js:20:1:22:1 | functio ... ata);\\n} |
17-
| tst.js:29:26:29:27 | cb |
18-
| tst.js:32:17:32:26 | data => {} |
19-
| tst.js:37:10:37:19 | data => {} |
20-
| tst.js:39:32:39:45 | getDataCurry() |
21-
| tst.js:44:19:44:20 | cb |
22-
| tst.js:47:32:47:60 | identit ... llback) |
17+
| tst.js:10:11:10:12 | cb |
18+
| tst.js:21:1:23:1 | functio ... ata);\\n} |
19+
| tst.js:30:26:30:27 | cb |
20+
| tst.js:33:17:33:26 | data => {} |
21+
| tst.js:38:10:38:19 | data => {} |
22+
| tst.js:40:32:40:45 | getDataCurry() |
23+
| tst.js:45:19:45:20 | cb |
24+
| tst.js:48:32:48:60 | identit ... llback) |
25+
| tst.js:58:16:58:22 | x => {} |
2326
dataValue
24-
| tst.js:20:18:20:21 | data |
25-
| tst.js:24:19:24:22 | data |
26-
| tst.js:32:17:32:20 | data |
27-
| tst.js:37:10:37:13 | data |
27+
| tst.js:21:18:21:21 | data |
28+
| tst.js:25:19:25:22 | data |
29+
| tst.js:33:17:33:20 | data |
30+
| tst.js:38:10:38:13 | data |
31+
| tst.js:58:16:58:16 | x |

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import javascript
2+
import CustomStep
23

34
string chainableMethod() {
45
result = "chain1" or

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

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import myapi from "@test/myapi";
2+
import config from "@test/myconfig";
23

34
let api = new myapi();
45

@@ -49,3 +50,10 @@ identity(fakeGetDataCallback);
4950

5051
function realGetDataCallback(data) {} // not found due to missing summarization
5152
function fakeGetDataCallback(notData) {} // should not be found
53+
54+
config.setConfigValue('connection', getConnection());
55+
56+
function getFromConfigFramework() {
57+
let conn = config.getConfigValue('connection');
58+
conn.getData(x => {});
59+
}

0 commit comments

Comments
 (0)