mirror of
https://github.com/github/codeql.git
synced 2025-12-17 01:03:14 +01:00
To do this we: * Let SSA writes target the name inside identifier patterns instead of the pattern itself * Include relevant names in the data flow graph * Add a store step from a identifier patterns with `ref` into the contained name. So we have an edge `ref a` -> `a` that stores in the reference content type.
137 lines
2.9 KiB
Rust
137 lines
2.9 KiB
Rust
// -----------------------------------------------------------------------------
|
|
// Data flow through borrows and pointers.
|
|
|
|
fn source(i: i64) -> i64 {
|
|
1000 + i
|
|
}
|
|
|
|
fn sink(s: i64) {
|
|
println!("{}", s);
|
|
}
|
|
|
|
fn read_through_borrow() {
|
|
let a = source(21);
|
|
let b = &a;
|
|
let c = *b;
|
|
sink(c); // $ hasValueFlow=21
|
|
}
|
|
|
|
fn write_through_borrow() {
|
|
let mut a = 1;
|
|
sink(a);
|
|
let b = &mut a;
|
|
*b = source(39);
|
|
sink(a); // $ MISSING: hasValueFlow=39
|
|
}
|
|
|
|
fn write_and_read_through_borrow() {
|
|
let mut a = 12;
|
|
let b = &mut a;
|
|
sink(*b);
|
|
*b = source(37);
|
|
sink(*b); // $ hasValueFlow=37
|
|
*b = 0;
|
|
sink(*b); // now cleared
|
|
}
|
|
|
|
fn takes_borrowed_value(&n: &i64) {
|
|
sink(n); // $ hasValueFlow=83
|
|
}
|
|
|
|
fn pass_borrowed_value() {
|
|
let val = source(83);
|
|
takes_borrowed_value(&val);
|
|
}
|
|
|
|
mod test_ref_pattern {
|
|
use super::{sink, source};
|
|
|
|
pub fn read_through_ref() {
|
|
let a = source(21);
|
|
let ref p = a;
|
|
sink(*p); // $ hasValueFlow=21
|
|
}
|
|
|
|
pub fn write_through_ref_mut() {
|
|
let ref mut a = source(78);
|
|
sink(*a); // $ hasValueFlow=78
|
|
*a = 0;
|
|
sink(*a); // now cleared
|
|
}
|
|
|
|
pub fn ref_pattern_in_match() {
|
|
let a = Some(source(17));
|
|
let b = match a {
|
|
Some(ref p) => sink(*p), // $ hasValueFlow=17
|
|
None => (),
|
|
};
|
|
}
|
|
}
|
|
|
|
enum MyNumber {
|
|
MyNumber(i64),
|
|
}
|
|
|
|
impl MyNumber {
|
|
fn to_number(self) -> i64 {
|
|
match self {
|
|
MyNumber::MyNumber(number) => number,
|
|
}
|
|
}
|
|
|
|
fn get_number(&self) -> i64 {
|
|
match self {
|
|
&MyNumber::MyNumber(number) => number,
|
|
}
|
|
}
|
|
}
|
|
|
|
fn through_self_in_method_no_borrow() {
|
|
let my_number = MyNumber::MyNumber(source(33));
|
|
sink(my_number.to_number()); // $ hasValueFlow=33
|
|
}
|
|
|
|
fn through_self_in_method_implicit_borrow() {
|
|
let my_number = MyNumber::MyNumber(source(85));
|
|
sink(my_number.get_number()); // $ MISSING: hasValueFlow=85
|
|
}
|
|
|
|
fn through_self_in_method_explicit_borrow() {
|
|
let my_number = &MyNumber::MyNumber(source(40));
|
|
sink(my_number.get_number()); // $ hasValueFlow=40
|
|
}
|
|
|
|
fn ref_nested_pattern_match() {
|
|
let a = &(source(23), 1);
|
|
|
|
// Match "in order", reference pattern then tuple pattern
|
|
let b = match a {
|
|
&(n, _) => n,
|
|
};
|
|
sink(b); // $ hasValueFlow=23
|
|
|
|
// Match "out of order", tuple pattern then deref pattern
|
|
let c = match a {
|
|
(n, _) => match n {
|
|
&i => i,
|
|
},
|
|
};
|
|
sink(c); // $ MISSING: hasValueFlow=23
|
|
}
|
|
|
|
use test_ref_pattern::*;
|
|
|
|
fn main() {
|
|
read_through_borrow();
|
|
write_through_borrow();
|
|
write_and_read_through_borrow();
|
|
pass_borrowed_value();
|
|
through_self_in_method_no_borrow();
|
|
through_self_in_method_implicit_borrow();
|
|
through_self_in_method_explicit_borrow();
|
|
ref_nested_pattern_match();
|
|
read_through_ref();
|
|
write_through_ref_mut();
|
|
ref_pattern_in_match();
|
|
}
|