Skip to content

Commit e9bd698

Browse files
committed
Rust: Assume callbacks will be invoked in library functions
1 parent 51f3acf commit e9bd698

4 files changed

Lines changed: 54 additions & 4 deletions

File tree

rust/ql/lib/codeql/rust/dataflow/internal/DataFlowImpl.qll

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -440,7 +440,7 @@ module RustDataFlowGen<RustDataFlowInputSig Input> implements InputSig<Location>
440440
or
441441
result = "self" and this.isSelf()
442442
or
443-
result = "closure self" and this.isClosureSelf()
443+
result = "closure-self" and this.isClosureSelf()
444444
}
445445

446446
ParamBase getParameterIn(ParamList ps) {

rust/ql/lib/codeql/rust/dataflow/internal/ModelsAsData.qll

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,9 @@ private import codeql.rust.dataflow.FlowBarrier
5858
private import codeql.rust.dataflow.FlowSummary
5959
private import codeql.rust.dataflow.FlowSource
6060
private import codeql.rust.dataflow.FlowSink
61+
private import codeql.rust.internal.typeinference.FunctionType
62+
private import codeql.rust.internal.typeinference.TypeMention
63+
private import codeql.rust.frameworks.stdlib.Stdlib
6164

6265
/**
6366
* Holds if in a call to the function with canonical path `path`, the value referred
@@ -207,6 +210,37 @@ private class SummarizedCallableFromModel extends SummarizedCallable::Range {
207210
}
208211
}
209212

213+
/**
214+
* Holds if library function `f` has a callback at position `n`. In this case we
215+
* add a flow model that achieves the effect of simulating that the callback is
216+
* invoked, which is needed for flow through captured variables to work.
217+
*/
218+
private predicate mayInvokeCallback(Function f, int n) {
219+
exists(TypeMention tm, Trait trait |
220+
tm = f.getParam(n).getTypeRepr() and
221+
trait = getALookupTrait(f, tm.getType()) and
222+
trait.getSupertrait*() instanceof FnOnceTrait and
223+
not f.fromSource()
224+
)
225+
}
226+
227+
private class SummarizedCallableWithCallback extends SummarizedCallable::Range {
228+
private int pos;
229+
230+
SummarizedCallableWithCallback() { mayInvokeCallback(this, pos) }
231+
232+
override predicate propagatesFlow(
233+
string input, string output, boolean preservesValue, Provenance p, boolean isExact, string model
234+
) {
235+
input = "Argument[" + pos + "]" and
236+
output = "Argument[" + pos + "].Parameter[closure-self]" and
237+
preservesValue = true and
238+
p = "hq-generated" and
239+
isExact = true and
240+
model = "heuristic-callback"
241+
}
242+
}
243+
210244
private class FlowSourceFromModel extends FlowSource::Range {
211245
private string path;
212246

rust/ql/test/library-tests/dataflow/lambdas/inline-flow.expected

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,12 @@ edges
5555
| main.rs:100:13:100:22 | source(...) | main.rs:100:9:100:9 | b | provenance | |
5656
| main.rs:101:17:101:17 | ... | main.rs:101:25:101:25 | x | provenance | |
5757
| main.rs:101:29:101:29 | b | main.rs:93:33:93:38 | ...: i64 | provenance | |
58+
| main.rs:109:13:109:22 | source(...) | main.rs:110:26:110:36 | \|...\| ... : ... => .. [captured a] | provenance | |
59+
| main.rs:109:13:109:22 | source(...) | main.rs:111:26:111:36 | \|...\| ... : ... => .. [captured a] | provenance | |
60+
| main.rs:109:13:109:22 | source(...) | main.rs:112:26:112:36 | \|...\| ... : ... => .. [captured a] | provenance | |
61+
| main.rs:110:26:110:36 | \|...\| ... : ... => .. [captured a] | main.rs:110:35:110:35 | a | provenance | heuristic-callback |
62+
| main.rs:111:26:111:36 | \|...\| ... : ... => .. [captured a] | main.rs:111:35:111:35 | a | provenance | heuristic-callback |
63+
| main.rs:112:26:112:36 | \|...\| ... : ... => .. [captured a] | main.rs:112:35:112:35 | a | provenance | heuristic-callback |
5864
nodes
5965
| main.rs:10:20:10:52 | if cond {...} else {...} | semmle.label | if cond {...} else {...} |
6066
| main.rs:10:30:10:39 | source(...) | semmle.label | source(...) |
@@ -121,6 +127,13 @@ nodes
121127
| main.rs:101:17:101:17 | ... | semmle.label | ... |
122128
| main.rs:101:25:101:25 | x | semmle.label | x |
123129
| main.rs:101:29:101:29 | b | semmle.label | b |
130+
| main.rs:109:13:109:22 | source(...) | semmle.label | source(...) |
131+
| main.rs:110:26:110:36 | \|...\| ... : ... => .. [captured a] | semmle.label | \|...\| ... : ... => .. [captured a] |
132+
| main.rs:110:35:110:35 | a | semmle.label | a |
133+
| main.rs:111:26:111:36 | \|...\| ... : ... => .. [captured a] | semmle.label | \|...\| ... : ... => .. [captured a] |
134+
| main.rs:111:35:111:35 | a | semmle.label | a |
135+
| main.rs:112:26:112:36 | \|...\| ... : ... => .. [captured a] | semmle.label | \|...\| ... : ... => .. [captured a] |
136+
| main.rs:112:35:112:35 | a | semmle.label | a |
124137
subpaths
125138
| main.rs:29:21:29:21 | a | main.rs:27:20:27:23 | ... | main.rs:27:26:27:52 | if cond {...} else {...} | main.rs:29:13:29:22 | f(...) |
126139
| main.rs:77:21:77:21 | a | main.rs:66:24:66:32 | ...: i64 | main.rs:66:42:72:1 | { ... } | main.rs:77:13:77:22 | f(...) |
@@ -140,3 +153,6 @@ testFailures
140153
| main.rs:99:25:99:25 | x | main.rs:100:13:100:22 | source(...) | main.rs:99:25:99:25 | x | $@ | main.rs:100:13:100:22 | source(...) | source(...) |
141154
| main.rs:101:25:101:25 | x | main.rs:98:13:98:22 | source(...) | main.rs:101:25:101:25 | x | $@ | main.rs:98:13:98:22 | source(...) | source(...) |
142155
| main.rs:101:25:101:25 | x | main.rs:100:13:100:22 | source(...) | main.rs:101:25:101:25 | x | $@ | main.rs:100:13:100:22 | source(...) | source(...) |
156+
| main.rs:110:35:110:35 | a | main.rs:109:13:109:22 | source(...) | main.rs:110:35:110:35 | a | $@ | main.rs:109:13:109:22 | source(...) | source(...) |
157+
| main.rs:111:35:111:35 | a | main.rs:109:13:109:22 | source(...) | main.rs:111:35:111:35 | a | $@ | main.rs:109:13:109:22 | source(...) | source(...) |
158+
| main.rs:112:35:112:35 | a | main.rs:109:13:109:22 | source(...) | main.rs:112:35:112:35 | a | $@ | main.rs:109:13:109:22 | source(...) | source(...) |

rust/ql/test/library-tests/dataflow/lambdas/main.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -107,9 +107,9 @@ use external_file::*;
107107

108108
fn test_external_call() {
109109
let a = source(81);
110-
may_invoke_callback1(|x| sink(a)); // $ MISSING: hasValueFlow=81
111-
may_invoke_callback2(|x| sink(a)); // $ MISSING: hasValueFlow=81
112-
may_invoke_callback3(|x| sink(a)); // $ MISSING: hasValueFlow=81
110+
may_invoke_callback1(|x| sink(a)); // $ hasValueFlow=81
111+
may_invoke_callback2(|x| sink(a)); // $ hasValueFlow=81
112+
may_invoke_callback3(|x| sink(a)); // $ hasValueFlow=81
113113
}
114114

115115
fn main() {

0 commit comments

Comments
 (0)