开发者

Static verification limitations when using pure functions in C# code contracts?

开发者 https://www.devze.com 2023-01-16 07:59 出处:网络
I\'m trying to statically verify the following partial implementation of an array-based stack with code contracts. The method Pop() uses the pure function IsNotEmpty() to ensure that the subsequent ar

I'm trying to statically verify the following partial implementation of an array-based stack with code contracts. The method Pop() uses the pure function IsNotEmpty() to ensure that the subsequent array access will be at/above the lower bound. The static verifier fails and suggests that I add the precondition Contract.Requires(0 <= this.top).

Can anyone explain why the verifier cannot prove the array ac开发者_JAVA技巧cess is valid with respect to the lower bound given the contract IsNotEmpty()?

At first I thought the Contract.Requires(IsNotEmpty()) approach might be incorrect because a subclass could override IsNotEmpty(). However, the verifier still can't prove the array access is valid if I mark the class as sealed.

Update: If I change IsNotEmpty() to a read-only property, the verification succeeds as expected. This raises the question: how / why are read-only properties and pure functions treated differently?

class StackAr<T>
{
    private T[] data;
    private int capacity;

    /// <summary>
    /// the index of the top array element
    /// </summary>
    private int top;

    [ContractInvariantMethod]
    private void ObjectInvariant()
    {
        Contract.Invariant(data != null);
        Contract.Invariant(top < capacity);
        Contract.Invariant(top >= -1);
        Contract.Invariant(capacity == data.Length);
    }

    public StackAr(int capacity)
    {
        Contract.Requires(capacity > 0);
        this.capacity = capacity;
        this.data = new T[capacity];
        top = -1;
    }

    [Pure]
    public bool IsNotEmpty()
    {
        return 0 <= this.top;
    }

    public T Pop()
    {
        Contract.Requires(IsNotEmpty());

        //CodeContracts: Suggested precondition: 
        //Contract.Requires(0 <= this.top);

        T element = data[top];
        top--;
        return element;
    }
}


This should solve the problem:

[Pure]
public bool IsNotEmpty() {
    Contract.Ensures(Contract.Result<bool>() && 0 <= this.top || !Contract.Result<bool>() && 0 > this.top);
    return 0 <= this.top;
}

See this thread on the code contracts forum for more information: Calling a method in Contract.Requires

Edit:

Another solution to this problem, as mentioned in the thread linked above, is the -infer command line option:

Now, inferring the post condition of this method is possible, and in fact we do have the option to do so: try to add -infer ensures on the extra options line in the contract property pane for the static checker.

I have checked, and this does resolve the problem. If you look in the code contracts manual, you'll see that the default option is to only infer property post-conditions. By using this switch, you can tell it to attempt to infer the post-conditions of methods too:

-infer (requires + propertyensures + methodensures) (default=propertyensures)

0

精彩评论

暂无评论...
验证码 换一张
取 消