Skip to content

Commit df03751

Browse files
committed
Rust: Add data flow tests
1 parent 3171752 commit df03751

File tree

11 files changed

+714
-509
lines changed

11 files changed

+714
-509
lines changed
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
11
identityLocalStep
2-
| main.rs:404:7:404:18 | phi(default_name) | Node steps to itself |
2+
| main.rs:394:7:394:18 | phi(default_name) | Node steps to itself |

rust/ql/test/library-tests/dataflow/local/DataFlowStep.expected

Lines changed: 328 additions & 333 deletions
Large diffs are not rendered by default.

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

Lines changed: 153 additions & 153 deletions
Large diffs are not rendered by default.

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

Lines changed: 9 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -225,6 +225,14 @@ fn option_unwrap() {
225225
sink(s1.unwrap()); // $ hasValueFlow=19
226226
}
227227

228+
fn option_unwrap_or() {
229+
let s1 = Some(source(46));
230+
sink(s1.unwrap_or(0)); // $ MISSING: hasValueFlow=46
231+
232+
let s2 = Some(0);
233+
sink(s2.unwrap_or(source(47))); // $ MISSING: hasValueFlow=47
234+
}
235+
228236
fn option_questionmark() -> Option<i64> {
229237
let s1 = Some(source(20));
230238
let s2 = Some(2);
@@ -379,24 +387,6 @@ fn array_assignment() {
379387
sink(mut_arr[0]); // $ SPURIOUS: hasValueFlow=55
380388
}
381389

382-
// -----------------------------------------------------------------------------
383-
// Data flow through mutable borrows
384-
385-
fn read_through_borrow() {
386-
let a = source(21);
387-
let b = &a;
388-
let c = *b;
389-
sink(c); // $ MISSING: hasValueFlow=21
390-
}
391-
392-
fn write_through_borrow() {
393-
let mut a = 1;
394-
sink(a);
395-
let b = &mut a;
396-
*b = source(39);
397-
sink(a); // $ MISSING: hasValueFlow=39
398-
}
399-
400390
// Test data flow inconsistency occuring with captured variables and `continue`
401391
// in a loop.
402392
pub fn captured_variable_and_continue(names: Vec<(bool, Option<String>)>) {
@@ -430,6 +420,7 @@ fn main() {
430420
option_pattern_match_qualified();
431421
option_pattern_match_unqualified();
432422
option_unwrap();
423+
option_unwrap_or();
433424
option_questionmark();
434425
let _ = result_questionmark();
435426
custom_tuple_enum_pattern_match_qualified();
@@ -443,7 +434,5 @@ fn main() {
443434
array_for_loop();
444435
array_slice_pattern();
445436
array_assignment();
446-
read_through_borrow();
447-
write_through_borrow();
448437
captured_variable_and_continue(vec![]);
449438
}
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
models
2+
edges
3+
| main.rs:40:18:40:21 | SelfParam [MyNumber] | main.rs:42:13:42:38 | ...::MyNumber(...) [MyNumber] | provenance | |
4+
| main.rs:42:13:42:38 | ...::MyNumber(...) [MyNumber] | main.rs:42:32:42:37 | number | provenance | |
5+
| main.rs:42:32:42:37 | number | main.rs:40:31:46:5 | { ... } | provenance | |
6+
| main.rs:58:21:58:50 | ...::MyNumber(...) [MyNumber] | main.rs:59:10:59:18 | my_number [MyNumber] | provenance | |
7+
| main.rs:58:40:58:49 | source(...) | main.rs:58:21:58:50 | ...::MyNumber(...) [MyNumber] | provenance | |
8+
| main.rs:59:10:59:18 | my_number [MyNumber] | main.rs:40:18:40:21 | SelfParam [MyNumber] | provenance | |
9+
| main.rs:59:10:59:18 | my_number [MyNumber] | main.rs:59:10:59:30 | my_number.to_number(...) | provenance | |
10+
nodes
11+
| main.rs:40:18:40:21 | SelfParam [MyNumber] | semmle.label | SelfParam [MyNumber] |
12+
| main.rs:40:31:46:5 | { ... } | semmle.label | { ... } |
13+
| main.rs:42:13:42:38 | ...::MyNumber(...) [MyNumber] | semmle.label | ...::MyNumber(...) [MyNumber] |
14+
| main.rs:42:32:42:37 | number | semmle.label | number |
15+
| main.rs:58:21:58:50 | ...::MyNumber(...) [MyNumber] | semmle.label | ...::MyNumber(...) [MyNumber] |
16+
| main.rs:58:40:58:49 | source(...) | semmle.label | source(...) |
17+
| main.rs:59:10:59:18 | my_number [MyNumber] | semmle.label | my_number [MyNumber] |
18+
| main.rs:59:10:59:30 | my_number.to_number(...) | semmle.label | my_number.to_number(...) |
19+
subpaths
20+
| main.rs:59:10:59:18 | my_number [MyNumber] | main.rs:40:18:40:21 | SelfParam [MyNumber] | main.rs:40:31:46:5 | { ... } | main.rs:59:10:59:30 | my_number.to_number(...) |
21+
testFailures
22+
#select
23+
| main.rs:59:10:59:30 | my_number.to_number(...) | main.rs:58:40:58:49 | source(...) | main.rs:59:10:59:30 | my_number.to_number(...) | $@ | main.rs:58:40:58:49 | source(...) | source(...) |
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
/**
2+
* @kind path-problem
3+
*/
4+
5+
import rust
6+
import utils.InlineFlowTest
7+
import DefaultFlowTest
8+
import ValueFlow::PathGraph
9+
10+
from ValueFlow::PathNode source, ValueFlow::PathNode sink
11+
where ValueFlow::flowPath(source, sink)
12+
select sink, source, sink, "$@", source, source.toString()
Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
// -----------------------------------------------------------------------------
2+
// Data flow through pointers.
3+
4+
fn source(i: i64) -> i64 {
5+
1000 + i
6+
}
7+
8+
fn sink(s: i64) {
9+
println!("{}", s);
10+
}
11+
12+
fn read_through_borrow() {
13+
let a = source(21);
14+
let b = &a;
15+
let c = *b;
16+
sink(c); // $ MISSING: hasValueFlow=21
17+
}
18+
19+
fn write_through_borrow() {
20+
let mut a = 1;
21+
sink(a);
22+
let b = &mut a;
23+
*b = source(39);
24+
sink(a); // $ MISSING: hasValueFlow=39
25+
}
26+
27+
fn write_and_read_through_borrow() {
28+
let mut a = 12;
29+
let b = &mut a;
30+
sink(*b);
31+
*b = source(37);
32+
sink(*b); // $ MISSING: hasValueFlow=37
33+
}
34+
35+
enum MyNumber {
36+
MyNumber(i64)
37+
}
38+
39+
impl MyNumber {
40+
fn to_number(self) -> i64 {
41+
match self {
42+
MyNumber::MyNumber(number) => {
43+
number
44+
}
45+
}
46+
}
47+
48+
fn get_number(&self) -> i64 {
49+
match self {
50+
MyNumber::MyNumber(number) => {
51+
*number
52+
}
53+
}
54+
}
55+
}
56+
57+
fn through_self_in_method_no_borrow() {
58+
let my_number = MyNumber::MyNumber(source(33));
59+
sink(my_number.to_number()); // $ hasValueFlow=33
60+
}
61+
62+
fn through_self_in_method_implicit_borrow() {
63+
let my_number = MyNumber::MyNumber(source(85));
64+
sink(my_number.get_number()); // $ MISSING: hasValueFlow=85
65+
}
66+
67+
fn through_self_in_method_explicit_borrow() {
68+
let my_number = &MyNumber::MyNumber(source(40));
69+
sink(my_number.get_number()); // $ MISSING: hasValueFlow=40
70+
}
71+
72+
fn main() {
73+
read_through_borrow();
74+
write_through_borrow();
75+
write_and_read_through_borrow();
76+
through_self_in_method_no_borrow();
77+
through_self_in_method_implicit_borrow();
78+
through_self_in_method_explicit_borrow();
79+
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
models
2+
edges
3+
| main.rs:26:14:26:23 | source(...) | main.rs:32:10:32:11 | s4 | provenance | |
4+
nodes
5+
| main.rs:26:14:26:23 | source(...) | semmle.label | source(...) |
6+
| main.rs:32:10:32:11 | s4 | semmle.label | s4 |
7+
subpaths
8+
testFailures
9+
#select
10+
| main.rs:32:10:32:11 | s4 | main.rs:26:14:26:23 | source(...) | main.rs:32:10:32:11 | s4 | $@ | main.rs:26:14:26:23 | source(...) | source(...) |
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
/**
2+
* @kind path-problem
3+
*/
4+
5+
import rust
6+
import utils.InlineFlowTest
7+
import DefaultFlowTest
8+
import TaintFlow::PathGraph
9+
10+
from TaintFlow::PathNode source, TaintFlow::PathNode sink
11+
where TaintFlow::flowPath(source, sink)
12+
select sink, source, sink, "$@", source, source.toString()
Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
// Taint tests for strings
2+
3+
fn source(i: i64) -> String {
4+
format!("{}", i)
5+
}
6+
7+
fn source_slice(_i: i64) -> &'static str {
8+
"source"
9+
}
10+
11+
fn sink_slice(s: &str) {
12+
println!("{}", s);
13+
}
14+
15+
fn sink(s: String) {
16+
println!("{}", s);
17+
}
18+
19+
fn string_slice() {
20+
let s = source(35);
21+
let sliced = &s[1..3];
22+
sink_slice(sliced); // $ MISSING: hasTaintFlow=35
23+
}
24+
25+
fn string_add() {
26+
let s1 = source(83);
27+
let s2 = "2".to_owned();
28+
let s3 = "3";
29+
let s4 = s1 + s3;
30+
let s5 = s2 + s3;
31+
32+
sink(s4); // $ hasTaintFlow=83
33+
sink(s5);
34+
}
35+
36+
fn string_add_reference() {
37+
let s1 = source(37);
38+
let s2 = "1".to_string();
39+
40+
sink("Hello ".to_string() + &s1); // $ MISSING: hasTaintFlow=37
41+
sink("Hello ".to_string() + &s2);
42+
}
43+
44+
fn string_from() {
45+
let s1 = source_slice(36);
46+
let s2 = String::from(s1);
47+
sink(s2); // $ MISSING: hasTaintFlow=36
48+
}
49+
50+
fn string_to_string() {
51+
let s1 = source_slice(22);
52+
let s2 = s1.to_string();
53+
sink(s2); // $ MISSING: hasTaintFlow=22
54+
}
55+
56+
fn as_str() {
57+
let s = source(67);
58+
sink_slice(s.as_str()); // $ MISSING: hasTaintFlow=67
59+
}
60+
61+
fn string_format() {
62+
let s1 = source(34);
63+
let s2 = "2";
64+
let s3 = "3";
65+
66+
let s4 = format!("{s1} and {s3}");
67+
let s5 = format!("{s2} and {s3}");
68+
69+
sink_slice(&s4); // $ MISSING: hasTaintFlow=34
70+
sink_slice(&s5);
71+
}
72+
73+
fn main() {
74+
string_slice();
75+
string_add();
76+
string_add_reference();
77+
string_from();
78+
as_str();
79+
string_to_string();
80+
string_format();
81+
}

0 commit comments

Comments
 (0)