Skip to content

Commit 6aad8d6

Browse files
authored
Merge pull request github#8302 from aibaars/type-tracking-smallstep
Ruby: TypeTracker: add smallstep for functions that return their arguments
2 parents c7d624d + 200a965 commit 6aad8d6

File tree

3 files changed

+63
-8
lines changed

3 files changed

+63
-8
lines changed

ruby/ql/lib/codeql/ruby/typetracking/TypeTrackerSpecific.qll

Lines changed: 29 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -11,12 +11,31 @@ class Node = DataFlowPublic::Node;
1111

1212
class TypeTrackingNode = DataFlowPublic::LocalSourceNode;
1313

14+
/** Holds if there is a simple local flow step from `nodeFrom` to `nodeTo` */
1415
predicate simpleLocalFlowStep = DataFlowPrivate::localFlowStepTypeTracker/2;
1516

17+
/**
18+
* Holds if data can flow from `node1` to `node2` in a way that discards call contexts.
19+
*/
1620
predicate jumpStep = DataFlowPrivate::jumpStep/2;
1721

18-
/** Holds if there is a level step from `pred` to `succ`. */
19-
predicate levelStep(Node pred, Node succ) { none() }
22+
/**
23+
* Holds if there is a summarized local flow step from `nodeFrom` to `nodeTo`,
24+
* because there is direct flow from a parameter to a return. That is, summarized
25+
* steps are not applied recursively.
26+
*/
27+
pragma[nomagic]
28+
private predicate summarizedLocalStep(Node nodeFrom, Node nodeTo) {
29+
exists(DataFlowPublic::ParameterNode param, DataFlowPrivate::ReturningNode returnNode |
30+
DataFlowPrivate::LocalFlow::getParameterDefNode(param.getParameter())
31+
.(TypeTrackingNode)
32+
.flowsTo(returnNode) and
33+
callStep(nodeTo.asExpr(), nodeFrom, param)
34+
)
35+
}
36+
37+
/** Holds if there is a level step from `nodeFrom` to `nodeTo`. */
38+
predicate levelStep(Node nodeFrom, Node nodeTo) { summarizedLocalStep(nodeFrom, nodeTo) }
2039

2140
/**
2241
* Gets the name of a possible piece of content. This will usually include things like
@@ -48,6 +67,13 @@ private predicate viableParam(
4867
)
4968
}
5069

70+
private predicate callStep(ExprNodes::CallCfgNode call, Node nodeFrom, Node nodeTo) {
71+
exists(DataFlowDispatch::ParameterPosition pos |
72+
argumentPositionMatch(call, nodeFrom, pos) and
73+
viableParam(call, nodeTo, pos)
74+
)
75+
}
76+
5177
/**
5278
* Holds if `nodeFrom` steps to `nodeTo` by being passed as a parameter in a call.
5379
*
@@ -56,10 +82,7 @@ private predicate viableParam(
5682
* methods is done using API graphs (which uses type tracking).
5783
*/
5884
predicate callStep(Node nodeFrom, Node nodeTo) {
59-
exists(ExprNodes::CallCfgNode call, DataFlowDispatch::ParameterPosition pos |
60-
argumentPositionMatch(call, nodeFrom, pos) and
61-
viableParam(call, nodeTo, pos)
62-
)
85+
callStep(_, nodeFrom, nodeTo)
6386
or
6487
// In normal data-flow, this will be a local flow step. But for type tracking
6588
// we model it as a call step, in order to avoid computing a potential

ruby/ql/test/library-tests/dataflow/type-tracker/TypeTracker.expected

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ track
5656
| type_tracker.rb:14:17:14:23 | "hello" | type tracker with call steps | type_tracker.rb:2:16:2:18 | val |
5757
| type_tracker.rb:14:17:14:23 | "hello" | type tracker with call steps | type_tracker.rb:2:16:2:18 | val |
5858
| type_tracker.rb:14:17:14:23 | "hello" | type tracker with call steps with content field | type_tracker.rb:7:5:9:7 | self in field |
59+
| type_tracker.rb:14:17:14:23 | "hello" | type tracker without call steps | type_tracker.rb:14:5:14:13 | call to field= |
5960
| type_tracker.rb:14:17:14:23 | "hello" | type tracker without call steps | type_tracker.rb:14:17:14:23 | "hello" |
6061
| type_tracker.rb:14:17:14:23 | "hello" | type tracker without call steps | type_tracker.rb:15:10:15:18 | call to field |
6162
| type_tracker.rb:14:17:14:23 | "hello" | type tracker without call steps with content field | type_tracker.rb:14:5:14:7 | [post] var |
@@ -72,19 +73,29 @@ trackEnd
7273
| type_tracker.rb:2:5:5:7 | return return in field= | type_tracker.rb:2:5:5:7 | return return in field= |
7374
| type_tracker.rb:2:5:5:7 | return return in field= | type_tracker.rb:14:5:14:13 | call to field= |
7475
| type_tracker.rb:2:5:5:7 | self (field=) | type_tracker.rb:2:5:5:7 | self (field=) |
76+
| type_tracker.rb:2:5:5:7 | self (field=) | type_tracker.rb:3:9:3:23 | self |
77+
| type_tracker.rb:2:5:5:7 | self (field=) | type_tracker.rb:3:14:3:17 | self |
7578
| type_tracker.rb:2:5:5:7 | self (field=) | type_tracker.rb:7:5:9:7 | self in field |
7679
| type_tracker.rb:2:5:5:7 | self in field= | type_tracker.rb:2:5:5:7 | self in field= |
80+
| type_tracker.rb:2:5:5:7 | self in field= | type_tracker.rb:3:9:3:23 | self |
81+
| type_tracker.rb:2:5:5:7 | self in field= | type_tracker.rb:3:14:3:17 | self |
7782
| type_tracker.rb:2:5:5:7 | self in field= | type_tracker.rb:7:5:9:7 | self in field |
7883
| type_tracker.rb:2:16:2:18 | val | type_tracker.rb:2:5:5:7 | return return in field= |
7984
| type_tracker.rb:2:16:2:18 | val | type_tracker.rb:2:16:2:18 | val |
8085
| type_tracker.rb:2:16:2:18 | val | type_tracker.rb:2:16:2:18 | val |
8186
| type_tracker.rb:2:16:2:18 | val | type_tracker.rb:2:16:2:18 | val |
8287
| type_tracker.rb:2:16:2:18 | val | type_tracker.rb:2:16:2:18 | val |
88+
| type_tracker.rb:2:16:2:18 | val | type_tracker.rb:4:9:4:20 | ... = ... |
89+
| type_tracker.rb:2:16:2:18 | val | type_tracker.rb:4:9:4:20 | ... = ... |
90+
| type_tracker.rb:2:16:2:18 | val | type_tracker.rb:4:18:4:20 | val |
91+
| type_tracker.rb:2:16:2:18 | val | type_tracker.rb:4:18:4:20 | val |
8392
| type_tracker.rb:2:16:2:18 | val | type_tracker.rb:14:5:14:13 | call to field= |
8493
| type_tracker.rb:3:9:3:23 | [post] self | type_tracker.rb:3:9:3:23 | [post] self |
94+
| type_tracker.rb:3:9:3:23 | [post] self | type_tracker.rb:3:14:3:17 | self |
8595
| type_tracker.rb:3:9:3:23 | [post] self | type_tracker.rb:7:5:9:7 | self in field |
8696
| type_tracker.rb:3:9:3:23 | call to puts | type_tracker.rb:3:9:3:23 | call to puts |
8797
| type_tracker.rb:3:9:3:23 | self | type_tracker.rb:3:9:3:23 | self |
98+
| type_tracker.rb:3:9:3:23 | self | type_tracker.rb:3:14:3:17 | self |
8899
| type_tracker.rb:3:9:3:23 | self | type_tracker.rb:7:5:9:7 | self in field |
89100
| type_tracker.rb:3:14:3:17 | [post] self | type_tracker.rb:3:14:3:17 | [post] self |
90101
| type_tracker.rb:3:14:3:17 | self | type_tracker.rb:3:14:3:17 | self |
@@ -93,9 +104,11 @@ trackEnd
93104
| type_tracker.rb:3:14:3:23 | call to field | type_tracker.rb:3:14:3:23 | call to field |
94105
| type_tracker.rb:4:9:4:14 | @field | type_tracker.rb:4:9:4:14 | @field |
95106
| type_tracker.rb:4:18:4:20 | val | type_tracker.rb:2:5:5:7 | return return in field= |
107+
| type_tracker.rb:4:18:4:20 | val | type_tracker.rb:4:9:4:20 | ... = ... |
96108
| type_tracker.rb:4:18:4:20 | val | type_tracker.rb:4:18:4:20 | val |
97109
| type_tracker.rb:4:18:4:20 | val | type_tracker.rb:14:5:14:13 | call to field= |
98110
| type_tracker.rb:7:5:9:7 | &block | type_tracker.rb:7:5:9:7 | &block |
111+
| type_tracker.rb:7:5:9:7 | field | type_tracker.rb:1:1:10:3 | Container |
99112
| type_tracker.rb:7:5:9:7 | field | type_tracker.rb:7:5:9:7 | field |
100113
| type_tracker.rb:7:5:9:7 | return return in field | type_tracker.rb:3:14:3:23 | call to field |
101114
| type_tracker.rb:7:5:9:7 | return return in field | type_tracker.rb:7:5:9:7 | return return in field |
@@ -109,20 +122,36 @@ trackEnd
109122
| type_tracker.rb:12:1:16:3 | m | type_tracker.rb:12:1:16:3 | m |
110123
| type_tracker.rb:12:1:16:3 | return return in m | type_tracker.rb:12:1:16:3 | return return in m |
111124
| type_tracker.rb:12:1:16:3 | self (m) | type_tracker.rb:12:1:16:3 | self (m) |
125+
| type_tracker.rb:12:1:16:3 | self (m) | type_tracker.rb:15:5:15:18 | self |
112126
| type_tracker.rb:12:1:16:3 | self in m | type_tracker.rb:12:1:16:3 | self in m |
127+
| type_tracker.rb:12:1:16:3 | self in m | type_tracker.rb:15:5:15:18 | self |
113128
| type_tracker.rb:13:5:13:7 | var | type_tracker.rb:13:5:13:7 | var |
114129
| type_tracker.rb:13:11:13:19 | Container | type_tracker.rb:13:11:13:19 | Container |
115130
| type_tracker.rb:13:11:13:19 | [post] Container | type_tracker.rb:13:11:13:19 | [post] Container |
116131
| type_tracker.rb:13:11:13:23 | call to new | type_tracker.rb:2:5:5:7 | self in field= |
132+
| type_tracker.rb:13:11:13:23 | call to new | type_tracker.rb:3:9:3:23 | self |
133+
| type_tracker.rb:13:11:13:23 | call to new | type_tracker.rb:3:14:3:17 | self |
117134
| type_tracker.rb:13:11:13:23 | call to new | type_tracker.rb:7:5:9:7 | self in field |
135+
| type_tracker.rb:13:11:13:23 | call to new | type_tracker.rb:13:5:13:23 | ... = ... |
136+
| type_tracker.rb:13:11:13:23 | call to new | type_tracker.rb:13:5:13:23 | ... = ... |
118137
| type_tracker.rb:13:11:13:23 | call to new | type_tracker.rb:13:11:13:23 | call to new |
138+
| type_tracker.rb:13:11:13:23 | call to new | type_tracker.rb:14:5:14:7 | var |
139+
| type_tracker.rb:13:11:13:23 | call to new | type_tracker.rb:15:10:15:12 | var |
119140
| type_tracker.rb:14:5:14:7 | [post] var | type_tracker.rb:7:5:9:7 | self in field |
120141
| type_tracker.rb:14:5:14:7 | [post] var | type_tracker.rb:14:5:14:7 | [post] var |
142+
| type_tracker.rb:14:5:14:7 | [post] var | type_tracker.rb:15:10:15:12 | var |
121143
| type_tracker.rb:14:5:14:13 | [post] ... = ... | type_tracker.rb:14:5:14:13 | [post] ... = ... |
122144
| type_tracker.rb:14:5:14:13 | __synth__0 | type_tracker.rb:14:5:14:13 | __synth__0 |
123145
| type_tracker.rb:14:5:14:13 | call to field= | type_tracker.rb:14:5:14:13 | call to field= |
124146
| type_tracker.rb:14:17:14:23 | "hello" | type_tracker.rb:2:16:2:18 | val |
125147
| type_tracker.rb:14:17:14:23 | "hello" | type_tracker.rb:2:16:2:18 | val |
148+
| type_tracker.rb:14:17:14:23 | "hello" | type_tracker.rb:4:9:4:20 | ... = ... |
149+
| type_tracker.rb:14:17:14:23 | "hello" | type_tracker.rb:4:18:4:20 | val |
150+
| type_tracker.rb:14:17:14:23 | "hello" | type_tracker.rb:14:5:14:13 | ... = ... |
151+
| type_tracker.rb:14:17:14:23 | "hello" | type_tracker.rb:14:5:14:13 | ... = ... |
152+
| type_tracker.rb:14:17:14:23 | "hello" | type_tracker.rb:14:5:14:13 | __synth__0 |
153+
| type_tracker.rb:14:17:14:23 | "hello" | type_tracker.rb:14:5:14:13 | call to field= |
154+
| type_tracker.rb:14:17:14:23 | "hello" | type_tracker.rb:14:5:14:23 | ... |
126155
| type_tracker.rb:14:17:14:23 | "hello" | type_tracker.rb:14:17:14:23 | "hello" |
127156
| type_tracker.rb:14:17:14:23 | "hello" | type_tracker.rb:15:10:15:18 | call to field |
128157
| type_tracker.rb:15:5:15:18 | [post] self | type_tracker.rb:15:5:15:18 | [post] self |

ruby/ql/test/library-tests/dataflow/type-tracker/TypeTracker.ql

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,9 @@ query predicate track(LocalSourceNode src, TypeTracker t, LocalSourceNode dst) {
1313
exists(TypeTracker t2, LocalSourceNode mid | track(src, t2, mid) and dst = mid.track(t2, t))
1414
}
1515

16-
query predicate trackEnd(LocalSourceNode src, LocalSourceNode dst) {
17-
track(src, TypeTracker::end(), dst)
16+
query predicate trackEnd(LocalSourceNode src, DataFlow::Node dst) {
17+
exists(LocalSourceNode end |
18+
track(src, TypeTracker::end(), end) and
19+
end.flowsTo(dst)
20+
)
1821
}

0 commit comments

Comments
 (0)