Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Incorrect support for two-phase borrows #668

Open
xldenis opened this issue Dec 19, 2022 · 9 comments
Open

Incorrect support for two-phase borrows #668

xldenis opened this issue Dec 19, 2022 · 9 comments
Assignees
Labels
bug Something isn't working high-priority Given a high priority known-fix Issue for which we know a fix, that we "just" need to implement. soundness Enhance soundness

Comments

@xldenis
Copy link
Collaborator

xldenis commented Dec 19, 2022

@jhaye reports that the following code creates ill typed why3 code.

use creusot_contracts::*;

/// A sparse map representation over a totally ordered key type.
///
/// Used in [crate::ExecutableReactions]
///
pub struct VecMap<K, V>
where
    K: Eq + Ord,
{
    v: Vec<(K, V)>,
}

impl<K, V> VecMap<K, V>
where
    K: Eq + Ord + DeepModel,
    K::DeepModelTy: OrdLogic,
{
    #[logic]
    #[trusted]
    #[ensures(result.len() == (@self.v).len() &&
              forall<i: Int> i >= 0 && i < (@self.v).len() ==>
              result[i] == (@self.v)[i].0.deep_model())]
    fn key_seq(self) -> Seq<K::DeepModelTy> {
        pearlite! { absurd }
    }

    #[predicate]
    fn is_sorted(self) -> bool {
        pearlite! {
            forall<m: Int, n: Int> m >= 0 && n >= 0 && m < (@self.v).len() && n < (@self.v).len() && m < n ==>
                self.key_seq()[m] < self.key_seq()[n]
        }
    }
}

impl<K, V> VecMap<K, V>
where
    K: Eq + Ord + DeepModel,
    K::DeepModelTy: OrdLogic,
{
    /// Directly insert into the underlying `Vec`. This does not maintain the sorting of elements
    /// by itself.
    #[requires(@idx <= (@self.v).len())]
    #[ensures((@(^self).v).len() == (@self.v).len() + 1)]
    #[ensures(forall<i: Int> 0 <= i && i < @idx ==> (@(^self).v)[i] == (@self.v)[i])]
    #[ensures((@(^self).v)[@idx] == (key, value))]
    #[ensures(forall<i: Int> @idx < i && i < (@(^self).v).len() ==> (@(^self).v)[i] == (@self.v)[i - 1])]
    #[ensures(self.is_sorted() && (@self.v).len() == 0 ==> (^self).is_sorted())]
    #[ensures(self.is_sorted() && (@self.v).len() > 0 && @idx > 0 && @idx < (@self.v).len() &&
              (@self.v)[@idx].0.deep_model() > key.deep_model() &&
              (@self.v)[@idx - 1].0.deep_model() < key.deep_model() ==>
              (^self).is_sorted()
    )]
    #[ensures(self.is_sorted() && (@self.v).len() > 0 && @idx == 0 &&
              (@self.v)[@idx].0.deep_model() > key.deep_model() ==>
              (^self).is_sorted()
    )]
    #[ensures(self.is_sorted() && (@self.v).len() > 0 && @idx == (@self.v).len() &&
              (@self.v)[@idx - 1].0.deep_model() < key.deep_model() ==>
              (^self).is_sorted()
    )]
    fn insert_internal(&mut self, idx: usize, key: K, value: V) {
        self.v.insert(idx, (key, value))
    }
}

/// A vacant Entry.
pub struct VacantEntry<'a, K, V>
where
    K: Ord + Eq,
{
    map: &'a mut VecMap<K, V>,
    key: K,
    index: usize,
}

impl<K, V> VacantEntry<'_, K, V>
where
    K: Ord + Eq + Clone + DeepModel,
    K::DeepModelTy: OrdLogic,
{
    /// Sets the value of the entry with the VacantEntry's key.
    #[requires(self.map.is_sorted())]
    #[requires(@self.index <= (@self.map.v).len())]
    #[requires(forall<i: Int> i >= 0 && i < @self.index ==>
               self.map.key_seq()[i] < self.key.deep_model())]
    #[requires(forall<i: Int> i >= @self.index && i < (@self.map.v).len() ==>
               self.map.key_seq()[i] > self.key.deep_model())]
    #[ensures((^self).map.is_sorted())]
    pub fn insert(&mut self, value: V) {
        self.map
            .insert_internal(self.index, self.key.clone(), value)
    }
}
@jhjourdan
Copy link
Collaborator

Minified example:

extern crate creusot_contracts;
use creusot_contracts::*;

/// A vacant Entry.
pub struct VacantEntry<'a, K>
where
    K: Ord + Eq,
{
    map: &'a mut Vec<K>,
    key: K,
    index: usize,
}

impl<K> VacantEntry<'_, K>
where
    K: Ord + Eq + Clone + DeepModel,
    K::DeepModelTy: OrdLogic,
{
    pub fn insert(&mut self) {
        self.map.insert(self.index, self.key.clone())
    }
}

@jhjourdan
Copy link
Collaborator

That should not be very hard to debug.

Basically, Creusot uses the same temporary variable for self.map and self.index.

@xldenis xldenis added the bug Something isn't working label Sep 11, 2024
@Lysxia
Copy link
Collaborator

Lysxia commented Nov 25, 2024

Is this an instance of #1239 ?

@jhjourdan
Copy link
Collaborator

Probably. But could you please check this specific test case is still an issue?

@Lysxia
Copy link
Collaborator

Lysxia commented Nov 25, 2024

Yes, the error still happens.

@jhjourdan
Copy link
Collaborator

Looking at the coma code generated, this does not seem to be related to #1239. I don't know where this comes from, but this can probably be used for unsoundness.

@jhjourdan jhjourdan added high-priority Given a high priority soundness Enhance soundness labels Nov 25, 2024
@jhjourdan
Copy link
Collaborator

The bug is in compute_ref_place, which computes garbage in this case. This has nothing to do with #1239.

@jhjourdan
Copy link
Collaborator

More generally, our handling of two-phase borrows is broken.

@jhjourdan jhjourdan changed the title Crash reported Incorrect support for two-phase borrows Nov 26, 2024
@jhjourdan jhjourdan self-assigned this Jan 13, 2025
@jhjourdan
Copy link
Collaborator

After discussions, it seems that a solution would be to delay the creation of the prophecy a the activation point of two phases borrows : at this point, the borrowed place should not have moved, and the borrow should not have been used yet.

@jhjourdan jhjourdan added the known-fix Issue for which we know a fix, that we "just" need to implement. label Jan 23, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working high-priority Given a high priority known-fix Issue for which we know a fix, that we "just" need to implement. soundness Enhance soundness
Projects
None yet
Development

No branches or pull requests

3 participants