VeriWeb Project Instructions

Contents

1  Introduction

Welcome! We’d like to thank you again for bidding on this project.

You will be given a small program, and your job is to describe the conditions that are necessary to prevent the program from crashing. For example, a Java program crashes if it dereferences null (a NullPointerException) or uses an illegal array index (an ArrayIndexOutOfBoundsException). If a method in the program dereferences its argument, then you would write a specification that says that the method’s argument must not be null.

To perform this task, you will use a web interface called VeriWeb. VeriWeb lets you write method specifications in a Java-like language, then it tells you whether the specifications you wrote are correct and sufficient.

The job has the following steps:

  1. Read Section 2 of this document carefully.
  2. Perform the warmup task in Section 3 to become acquainted with the tool.
  3. Answer an online quiz to check that you understood the core concepts: http://bit.ly/zSJp5M .
  4. Contact us via vWorker before continuing.
  5. Perform the main task (see Section 5).
  6. Answer a short online survey about your experience.

Note: we wish to learn how long the main task takes. We expect it will take between 1-3 hours. Therefore, we ask that you do not take any breaks when performing the main task. If you have to take a break, please record the time and length of the break. Additionally, we will be monitoring your progress remotely.

If you have any questions about the project, please contact us via vWorker.

2  How to write program specifications

A program specification describes the behavior of a program. A verification tool can check the specification and verify that the program behaves as expected. However, for this to work, the specification must be precise and sufficient.

2.1  Method Specifications

A method specification consists of three parts:

You will write specifications using the Java Modeling Language (JML). We now give some examples.

2.2  Trivial example

Consider the following method:

/** Adds five to its argument. */
public Integer addFive(Integer x) throws IllegalArgumentException{
    if (x < 0){
        throw new IllegalArgumentException("x cannot be negative");
    }   
    return x + 5;
}

It is often possible to determine some of the specifications from the method’s documentation. When the documentation is not comprehensive, you have to determine them yourself.

2.3  Another example

Here is an example of a method specification written in JML, the Java Modeling Language. JML is Java-like, with some additional expressions. The method preconditions and postconditions are written between the method body and the method signature using the @requires, @ensures and @exsures annotations. A method can have multiple clauses of each type. You will use the web interface to write these, instead of inserting them directly in the source code.

class Queue{

    private int currentSize;

    private int theArray[];

    ...

    /**
    * Insert a new item into the queue.
    * @param x the item to insert.
    * @exception Overflow if queue is full.
    **/
    public void enqueue( Object x ) throws RuntimeException
    /*@ requires x != null; */
    /*@ ensures currentSize == \old(currentSize) + 1; */
    /*@ exsures (RuntimeException) \old(currentSize) == theArray.length; */
    {
      if( isFull( ) )
        throw new RuntimeException( "Overflow" );
      if ( ++back == theArray.length )
        back = 0;
      theArray[ back ] = x;
      currentSize++;
    }

    ...
}

2.4  JML syntax

Here is table that describes the JML expressions you will need to know for your task:

ExpressionTypeMeaning
a && bbooleanjust like in Java
a || bbooleanjust like in Java
!abooleanjust like in Java
a ==> bbooleanif a is true, then b is true; equivalent to (!a) || b
\forall decl; pred; exprbooleanused to express that expr holds over the range of values for which pred holds (Section 2.4.2)
\resultsame as the method’s return typethe return value of the method (can only be used in the method’s postcondition)
\old(expr)same as the type of exprrefers to the value of expr at the entry of a method (can only be used in a postcondition)

2.4.1  Implication

Implication, written as ==>, is related to conditional expressions (i.e., if and else). Saying that "a implies b", written in JML as a ==> b, means that if a is true then b must also be true. However, if a is false, b can be anything. In other words, false implies anything. For example, the statement "France is in Asia implies apples are oranges" is a true statement because France is not in Asia.

2.4.2  \forall statement: properties that hold for a range of values

The \forall statement is used to express that a fact holds over a range of values. For example, the following expression states that all of the values in the array array are non-null:

(\forall int i; 0 <= i && i < array.length; array[i] != null);

Notice that the middle expression 0 <= i && i < array.length is used to specify which values of i are important.

You can declare multiple variables in a \forall statement, as in the following example:

(\forall int i,j; 0 <= i && i < j && j < array.length; array[i] != array[j]);

3  Warmup: Using VeriWeb to verify a program

Before starting the main project, you’ll familiarize yourself with the interface by verifying the warmup project FixedSizeSet. FixedSizeSet represents a mutable set of integers between 0 and 7. The walkthrough is meant to introduce and reinforce the main concepts needed to complete the main task. You should spend about 1 hour on the warmup.

Don’t hesitate to ask us questions about the tool, or the process of verification, during the warmup.

VeriWeb is a web interface that checks the program properties that the user writes as method pre- and postconditions. VeriWeb reads the source code (and properties) and warns about properties that might not be always true. VeriWeb also warns about potential runtime exceptions.

VeriWeb is a modular checker: it reasons about code by examining the body of one method at a time. Therefore, VeriWeb both checks and depends on properties. For instance, suppose method A calls method B. If you have not written properties describing the return value of B, VeriWeb may not be able to prove a property about method A.

3.1  Start VeriWeb

VeriWeb is a web interface that checks the program properties that the user writes as method pre- and postconditions. VeriWeb reads the source code (and properties) and warns about properties that might not be always true. VeriWeb also warns about potential runtime exceptions.

VeriWeb is a modular checker: it reasons about code by examining the body of one method at a time. Therefore, VeriWeb both checks and depends on properties. For instance, suppose method A calls method B. If you have not written properties describing the return value of B, VeriWeb may not be able to prove a property about method A.

VeriWeb works best in Chrome and Firefox. Do not use another browser (e.g., Internet Explorer) because the interface may not function properly.

  1. Browse to URL given to you over vWorker.
  2. Enter the username given to you and select the project FixedSizeSet. Click "OK"
  3. If at any point you believe that the tool has stopped working (e.g., drag and drop doesn’t work), try reloading the page. If the problem persists, please contact us.

3.2  Problem 1: Write postconditions for FixedSizeSet()

To begin this project, VeriWeb will ask you to write postconditions for the method FixedSizeSet(). The interface consists of 3 main panels:

3.2.1  Postcondition Problems

A postcondition problem asks you to write expressions that are true when the method returns. Expressions you try are shown in the bottom left of the interface. VeriWeb also tries some postconditions automatically for you. In this case, the tool has guessed a couple postconditions. The conditions are correct, so they are shown in green:

3.2.2  Resizing Panels

You can move the split bars to change the size of the three main information regions. For example, to give yourself more space to see long conditions listed in the lower left, click and drag the vertical slider to the right.

3.2.3  Viewing documentation and specifications

In the source code view, hover your mouse over the FixedSetSet method name underlined in blue. The information panel will show the documentation for the method. As we’ll see later in the walkthrough, the method’s conditions will be also be displayed in the information panel when you hover your mouse over the method in the source code view.

3.2.4  Writing a new property with drag and drop

Even though VeriWeb guesses postconditions, you should also think of other properties that might be true. In this case, the fact that bits is not null when the method returns seems important. Let’s use the drag-and-drop interface to write the condition.

The drag and drop interface lets you assemble conditions by combining condition fragments. The interface consists of three main parts: the condition fragment palette, the scratch pad, and the condition entry box.

The fragment palette contains JML specification fragments with holes that you can fill with other fragments. To use a new fragment, click and drag it from the palette. Try dragging the forall int i fragment to the scratch pad:

Fragments can be dropped onto the scratch pad, or the hole of another fragment:

The scratch pad can contain as many fragments as you want. Use the scratch pad to build up complex fragments, for example:

Removing subfragments

To remove a subfragment from a fragment (and move it elsewhere), hover your mouse over the fragment,

then click and drag the fragment to another location, such as an open hole in a another fragment.

Deleting Fragments

To delete a fragment, click and drag the fragment, dropping it onto the "Delete Fragment" area that appears:

Try deleting all the fragments on the scratch pad.

Submitting the condition

Now that we’ve learned to use the interface, let’s write the condition bits != null:

  1. Click the “Comparison” tab on the fragment palette
  2. Drag the !=null fragment to the condition box.
  3. Click the “Variables” tab on the fragment palette, to see the fields and method argument fragments.
  4. Drag the this.bits fragment and drop it into the hole on the !=null fragment to form the condition this.bits != null.

  5. Click “Submit”
  6. The condition will show in yellow while VeriWeb checks it; when VeriWeb has confirmed that it is correct, it will turn green like the other two conditions.

Click “Next Problem” to move onto the next problem.

3.3  Problem 2: Select preconditions for add(...)

Next, VeriWeb will ask you to select required preconditions from a list of guessed preconditions for the add method, since the method might crash with an exception. To see the warnings, hover your mouse over the source code underlined in red. In this case, 3 warnings will show in the information panel:

Since the “Array index possibly too large” warning would be eliminated if n < bits.length was true, click the checkbox next to the precondition to activate it. After VeriWeb has finished thinking, when you hover your mouse over the underlined source code, you will see that the warning is no longer present.

The other possible precondition, bits.length == 8, is not necessary. Do not activate it. Be careful to not make the preconditions too strict! If you write a precondition that is not true, it might eliminate the warning in the method body, but you will have to change it later when you are working on another part of the code that calls this method.

The set of possible preconditions VeriWeb knows about is not sufficient to eliminate the other two warnings, so we let VeriWeb know about them. Click the “Condition Not Listed” button. In the window that appears, write a short description of the preconditions needed to eliminate the warnings, i.e., that n should be non-negative, and bits should not be null. Click “OK.”

3.4  Problem 3: Write preconditions for add(...)

Next, VeriWeb will have you write preconditions for the method. Note that in the information bar, VeriWeb is notifying you that “There are messages.” By clicking this link, you can see the messages for the problem. In this case, your message from the previous problem will appear.

3.4.1  Messages

Whenever you indicate that a problem cannot be solved, or that an existing specification is incorrect, the VeriWeb interface will ask you to write a short message describing the problem. These messages are made available to you when VeriWeb asks you to fix the problem.

If there are multiple message, VeriWeb will show you a list of source methods. Click on the source method to view to associated message thread.

3.4.2  Typing Conditions

The interface has two interfaces for entering conditions: (1) drag and drop, and (2) textual. You can switch between the two modes using the radio buttons:

Type and submit the following two preconditions.

We suggest that you start with the drag and drop interface because it helps you write syntactically valid conditions. When you are confident you can write conditions on your own, you can switch to textual input. You can always switch back if you want.

When VeriWeb is done thinking, click the “Next Problem Button”.

3.5  Problem 4: Write postconditions for add(...)

Next, VeriWeb will ask you to write postconditions for the method add. In the source code view, you will see the preconditions that are assumed — the precondition that you activated and the two preconditions you just wrote.

For this problem, VeriWeb automatically checks 2 postconditions: VeriWeb displays the condition bits.length == 8 in red since it is not guaranteed to be true given the assumed preconditions. You can hide the condition by clicking the red “X” to the left of the condition. The condition bits[n] == true turns green since it is guaranteed to be true.

Click “Next Problem”.

3.6  Problem 5: Select preconditions for union(...)

Next, VeriWeb will ask you to select preconditions for the method union. Notice that there are 2 areas of the source code underlined in red. Hover your mouse over each to view the warnings. Based on the warnings, it should be clear that both suggested preconditions should be activated. But, as before, these aren’t sufficient, since it also must be true that both other.bits and this.bits are not null, and other.bits.length >= bits.length.

Click the “Condition not listed” button, and write a short textual description of the missing preconditions.

3.7  Problem 6: Write preconditions for union(...)

Next, VeriWeb will ask you to write preconditions for the same method union. Submit the conditions other.bits != null and this.bits != null.

3.7.1  Feedback about incorrect conditions

Next, let’s submit a slightly incorrect precondition. If VeriWeb cannot prove a condition, then there are three possibilities: (1) the condition is false and you should not have written/selected it, (2) the condition is true but you have not yet provided enough other information (such as method pre- or postconditions on this or another method) to permit VeriWeb to prove it, or (3) VeriWeb is not powerful enough to prove the property, no matter how much other information you provide.

Enter the condition other.bits.length > bits.length (note the strict inequality). The condition will turn red:

Hover your mouse over the blue information box to view the condition failure information in the information panel. By expanding the nodes in the tree, you can see that the method can be called with both arrays having the same size. Also, you can hover your mouse over the subexpressions of the condition to see their values:

When you are solving postcondition problems, the table will also show the values when the method exits.

Non-null values are described by a unique id of the form ref@.... If two ids are the same, the references point to the same object.

Submit the correct condition other.bits.length >= bits.length, and click “Next Problem” when VeriWeb has finished thinking.

3.8  Problem 7: Writing postconditions for union(...)

Next, VeriWeb will ask you to write postconditions for union. In this case, VeriWeb again automatically tries a couple postconditions. But, we note the second conditions isn’t general enough: the property should hold for each element of the array. To express this, we use a \forall statement (see Section 2.4.2):

(\forall int i; 0 <= i && i < bits.length; bits[i] == (\old(bits[i]) || other.bits[i]))

Note the use of the \old(...) expression to refer to the bits array when the method is called.

Click “Next Problem”.

3.9  Problem 8: Select preconditions for similar(...)

Next, VeriWeb will ask you to select preconditions for the method similar. From the code, you can see that the required postconditions are the same as for union, but that other != null is not required since the method is since the method has declared it throws a RuntimeException in its throws clause.

Therefore, the following conditions should hold:

Indicating that the properties only must hold when other != null. To enter these, click the “Precondition Not Listed” button, and enter a short description of the necessary preconditions. VeriWeb will then ask you to submit those preconditions.

3.10  Problem 9: Write postconditions for similar(...)

VeriWeb will now ask you to write the similar methods regular postconditions, i.e., what is true when the exception is not thrown. The postcondition should say that the method returns true if, and only if, the elements are equal:

\result == (\forall int i; 0 <= i && i < bits.length; bits[i] == other.bits[i])

HINT: When answering postcondition questions, any mention of an argument x refers to \old(x), the value of x when the method was called.

3.11  Problem 10: Write exceptional postconditions for similar(...)

VeriWeb will now ask you to write the exceptional postconditions for RuntimeException, i.e., what is true when the exception is thrown in the similar(...) method. The top of the problem panel will say “Write post-conditions for RuntimeException”.

REMEMBER: An exceptional postcondition states what is true when the exception is thrown. This may not be the same as the conditions when the method was called that caused the exception to be thrown later.

In this case, we know that other == null. Submit this condition.

HINT: When answering postcondition questions, any mention of an argument x refers to \old(x), the value of x when the method was called.

3.12  Completing the warmup

This concludes the walkthrough; complete the task by using the VeriWeb tool until it informs you that you are finished.

3.12.1  Methods that call other methods

VeriWeb provides two ways to learn about the methods called by the current method:

  1. To view the documentation and specifications for a method, hover your mouse over the element underlined in blue in the source code
  2. Toggle inline specifications for a method with editable conditions by clicking on the method in the source code:
    This "inline view" also lets you view unproven postconditions for the method — VeriWeb doesn’t know if they are true or not. If you see a condition on the list that you think you need, it may be a good idea to try to add it to the method by clicking the "Add" button in the method’s main documentation display.

In the example below, the user has toggled the inline specifications for FixedSizeSet and contains:

Notice that the precondition bits != null is not met for the method contains, and is therefore shown in red. By looking at the postconditions FixedSizeSet, you can see that the method needs a postcondition that bits != null.

To tell VeriWeb that this postcondition is needed, bring up the specification for FixedSizeSet by hovering your mouse over the method. Then click “Add Postcondition”.

Alternatively, if you thought the precondition for contains was too strong, you would bring up the specification for contains and then click the “Bad” button next to the bits != null condition:

3.12.2  Reference Solution

If you get stuck, you can "cheat" by referring to the file FixedSizeSet.java, which contains a set of annotations that are sufficient to verify the library and the client. This is only one possible solution among many; your solution might include more / different annotations. The purpose of looking at the solution is to help your skills in reasoning about programs, not just to get you through the warm-up quickly.

4  Quiz

Answer the online quiz to check that you understood the core concepts: http://bit.ly/zSJp5M. Then, contact us via vWorker before continuing with the main project.

5  Main Project

  1. Open the StackAr project in the VeriWeb environment (see Section 3.1).
  2. Record your starting time for the project.
  3. Use the tool until VeriWeb presents you with a solution key.
  4. Record your ending time for the project.

Please do not take any breaks when working on the main project. If you need to take a break, record the start time and length of the break.

While we will answer tool / interface questions during the main project, we will not answer questions such as "Why can’t VeriWeb verify this postcondition?"

6  General Hints

VeriWeb is a modular checker: it reasons about code by examining one method at a time. Therefore, VeriWeb both checks and depends on annotations. For instance, suppose method A calls method B. If you have not written properties describing the return value of B, VeriWeb may not be able to prove a property about method A.

When answering postcondition questions, instead of calling a boolean predicate (e.g., isEmpty()) write the property (the method’s body) explicitly.