Code Contracts : What, Why and How?



#include <iostream>

int main()
{
	std::cout << "Hello World!" << std::endl;
	return 0;
}

Is this program correct?

/* Write a program that prints the first
   5 prime numbers                       */
#include <iostream>

int main()
{
	std::cout << "Hello World!" << std::endl;
	return 0;
}

Is this program correct?

History

Robert W Floyd

Sir Tony Hoare

Floyd-Hoare Logic

1967-1969

* Images are taken from Wikipedia

About inventing NULL reference, "I call it my billion dollar mistake."

History

  • Owiki-Gries 1976 : Rely-Guarantee for concurrent programs
  • O'hearn-Reynolds 2001 : Separation Logic for heap manipulating programs

Code Contracts : Formal description of sets of states (or behaviors) of program or a program fragment that defines correctness of the said program or a program fragment at given program points (or for given program traces/executions) .

Our field needs more formality, but the profession has not realized it yet.”  --Bertrand Meyer (Creator of Eiffel)

We have been using code contracts since long...

We have been using code contracts since long...

void add_to_node(node_t* n,int val)
{
	assert(n!=nullptr);
	n->val += val;
}

Program State

Values of all the program variables at a given instant

int x;

\(2^{32}\) possible states for a 32-bit int

int a[100];

\(2^{3200}\) possible states for a 32-bit int

Program as a state transformer

int x;
x=x+1;
x==INT_MIN
x==0
x==INT_MAX

...

x==INT_MIN+1
x==INT_MIN
x==1
?

...

...

...

x=x+1
x=x+1
x=x+1

Program as a state transformer

int x;
x=x+1;
x==INT_MIN
x==0
x==INT_MAX

...

x==INT_MIN+1
x==INT_MIN
x==1
Undefined

...

...

...

x=x+1

Program as a state transformer

int x;
x=x+1;
x==INT_MAX
Undefined
x=x+1
x<INT_MAX
x=x+1
x>INT_MIN

Program as a state transformer

int x;
x=x+1;
x==INT_MAX
Undefined
x=x+1
x<INT_MAX
x=x+1
x==old_x+1

Program as a state transformer

int x;
x=x+1;
x==INT_MAX
Undefined
x=x+1
x<INT_MAX
x=x+1
x==old_x+1

precondition

postcondition

Program as a state transformer

int x;
x=x+1;
x==INT_MAX
Undefined
x=x+1
x<INT_MAX
x=x+1
x==old_x+1

precondition

postcondition

Even a million tests has less than 1 in 4096 chance of finding the bug


int foo(int x)
{

    int tmp=x;
    x=x+1;
    if(x<tmp)
    {
    	launch_nukes_and_destroy_the_world();
    }
    return x;

}

int64_t foo(int64_t x)
{

    int64_t tmp=x;
    x=x+1;
    if(x<tmp)
    {
    	launch_nukes_and_destroy_the_world();
    }
    return x;

}

Even with a billion tests, the probability of finding the bug is less than 1 in 16 billion

  • Ariane 5 : 64-bit FP to 16-bit Short
  • Mariner 1 1962: A missing hyphen
  • Vancouver stock exchange : Floating point truncation bug
  • Nest thermostat bug 2016: Software bug causing battery drain
  • Therac-25 : Fatal exposure to radiation to patients

Disasters caused by software

  • https://spectrum.ieee.org/how-the-boeing-737-max-disaster-looks-to-a-software-developer
  •  

Testing

Testing

Testing

Testing

Testing

Testing

Testing

Absence of failure during testing does not mean absence of bugs.

What ideally we want..

What ideally we want..

Undecidable : There are programs for which computing exact set of reachable sets is impossible.

What ideally we want..

Undecidable : There are programs for which computing exact set of reachable sets is impossible.

... but we are engineers. Do it for programs for which it is possible.

Static Reachability Analysis

Instead of computing exact sets, compute overapproximate sets.

Static Reachability Analysis

Instead of computing exact sets, compute overapproximate sets.

Static Reachability Analysis

Static Reachability Analysis

False positive

Testing

  • Scales well
  • Easy to understand
  • Does not guarantee safety

Static Reachability

  • Does not scale well
  • Requires expertise
  • Can guarantee safety

Static Contract Checking

cond(var1)
cond1(var1,old_var1)
var1=f(old_var1)
cond2(var2)
cond3(var2,old_var2)
var2=f2(old_var2)

Static Contract Checking

cond(var1)
cond1(var1,old_var1)
var1=f(old_var1)
cond2(var2)
cond3(var2,old_var2)
var2=f2(old_var2)

Static Contract Checking

  • In practice, for checkers, it is easier to check for contracts rather than synthesizing them
  • Contract checking for smaller program fragments is easier than larger fragments

Static Checkers

Dynamic contract checking

Dynamic contract checking

  • Absence of bugs are not guaranteed
  • Formal and unambiguous in-source documentation
  • Self-documenting code: kind of enforces contract update upon code that changes pre/post conditions
  • Fault localization

It is absurd to make elaborate security checks on debugging runs, when no trust is put in the results, and then remove them in production runs, when an erroneous result could be expensive or disastrous. What would we think of a sailing enthusiast who wears his life-jacket when training on dry land but takes it off as soon as he goes to sea?”  -- Sir Tony Hoare [1973]

References