mirror of
https://github.com/github/codeql.git
synced 2025-12-16 16:53:25 +01:00
288 lines
7.4 KiB
Rust
288 lines
7.4 KiB
Rust
// -----------------------------------------------------------------------------
|
|
// Data flow through borrows and pointers.
|
|
|
|
fn source(i: i64) -> i64 {
|
|
1000 + i
|
|
}
|
|
|
|
fn sink(s: i64) {
|
|
println!("{}", s);
|
|
}
|
|
|
|
// Intraprocedural tests involving immutable borrows
|
|
mod intraprocedural_immutable_borrows {
|
|
use super::{sink, source};
|
|
|
|
pub fn read_through_borrow() {
|
|
let a = source(21);
|
|
let b = &a;
|
|
let c = *b;
|
|
sink(c); // $ hasValueFlow=21
|
|
}
|
|
|
|
fn takes_borrowed_value(&n: &i64) {
|
|
sink(n); // $ hasValueFlow=83
|
|
}
|
|
|
|
pub fn pass_borrowed_value() {
|
|
let val = source(83);
|
|
takes_borrowed_value(&val);
|
|
}
|
|
|
|
pub 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
|
|
}
|
|
|
|
pub fn read_through_ref_pattern() {
|
|
let a = source(21);
|
|
let ref p = a;
|
|
sink(*p); // $ hasValueFlow=21
|
|
}
|
|
|
|
pub fn ref_pattern_in_match() {
|
|
let a = Some(source(17));
|
|
match a {
|
|
Some(ref p) => sink(*p), // $ hasValueFlow=17
|
|
None => (),
|
|
};
|
|
}
|
|
}
|
|
|
|
// Intraprocedural tests involving mutable borrows
|
|
mod intraprocedural_mutable_borrows {
|
|
use super::{sink, source};
|
|
|
|
pub 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
|
|
}
|
|
|
|
pub fn write_through_borrow() {
|
|
let mut a = 1;
|
|
sink(a);
|
|
let b = &mut a;
|
|
*b = source(39);
|
|
sink(a); // $ MISSING: hasValueFlow=39
|
|
}
|
|
|
|
pub fn write_borrow_directly() {
|
|
let mut a = 1;
|
|
sink(a);
|
|
*(&mut a) = source(87);
|
|
sink(a); // $ hasValueFlow=87
|
|
}
|
|
|
|
pub fn clear_through_borrow() {
|
|
let mut to_be_cleared = source(34);
|
|
let p = &mut to_be_cleared;
|
|
*p = 0;
|
|
sink(to_be_cleared); // variable is cleared
|
|
}
|
|
|
|
pub fn write_through_borrow_in_match(cond: bool) {
|
|
let mut a = 1;
|
|
let mut b = 2;
|
|
let c = if cond { &mut a } else { &mut b };
|
|
*c = source(24);
|
|
sink(*c); // $ hasValueFlow=24
|
|
sink(a); // $ MISSING: hasValueFlow=24
|
|
sink(b); // $ MISSING: hasValueFlow=24
|
|
}
|
|
|
|
pub fn write_through_ref_mut() {
|
|
let ref mut a = source(78);
|
|
sink(*a); // $ hasValueFlow=78
|
|
*a = 0;
|
|
sink(*a); // now cleared
|
|
}
|
|
|
|
pub fn mutate_tuple() {
|
|
let mut t = (1, 2, 3);
|
|
sink(t.1);
|
|
let r = &mut t.1;
|
|
*r = source(48);
|
|
sink(t.1); // $ MISSING: hasValueFlow=48
|
|
let r = &mut t.1;
|
|
*r = 0;
|
|
sink(t.1); // now cleared
|
|
}
|
|
|
|
pub fn tuple_match_mut() {
|
|
let mut a = (0, 1);
|
|
sink(a.0);
|
|
sink(a.1);
|
|
match a {
|
|
(ref mut x, ref mut y) => {
|
|
*x = source(71);
|
|
*y = 2;
|
|
}
|
|
}
|
|
sink(a.0); // $ MISSING: hasValueFlow=71
|
|
sink(a.1);
|
|
}
|
|
}
|
|
|
|
#[derive(Copy, Clone)]
|
|
enum MyNumber {
|
|
MyNumber(i64),
|
|
}
|
|
|
|
fn to_number(m: MyNumber) -> i64 {
|
|
match m {
|
|
MyNumber::MyNumber(number) => number,
|
|
}
|
|
}
|
|
|
|
impl MyNumber {
|
|
fn to_number(self) -> i64 {
|
|
match self {
|
|
MyNumber::MyNumber(number) => number,
|
|
}
|
|
}
|
|
|
|
fn get(&self) -> i64 {
|
|
match self {
|
|
&MyNumber::MyNumber(number) => number,
|
|
}
|
|
}
|
|
}
|
|
|
|
// Interprocedural tests involving immutable borrows
|
|
mod interprocedural_immutable_borrows {
|
|
use super::*;
|
|
|
|
pub fn through_self_in_method_no_borrow() {
|
|
let my_number = MyNumber::MyNumber(source(33));
|
|
sink(my_number.to_number()); // $ hasValueFlow=33
|
|
}
|
|
|
|
pub fn through_self_in_method_explicit_borrow() {
|
|
let my_number = MyNumber::MyNumber(source(40));
|
|
sink((&my_number).get()); // $ hasValueFlow=40
|
|
}
|
|
|
|
pub fn through_self_in_method_implicit_borrow() {
|
|
let my_number = MyNumber::MyNumber(source(85));
|
|
// Implicit borrow
|
|
sink(my_number.get()); // $ hasValueFlow=85
|
|
}
|
|
|
|
pub fn through_self_in_method_implicit_deref() {
|
|
let my_number = &MyNumber::MyNumber(source(58));
|
|
// Implicit dereference
|
|
sink(my_number.to_number()); // $ hasValueFlow=58
|
|
}
|
|
}
|
|
|
|
// Interprocedural tests involving mutable borrows
|
|
mod interprocedural_mutable_borrows {
|
|
use super::*;
|
|
|
|
fn set_int(n: &mut i64, value: i64) {
|
|
*n = value;
|
|
}
|
|
|
|
pub fn mutates_existing_borrow() {
|
|
// Passing an already borrowed value to a function and then reading from
|
|
// the same borrow.
|
|
let mut n = 0;
|
|
let p = &mut n;
|
|
sink(*p);
|
|
set_int(p, source(38));
|
|
sink(*p); // $ hasValueFlow=38
|
|
}
|
|
|
|
pub fn mutate_primitive_through_function() {
|
|
// Borrowing at the call and then reading from the unborrowed variable.
|
|
let mut n = 0;
|
|
sink(n);
|
|
set_int(&mut n, source(55));
|
|
sink(n); // $ hasValueFlow=55
|
|
}
|
|
|
|
impl MyNumber {
|
|
fn set(&mut self, number: i64) {
|
|
*self = MyNumber::MyNumber(number);
|
|
}
|
|
}
|
|
|
|
fn set_number(n: &mut MyNumber, number: i64) {
|
|
*n = MyNumber::MyNumber(number);
|
|
}
|
|
|
|
pub fn mutate_enum_through_function() {
|
|
let mut my_number = MyNumber::MyNumber(0);
|
|
set_number(&mut my_number, source(64));
|
|
sink(my_number.get()); // $ hasValueFlow=64
|
|
set_number(&mut my_number, 0);
|
|
sink(my_number.get()); // $ SPURIOUS: hasValueFlow=64
|
|
}
|
|
|
|
pub fn mutate_enum_through_method_implicit_borrow() {
|
|
let mut my_number = MyNumber::MyNumber(0);
|
|
// Implicit borrow.
|
|
my_number.set(source(45));
|
|
sink(to_number(my_number)); // $ hasValueFlow=45
|
|
my_number.set(0);
|
|
sink(to_number(my_number)); // $ SPURIOUS: hasValueFlow=45
|
|
}
|
|
|
|
pub fn mutate_enum_through_method_explicit_borrow() {
|
|
let mut my_number = MyNumber::MyNumber(0);
|
|
// Explicit borrow.
|
|
(&mut my_number).set(source(99));
|
|
sink(to_number(my_number)); // $ hasValueFlow=99
|
|
(&mut my_number).set(0);
|
|
sink(to_number(my_number)); // $ SPURIOUS: hasValueFlow=99
|
|
}
|
|
}
|
|
|
|
use interprocedural_immutable_borrows::*;
|
|
use interprocedural_mutable_borrows::*;
|
|
use intraprocedural_immutable_borrows::*;
|
|
use intraprocedural_mutable_borrows::*;
|
|
|
|
fn main() {
|
|
read_through_borrow();
|
|
write_through_borrow();
|
|
write_borrow_directly();
|
|
clear_through_borrow();
|
|
write_through_borrow_in_match(true);
|
|
write_and_read_through_borrow();
|
|
pass_borrowed_value();
|
|
through_self_in_method_no_borrow();
|
|
through_self_in_method_explicit_borrow();
|
|
through_self_in_method_implicit_borrow();
|
|
through_self_in_method_implicit_deref();
|
|
mutates_existing_borrow();
|
|
mutate_primitive_through_function();
|
|
mutate_enum_through_function();
|
|
mutate_enum_through_method_implicit_borrow();
|
|
mutate_enum_through_method_explicit_borrow();
|
|
ref_nested_pattern_match();
|
|
read_through_ref_pattern();
|
|
write_through_ref_mut();
|
|
ref_pattern_in_match();
|
|
mutate_tuple();
|
|
tuple_match_mut();
|
|
}
|