Skip to content

Commit 4224947

Browse files
committed
wip
1 parent d25f9a0 commit 4224947

File tree

5 files changed

+89
-42
lines changed

5 files changed

+89
-42
lines changed

rust/ql/lib/codeql/rust/internal/PathResolution.qll

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1520,11 +1520,11 @@ private predicate builtin(string name, ItemNode i) {
15201520

15211521
/** Provides predicates for debugging the path resolution implementation. */
15221522
private module Debug {
1523-
private Locatable getRelevantLocatable() {
1523+
Locatable getRelevantLocatable() {
15241524
exists(string filepath, int startline, int startcolumn, int endline, int endcolumn |
15251525
result.getLocation().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) and
1526-
filepath.matches("%/test.rs") and
1527-
startline = 74
1526+
filepath.matches("%/main.rs") and
1527+
startline = 52
15281528
)
15291529
}
15301530

@@ -1570,4 +1570,20 @@ private module Debug {
15701570
result = i.getCanonicalPath(c) and
15711571
i = getRelevantLocatable()
15721572
}
1573+
1574+
private predicate sdff(ImplItemNode i, Struct s) {
1575+
s = i.resolveSelfTy() and
1576+
s.getName().getText() = "File" and
1577+
s.getFile().getBaseName() = "file.rs"
1578+
}
1579+
1580+
private predicate sdff2(ImplItemNode i) {
1581+
i.getSelfPath().toStringDebug() = "File" and
1582+
i.getTraitPath().toStringDebug() = "Read" and
1583+
i.getLocation().getFile().getBaseName() = "fs.rs"
1584+
}
1585+
1586+
private predicate sdff3(Crate c, SourceFile f) { c.getName() = "alloc" and f = c.getSourceFile() }
1587+
1588+
private predicate sdfsdfsf(File f) { f.getAbsolutePath().matches("%/prelude/mod.rs") }
15731589
}

rust/ql/lib/codeql/rust/internal/TypeInference.qll

Lines changed: 31 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1250,6 +1250,7 @@ import MethodCall
12501250
* Holds if a method for `type` with the name `name` and the arity `arity`
12511251
* exists in `impl`.
12521252
*/
1253+
pragma[nomagic]
12531254
private predicate methodCandidate(Type type, string name, int arity, Impl impl) {
12541255
type = impl.getSelfTy().(TypeMention).resolveType() and
12551256
exists(Function f |
@@ -1269,12 +1270,31 @@ private predicate methodCandidateTrait(Type type, Trait trait, string name, int
12691270
methodCandidate(type, name, arity, impl)
12701271
}
12711272

1273+
pragma[nomagic]
1274+
private predicate isMethodCall(MethodCall mc, Type rootType, string name, int arity) {
1275+
rootType = mc.getTypeAt(TypePath::nil()) and
1276+
name = mc.getMethodName() and
1277+
arity = mc.getArity()
1278+
}
1279+
1280+
pragma[nomagic]
1281+
private predicate universalMethodCandidate(string name, int arity, Impl impl) {
1282+
methodCandidate(any(TypeParameter tp), name, arity, impl)
1283+
}
1284+
12721285
private module IsInstantiationOfInput implements IsInstantiationOfInputSig<MethodCall> {
1273-
pragma[nomagic]
1274-
private predicate isMethodCall(MethodCall mc, Type rootType, string name, int arity) {
1275-
rootType = mc.getTypeAt(TypePath::nil()) and
1276-
name = mc.getMethodName() and
1277-
arity = mc.getArity()
1286+
private predicate testisMethodCall(MethodCall mc, Type rootType, string name, int arity) {
1287+
isMethodCall(mc, rootType, name, arity) and
1288+
mc.getLocation().getStartLine() = 310 and
1289+
mc.fromSource()
1290+
}
1291+
1292+
private predicate testpotentialInstantiationOf(
1293+
MethodCall mc, TypeAbstraction impl, TypeMention constraint
1294+
) {
1295+
potentialInstantiationOf(mc, impl, constraint) and
1296+
mc.getLocation().getStartLine() = 310 and
1297+
mc.fromSource()
12781298
}
12791299

12801300
pragma[nomagic]
@@ -1339,6 +1359,12 @@ private Function inferMethodCallTarget(MethodCall mc) {
13391359
or
13401360
// The type of the receiver is an `impl Trait` type.
13411361
result = getTraitMethod(mc.getTypeAt(TypePath::nil()), mc.getMethodName())
1362+
// or
1363+
// exists(string name, int arity, Impl impl |
1364+
// isMethodCall(mc, _, name, arity) and
1365+
// universalMethodCandidate(name, arity, impl) and
1366+
// result = getMethodSuccessor(impl, name)
1367+
// )
13421368
}
13431369

13441370
cached

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

Lines changed: 33 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,15 @@
11
models
2-
| 1 | Summary: lang:core; <_ as crate::convert::From>::from; Argument[0]; ReturnValue; value |
3-
| 2 | Summary: lang:core; <crate::option::Option>::unwrap; Argument[self].Field[crate::option::Option::Some(0)]; ReturnValue; value |
4-
| 3 | Summary: lang:core; <crate::option::Option>::unwrap_or; Argument[0]; ReturnValue; value |
5-
| 4 | Summary: lang:core; <crate::option::Option>::unwrap_or; Argument[self].Field[crate::option::Option::Some(0)]; ReturnValue; value |
6-
| 5 | Summary: lang:core; <crate::option::Option>::unwrap_or_else; Argument[0].ReturnValue; ReturnValue; value |
7-
| 6 | Summary: lang:core; <crate::option::Option>::unwrap_or_else; Argument[self].Field[crate::option::Option::Some(0)]; ReturnValue; value |
8-
| 7 | Summary: lang:core; <crate::result::Result>::err; Argument[self].Field[crate::result::Result::Err(0)]; ReturnValue.Field[crate::option::Option::Some(0)]; value |
9-
| 8 | Summary: lang:core; <crate::result::Result>::expect; Argument[self].Field[crate::result::Result::Ok(0)]; ReturnValue; value |
10-
| 9 | Summary: lang:core; <crate::result::Result>::expect_err; Argument[self].Field[crate::result::Result::Err(0)]; ReturnValue; value |
11-
| 10 | Summary: lang:core; <crate::result::Result>::ok; Argument[self].Field[crate::result::Result::Ok(0)]; ReturnValue.Field[crate::option::Option::Some(0)]; value |
2+
| 1 | Summary: lang:alloc; <crate::boxed::Box>::new; Argument[0]; ReturnValue.Reference; value |
3+
| 2 | Summary: lang:core; <_ as crate::convert::From>::from; Argument[0]; ReturnValue; value |
4+
| 3 | Summary: lang:core; <crate::option::Option>::unwrap; Argument[self].Field[crate::option::Option::Some(0)]; ReturnValue; value |
5+
| 4 | Summary: lang:core; <crate::option::Option>::unwrap_or; Argument[0]; ReturnValue; value |
6+
| 5 | Summary: lang:core; <crate::option::Option>::unwrap_or; Argument[self].Field[crate::option::Option::Some(0)]; ReturnValue; value |
7+
| 6 | Summary: lang:core; <crate::option::Option>::unwrap_or_else; Argument[0].ReturnValue; ReturnValue; value |
8+
| 7 | Summary: lang:core; <crate::option::Option>::unwrap_or_else; Argument[self].Field[crate::option::Option::Some(0)]; ReturnValue; value |
9+
| 8 | Summary: lang:core; <crate::result::Result>::err; Argument[self].Field[crate::result::Result::Err(0)]; ReturnValue.Field[crate::option::Option::Some(0)]; value |
10+
| 9 | Summary: lang:core; <crate::result::Result>::expect; Argument[self].Field[crate::result::Result::Ok(0)]; ReturnValue; value |
11+
| 10 | Summary: lang:core; <crate::result::Result>::expect_err; Argument[self].Field[crate::result::Result::Err(0)]; ReturnValue; value |
12+
| 11 | Summary: lang:core; <crate::result::Result>::ok; Argument[self].Field[crate::result::Result::Ok(0)]; ReturnValue.Field[crate::option::Option::Some(0)]; value |
1213
edges
1314
| main.rs:22:9:22:9 | s | main.rs:23:10:23:10 | s | provenance | |
1415
| main.rs:22:13:22:21 | source(...) | main.rs:22:9:22:9 | s | provenance | |
@@ -22,6 +23,10 @@ edges
2223
| main.rs:48:15:48:23 | source(...) | main.rs:47:9:47:9 | b | provenance | |
2324
| main.rs:56:5:56:5 | i | main.rs:57:10:57:10 | i | provenance | |
2425
| main.rs:56:9:56:17 | source(...) | main.rs:56:5:56:5 | i | provenance | |
26+
| main.rs:89:9:89:9 | i [&ref] | main.rs:90:11:90:11 | i [&ref] | provenance | |
27+
| main.rs:89:13:89:31 | ...::new(...) [&ref] | main.rs:89:9:89:9 | i [&ref] | provenance | |
28+
| main.rs:89:22:89:30 | source(...) | main.rs:89:13:89:31 | ...::new(...) [&ref] | provenance | MaD:1 |
29+
| main.rs:90:11:90:11 | i [&ref] | main.rs:90:10:90:11 | * ... | provenance | |
2530
| main.rs:97:9:97:9 | a [tuple.0] | main.rs:98:10:98:10 | a [tuple.0] | provenance | |
2631
| main.rs:97:13:97:26 | TupleExpr [tuple.0] | main.rs:97:9:97:9 | a [tuple.0] | provenance | |
2732
| main.rs:97:14:97:22 | source(...) | main.rs:97:13:97:26 | TupleExpr [tuple.0] | provenance | |
@@ -95,43 +100,43 @@ edges
95100
| main.rs:229:11:229:12 | s1 [Some] | main.rs:230:9:230:15 | Some(...) [Some] | provenance | |
96101
| main.rs:230:9:230:15 | Some(...) [Some] | main.rs:230:14:230:14 | n | provenance | |
97102
| main.rs:230:14:230:14 | n | main.rs:230:25:230:25 | n | provenance | |
98-
| main.rs:240:9:240:10 | s1 [Some] | main.rs:241:10:241:20 | s1.unwrap() | provenance | MaD:2 |
103+
| main.rs:240:9:240:10 | s1 [Some] | main.rs:241:10:241:20 | s1.unwrap() | provenance | MaD:3 |
99104
| main.rs:240:14:240:29 | Some(...) [Some] | main.rs:240:9:240:10 | s1 [Some] | provenance | |
100105
| main.rs:240:19:240:28 | source(...) | main.rs:240:14:240:29 | Some(...) [Some] | provenance | |
101-
| main.rs:245:9:245:10 | s1 [Some] | main.rs:246:10:246:24 | s1.unwrap_or(...) | provenance | MaD:4 |
106+
| main.rs:245:9:245:10 | s1 [Some] | main.rs:246:10:246:24 | s1.unwrap_or(...) | provenance | MaD:5 |
102107
| main.rs:245:14:245:29 | Some(...) [Some] | main.rs:245:9:245:10 | s1 [Some] | provenance | |
103108
| main.rs:245:19:245:28 | source(...) | main.rs:245:14:245:29 | Some(...) [Some] | provenance | |
104-
| main.rs:249:23:249:32 | source(...) | main.rs:249:10:249:33 | s2.unwrap_or(...) | provenance | MaD:3 |
105-
| main.rs:253:9:253:10 | s1 [Some] | main.rs:254:10:254:32 | s1.unwrap_or_else(...) | provenance | MaD:6 |
109+
| main.rs:249:23:249:32 | source(...) | main.rs:249:10:249:33 | s2.unwrap_or(...) | provenance | MaD:4 |
110+
| main.rs:253:9:253:10 | s1 [Some] | main.rs:254:10:254:32 | s1.unwrap_or_else(...) | provenance | MaD:7 |
106111
| main.rs:253:14:253:29 | Some(...) [Some] | main.rs:253:9:253:10 | s1 [Some] | provenance | |
107112
| main.rs:253:19:253:28 | source(...) | main.rs:253:14:253:29 | Some(...) [Some] | provenance | |
108-
| main.rs:257:31:257:40 | source(...) | main.rs:257:10:257:41 | s2.unwrap_or_else(...) | provenance | MaD:5 |
113+
| main.rs:257:31:257:40 | source(...) | main.rs:257:10:257:41 | s2.unwrap_or_else(...) | provenance | MaD:6 |
109114
| main.rs:261:9:261:10 | s1 [Some] | main.rs:263:14:263:15 | s1 [Some] | provenance | |
110115
| main.rs:261:14:261:29 | Some(...) [Some] | main.rs:261:9:261:10 | s1 [Some] | provenance | |
111116
| main.rs:261:19:261:28 | source(...) | main.rs:261:14:261:29 | Some(...) [Some] | provenance | |
112117
| main.rs:263:9:263:10 | i1 | main.rs:264:10:264:11 | i1 | provenance | |
113118
| main.rs:263:14:263:15 | s1 [Some] | main.rs:263:14:263:16 | TryExpr | provenance | |
114119
| main.rs:263:14:263:16 | TryExpr | main.rs:263:9:263:10 | i1 | provenance | |
115-
| main.rs:270:9:270:10 | r1 [Ok] | main.rs:271:28:271:34 | r1.ok() [Some] | provenance | MaD:10 |
120+
| main.rs:270:9:270:10 | r1 [Ok] | main.rs:271:28:271:34 | r1.ok() [Some] | provenance | MaD:11 |
116121
| main.rs:270:32:270:45 | Ok(...) [Ok] | main.rs:270:9:270:10 | r1 [Ok] | provenance | |
117122
| main.rs:270:35:270:44 | source(...) | main.rs:270:32:270:45 | Ok(...) [Ok] | provenance | |
118-
| main.rs:271:9:271:11 | o1a [Some] | main.rs:273:10:273:21 | o1a.unwrap() | provenance | MaD:2 |
123+
| main.rs:271:9:271:11 | o1a [Some] | main.rs:273:10:273:21 | o1a.unwrap() | provenance | MaD:3 |
119124
| main.rs:271:28:271:34 | r1.ok() [Some] | main.rs:271:9:271:11 | o1a [Some] | provenance | |
120-
| main.rs:276:9:276:10 | r2 [Err] | main.rs:278:28:278:35 | r2.err() [Some] | provenance | MaD:7 |
125+
| main.rs:276:9:276:10 | r2 [Err] | main.rs:278:28:278:35 | r2.err() [Some] | provenance | MaD:8 |
121126
| main.rs:276:32:276:46 | Err(...) [Err] | main.rs:276:9:276:10 | r2 [Err] | provenance | |
122127
| main.rs:276:36:276:45 | source(...) | main.rs:276:32:276:46 | Err(...) [Err] | provenance | |
123-
| main.rs:278:9:278:11 | o2b [Some] | main.rs:280:10:280:21 | o2b.unwrap() | provenance | MaD:2 |
128+
| main.rs:278:9:278:11 | o2b [Some] | main.rs:280:10:280:21 | o2b.unwrap() | provenance | MaD:3 |
124129
| main.rs:278:28:278:35 | r2.err() [Some] | main.rs:278:9:278:11 | o2b [Some] | provenance | |
125130
| main.rs:284:9:284:10 | s1 [Ok] | main.rs:287:14:287:15 | s1 [Ok] | provenance | |
126131
| main.rs:284:32:284:45 | Ok(...) [Ok] | main.rs:284:9:284:10 | s1 [Ok] | provenance | |
127132
| main.rs:284:35:284:44 | source(...) | main.rs:284:32:284:45 | Ok(...) [Ok] | provenance | |
128133
| main.rs:287:9:287:10 | i1 | main.rs:289:10:289:11 | i1 | provenance | |
129134
| main.rs:287:14:287:15 | s1 [Ok] | main.rs:287:14:287:16 | TryExpr | provenance | |
130135
| main.rs:287:14:287:16 | TryExpr | main.rs:287:9:287:10 | i1 | provenance | |
131-
| main.rs:297:9:297:10 | s1 [Ok] | main.rs:298:10:298:22 | s1.expect(...) | provenance | MaD:8 |
136+
| main.rs:297:9:297:10 | s1 [Ok] | main.rs:298:10:298:22 | s1.expect(...) | provenance | MaD:9 |
132137
| main.rs:297:32:297:45 | Ok(...) [Ok] | main.rs:297:9:297:10 | s1 [Ok] | provenance | |
133138
| main.rs:297:35:297:44 | source(...) | main.rs:297:32:297:45 | Ok(...) [Ok] | provenance | |
134-
| main.rs:301:9:301:10 | s2 [Err] | main.rs:303:10:303:26 | s2.expect_err(...) | provenance | MaD:9 |
139+
| main.rs:301:9:301:10 | s2 [Err] | main.rs:303:10:303:26 | s2.expect_err(...) | provenance | MaD:10 |
135140
| main.rs:301:32:301:46 | Err(...) [Err] | main.rs:301:9:301:10 | s2 [Err] | provenance | |
136141
| main.rs:301:36:301:45 | source(...) | main.rs:301:32:301:46 | Err(...) [Err] | provenance | |
137142
| main.rs:312:9:312:10 | s1 [A] | main.rs:314:11:314:12 | s1 [A] | provenance | |
@@ -233,7 +238,7 @@ edges
233238
| main.rs:524:11:524:15 | c_ref [&ref] | main.rs:524:10:524:15 | * ... | provenance | |
234239
| main.rs:528:9:528:9 | a | main.rs:532:20:532:20 | a | provenance | |
235240
| main.rs:528:18:528:27 | source(...) | main.rs:528:9:528:9 | a | provenance | |
236-
| main.rs:532:20:532:20 | a | main.rs:532:10:532:21 | ...::from(...) | provenance | MaD:1 |
241+
| main.rs:532:20:532:20 | a | main.rs:532:10:532:21 | ...::from(...) | provenance | MaD:2 |
237242
nodes
238243
| main.rs:18:10:18:18 | source(...) | semmle.label | source(...) |
239244
| main.rs:22:9:22:9 | s | semmle.label | s |
@@ -253,6 +258,11 @@ nodes
253258
| main.rs:56:5:56:5 | i | semmle.label | i |
254259
| main.rs:56:9:56:17 | source(...) | semmle.label | source(...) |
255260
| main.rs:57:10:57:10 | i | semmle.label | i |
261+
| main.rs:89:9:89:9 | i [&ref] | semmle.label | i [&ref] |
262+
| main.rs:89:13:89:31 | ...::new(...) [&ref] | semmle.label | ...::new(...) [&ref] |
263+
| main.rs:89:22:89:30 | source(...) | semmle.label | source(...) |
264+
| main.rs:90:10:90:11 | * ... | semmle.label | * ... |
265+
| main.rs:90:11:90:11 | i [&ref] | semmle.label | i [&ref] |
256266
| main.rs:97:9:97:9 | a [tuple.0] | semmle.label | a [tuple.0] |
257267
| main.rs:97:13:97:26 | TupleExpr [tuple.0] | semmle.label | TupleExpr [tuple.0] |
258268
| main.rs:97:14:97:22 | source(...) | semmle.label | source(...) |
@@ -507,14 +517,14 @@ nodes
507517
| main.rs:532:20:532:20 | a | semmle.label | a |
508518
subpaths
509519
testFailures
510-
| main.rs:90:15:90:33 | //... | Missing result: hasValueFlow=7 |
511520
#select
512521
| main.rs:18:10:18:18 | source(...) | main.rs:18:10:18:18 | source(...) | main.rs:18:10:18:18 | source(...) | $@ | main.rs:18:10:18:18 | source(...) | source(...) |
513522
| main.rs:23:10:23:10 | s | main.rs:22:13:22:21 | source(...) | main.rs:23:10:23:10 | s | $@ | main.rs:22:13:22:21 | source(...) | source(...) |
514523
| main.rs:30:10:30:10 | c | main.rs:27:13:27:21 | source(...) | main.rs:30:10:30:10 | c | $@ | main.rs:27:13:27:21 | source(...) | source(...) |
515524
| main.rs:39:10:39:10 | b | main.rs:34:13:34:21 | source(...) | main.rs:39:10:39:10 | b | $@ | main.rs:34:13:34:21 | source(...) | source(...) |
516525
| main.rs:50:10:50:10 | b | main.rs:48:15:48:23 | source(...) | main.rs:50:10:50:10 | b | $@ | main.rs:48:15:48:23 | source(...) | source(...) |
517526
| main.rs:57:10:57:10 | i | main.rs:56:9:56:17 | source(...) | main.rs:57:10:57:10 | i | $@ | main.rs:56:9:56:17 | source(...) | source(...) |
527+
| main.rs:90:10:90:11 | * ... | main.rs:89:22:89:30 | source(...) | main.rs:90:10:90:11 | * ... | $@ | main.rs:89:22:89:30 | source(...) | source(...) |
518528
| main.rs:98:10:98:12 | a.0 | main.rs:97:14:97:22 | source(...) | main.rs:98:10:98:12 | a.0 | $@ | main.rs:97:14:97:22 | source(...) | source(...) |
519529
| main.rs:106:10:106:11 | a1 | main.rs:103:17:103:26 | source(...) | main.rs:106:10:106:11 | a1 | $@ | main.rs:103:17:103:26 | source(...) | source(...) |
520530
| main.rs:113:10:113:12 | a.1 | main.rs:111:21:111:30 | source(...) | main.rs:113:10:113:12 | a.1 | $@ | main.rs:111:21:111:30 | source(...) | source(...) |

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

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -101,11 +101,6 @@ nodes
101101
| main.rs:87:18:87:32 | { ... } | semmle.label | { ... } |
102102
subpaths
103103
testFailures
104-
| main.rs:53:10:53:11 | s2 | Fixed missing result: hasValueFlow=36 |
105-
| main.rs:64:16:64:25 | s.as_str() | Fixed missing result: hasValueFlow=67 |
106-
| main.rs:71:10:71:19 | formatted1 | Fixed missing result: hasTaintFlow=88 |
107-
| main.rs:74:10:74:19 | formatted2 | Fixed missing result: hasTaintFlow=88 |
108-
| main.rs:78:10:78:19 | formatted3 | Fixed missing result: hasTaintFlow=10 |
109104
#select
110105
| main.rs:28:16:28:21 | sliced | main.rs:26:13:26:22 | source(...) | main.rs:28:16:28:21 | sliced | $@ | main.rs:26:13:26:22 | source(...) | source(...) |
111106
| main.rs:38:10:38:11 | s4 | main.rs:32:14:32:23 | source(...) | main.rs:38:10:38:11 | s4 | $@ | main.rs:32:14:32:23 | source(...) | source(...) |

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

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -50,32 +50,32 @@ fn string_add_reference() {
5050
fn string_from() {
5151
let s1 = source_slice(36);
5252
let s2 = String::from(s1);
53-
sink(s2); // $ MISSING: hasValueFlow=36 - we need to extract builtins
53+
sink(s2); // $ hasValueFlow=36
5454
}
5555

5656
fn string_to_string() {
5757
let s1 = source_slice(22);
5858
let s2 = s1.to_string();
59-
sink(s2); // $ MISSING: hasTaintFlow=22 - we need to extract builtins
59+
sink(s2); // $ MISSING: hasTaintFlow=22 - we are not currently able to resolve the `to_string` call above, which comes from `impl<T: fmt::Display + ?Sized> ToString for T`
6060
}
6161

6262
fn as_str() {
6363
let s = source(67);
64-
sink_slice(s.as_str()); // $ MISSING: hasValueFlow=67 - we need to extract builtins
64+
sink_slice(s.as_str()); // $ hasValueFlow=67
6565
}
6666

6767
fn format_args_built_in() {
6868
let s = source(88);
6969

7070
let formatted1 = fmt::format(format_args!("Hello {}!", s));
71-
sink(formatted1); // $ MISSING: hasTaintFlow=88 - we need to extract builtins
71+
sink(formatted1); // $hasTaintFlow=88
7272

7373
let formatted2 = fmt::format(format_args!("Hello {s}!"));
74-
sink(formatted2); // $ MISSING: hasTaintFlow=88 - we need to extract builtins
74+
sink(formatted2); // $ hasTaintFlow=88
7575

7676
let width = source_usize(10);
7777
let formatted3 = fmt::format(format_args!("Hello {:width$}!", "World"));
78-
sink(formatted3); // $ MISSING: hasTaintFlow=10 - we need to extract builtins
78+
sink(formatted3); // $ hasTaintFlow=10
7979
}
8080

8181
fn format_macro() {

0 commit comments

Comments
 (0)