willcrichton / flowistry

Flowistry is an IDE plugin for Rust that helps you focus on relevant code.
https://marketplace.visualstudio.com/items?itemName=wcrichton.flowistry
MIT License
1.88k stars 44 forks source link

[PDG] Alias analysis causes imprecise PDGs #93

Open JustusAdam opened 7 months ago

JustusAdam commented 7 months ago

The lifetime based alias analysis inserts on-existent dependencies when a called function's lifetime annotations claim such a dependency exists.

Consider the following example

fn insert_ref<'v, 't: 'v, T>(v: &mut Vec<&'v T>, t: &'t T) {}
fn main() {
    let x = /* some object */;
    let mut v = Vec::new();
    insert_ref(&mut v, &x);
    read(&v);
}

The resulting PDG has an edge from x to the &v argument of read, even though x is never added to the vector.

Implications on async

Perhaps more worryingly this also occurs when async functions are used.

async fn handle(ud1: &UserData, ud2: &mut UserData) {
    read(ud1);
    write(ud2);
}

async fn main() {
    let mut ud1 = get_user_data();
    let mut ud2 = get_user_data();
    handle(&ud1, &mut ud2).await;
}

// external functions
fn read<T>(read: &T);
fn write<T>(written: &mut T);

In this example the PDG shows a connection ud1 -> written which does not actually exist.

Similarly, and perhaps more concerning, the same effect is also visible in the caller, e.g.

async fn handle(ud1: &UserData, ud2: &mut UserData) {
}

async fn main() {
    let mut ud1 = get_user_data();
    let mut ud2 = get_user_data();
    handle(&ud1, &mut ud2).await;
    read(ud1);
    write(ud2);
}

Also has a ud1 -> written edge.

This seems to be caused by into_future and new_unchecked, which is called automatically by the await desugaring.