CBMC(C Bounded Model Checking)


model checking is a method for checking whether a finite-state model of a system meets a given specification.


CBMC overview

image


program into a control flow graph

image


program

if ( (0 <= t) && (t <= 79) )
{
    switch ( t / 20 )
    {
        case 0:
            TEMP2 = ( (B AND C) OR (~B AND D) );
            break;
        case 1:
            TEMP2 = ( (B XOR C XOR D) );
            break;
        case 2:
            TEMP2 = ( (B AND C) OR (B AND D) OR (C AND D) );
            break;
        case 3:
            TEMP2 = ( B XOR C XOR D );
            break;
        default:
    }
    assert(TEMP2>0);
    
}


code flow graph

image


Linear temporal logic

  • Linear temporal logic
    • G for always (globally)
    • F for finally
    • R for release
    • W for weak until
    • M for mighty release
  • Computation tree logic
    • AAll
    • EExists
    • X - NeXt

image


Goal: check properties of the form AG p, satisfy assertions.


SAT solver

https://www.inf.ufpr.br/dpasqualin/d3-dpll/ SAT solver will find instance that satisfy all cases


But SAT only can solve pure boolean satisfiability problem

is boolean but is INT32 or INT8 how to convert it to pure boolean probleam


convert code to conjunctive normal form for SAT solver

image


SAT will try to find the counter of

we can check is exist counter example of the form AG p


convert to pure boolean

digital logic image


loop

while(cond){
    a++;
    assert(a<0);
}

unrolling

bounded model checking bounded how deep we can unrolling

if(cond){
    a++;
    assert(a<0);
    if(cond){
        a++;
        assert(a<0);
        if(cond){
            a++;
            assert(a<0);
            if(cond){
                a++;
                assert(a<0);
                ....
            }
        }
    }
}

unrolling optimization

image


pointer bound

int n;
int ∗p;
p=malloc(sizeof(int)∗5);
p[n]=100;
int n;
int ∗p;
p=malloc(sizeof(int)∗5);

assert(0<=n && n<5);
p[n]=100;

code example overflow

void f00 (int x, int y, int z) {
  if (x < y) {
    int firstSum = x + z;
    int secondSum = y + z;
    assert(firstSum < secondSum);
  }
}
example.c function f00
[f00.assertion.1] line 16 assertion firstSum < secondSum: FAILURE

Trace for f00.assertion.1:

↳ example.c:12 f00(-1275228454, 1113655513, -1157894487)
  14: firstSum=1861844355 (01101110 11111001 01111101 10000011)
  15: secondSum=-44238974 (11111101 01011100 11110111 10000010)

Violated property:
  file example.c function f00 line 16 thread 0
  assertion firstSum < secondSum
  firstSum < secondSum

code example pointer

void f15 (int x, int y) {
  int a[5]={1,2,3,4,5};

  int *b= (int *)malloc(5 * sizeof(int));
  for(int i=0;i<5;i++)
    b[i]=i;

  int *p=a;

  if(x==1 && y==1){
    // p=b+1; 
    p=&b[1];
    p[4]=5;
  }
  for(int i=0;i<5;i++){
    assert(a[i] == p[i]);
  }
  free(b);
}

code example pointer

Trace for f15.pointer_dereference.12:

↳ example.c:143 f15(1, 1)
  144: a={ 1, 2, 3, 4, 5 } ({ 00000000 00000000 00000000 00000001, 00000000 00000000 00000000 00000010, 00000000 00000000 00000000 00000011, 00000000 00000000 00000000 00000100, 00000000 00000000 00000000 00000101 })
  144: a[0l]=1 (00000000 00000000 00000000 00000001)
  144: a[1l]=2 (00000000 00000000 00000000 00000010)
  144: a[2l]=3 (00000000 00000000 00000000 00000011)
  144: a[3l]=4 (00000000 00000000 00000000 00000100)
  144: a[4l]=5 (00000000 00000000 00000000 00000101)

↳ example.c:146 malloc(sizeof(signed int) * 5ul /*20ul*/ )
  12: dynamic_object1[0l]=0 (00000000 00000000 00000000 00000000)
  12: dynamic_object1[1l]=0 (00000000 00000000 00000000 00000000)
  12: dynamic_object1[2l]=0 (00000000 00000000 00000000 00000000)
  12: dynamic_object1[3l]=0 (00000000 00000000 00000000 00000000)
  12: dynamic_object1[4l]=0 (00000000 00000000 00000000 00000000)
  146: b=dynamic_object1 (00000010 00000000 00000000 00000000 00000000 00000000 00000000 00000000)
  147: i=0 (00000000 00000000 00000000 00000000)
  148: dynamic_object1[0l]=0 (00000000 00000000 00000000 00000000)
  147: i=1 (00000000 00000000 00000000 00000001)
  148: dynamic_object1[1l]=1 (00000000 00000000 00000000 00000001)
  147: i=2 (00000000 00000000 00000000 00000010)
  148: dynamic_object1[2l]=2 (00000000 00000000 00000000 00000010)
  147: i=3 (00000000 00000000 00000000 00000011)
  148: dynamic_object1[3l]=3 (00000000 00000000 00000000 00000011)
  147: i=4 (00000000 00000000 00000000 00000100)
  148: dynamic_object1[4l]=4 (00000000 00000000 00000000 00000100)
  147: i=5 (00000000 00000000 00000000 00000101)
  150: p=((signed int *)NULL) (00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000)
  151: p=a!0@1 (00000011 00000000 00000000 00000000 00000000 00000000 00000000 00000000)
  155: p=dynamic_object1 + 1l (00000010 00000000 00000000 00000000 00000000 00000000 00000000 00000100)

Violated property:
  file example.c function f15 line 156 thread 0
  dereference failure: pointer outside dynamic object bounds in p[(signed long int)4]
  16l + POINTER_OFFSET(p) >= 0l && __CPROVER_malloc_size >= 20ul + (unsigned long int)POINTER_OFFSET(p) || !(POINTER_OBJECT(p) == POINTER_OBJECT(__CPROVER_malloc_object))


code example multiple

void f14 (int x, int y) {
    int a = x;
    int b = y;
    assert(a*b == x*y);
}

code example multiple MiniSAT

CBMC version 5.12 (cbmc-5.12) 64-bit x86_64 linux
Parsing example.c
Converting
Type-checking example
Generating GOTO Program
Adding CPROVER library (x86_64)
Removal of function pointers and virtual functions
Generic Property Instrumentation
Removing unused functions
Dropping 14 of 17 functions (3 used)
Performing a reachability slice
Running with 8 object bits, 56 offset bits (default)
Starting Bounded Model Checking
size of program expression: 47 steps
simple slicing removed 4 assignments
Generated 2 VCC(s), 1 remaining after simplification
Passing problem to propositional reduction
converting SSA
Running propositional reduction
Post-processing
Solving with MiniSAT 2.2.1 with simplifier
3817 variables, 18930 clauses
SAT checker: instance is UNSATISFIABLE
Runtime decision procedure: 477.908s

** Results:
function __CPROVER__start
[__CPROVER__start.memory-leak.1] dynamically allocated memory never freed in __CPROVER_memory_leak == NULL: SUCCESS

example.c function f14
[f14.assertion.1] line 140 assertion a*b == x*y: SUCCESS

** 0 of 2 failed (1 iterations)
VERIFICATION SUCCESSFUL

code example multiple Z3

CBMC version 5.12 (cbmc-5.12) 64-bit x86_64 linux
Parsing example.c
Converting
Type-checking example
Generating GOTO Program
Adding CPROVER library (x86_64)
Removal of function pointers and virtual functions
Generic Property Instrumentation
Removing unused functions
Dropping 15 of 18 functions (3 used)
Performing a reachability slice
Running with 8 object bits, 56 offset bits (default)
Starting Bounded Model Checking
size of program expression: 47 steps
simple slicing removed 4 assignments
Generated 2 VCC(s), 1 remaining after simplification
Passing problem to SMT2 QF_AUFBV using Z3
converting SSA
Running SMT2 QF_AUFBV using Z3
Runtime decision procedure: 0.00870986s

** Results:
function __CPROVER__start
[__CPROVER__start.memory-leak.1] dynamically allocated memory never freed in __CPROVER_memory_leak == NULL: SUCCESS

example.c function f14
[f14.assertion.1] line 140 assertion a*b == x*y: SUCCESS

** 0 of 2 failed (1 iterations)
VERIFICATION SUCCESSFUL

SPIN


SPIN

  • promela language
  • deadlock deletction

image


promela language

image


image


two process FSM

Gcluster_P1Process P1cluster_P2Process P2S5S5: Hold R2T5T5: Hold R1S1S1: InitialS2S2: Request R1S1->S2request R1S3S3: Hold R1S2->S3acquire R1S4S4: Request R2S3->S4request R2S4->S5acquire R2T1T1: InitialT2T2: Request R2T1->T2request R2T3T3: Hold R2T2->T3acquire R2T4T4: Request R1T3->T4request R1T4->T5acquire R1

the state that is not final state but have no next state is the deadlock state

GS5T1S5,T1S1T5S1T5S2T5S2T5S5T2S5,T2S1T1S1,T1S2T1S2,T1S1T1->S2T1P1: request R1S1T2S1,T2S1T1->S1T2P2: request R2S3T1S3,T1S2T1->S3T1P1: acquire R1S2T2S2,T2S2T1->S2T2P2: request R2S4T1S4,T1S3T1->S4T1P1: request R2S3T2S3,T2S3T1->S3T2P2: request R2S4T1->S5T1P1: acquire R2S4T2S4,T2S4T1->S4T2P2: request R2S1T2->S2T2P1: request R1S1T3S1,T3S1T2->S1T3P2: acquire R2S2T3S2,T3S2T2->S2T3P2: acquire R2S2T2->S3T2P1: acquire R1S1T4S1,T4S1T3->S1T4P2: request R1S1T3->S2T3P1: acquire R1S1T4->S1T5P2: acquire R1S2T4S2,T4S1T4->S2T4P1: request R1S2T3->S2T4P2: request R1S3T3S3,T3S2T3->S3T3P1: acquire R1S2T4->S2T5P2: acquire R1S3T2->S4T2P1: request R2S3T2->S3T3P2: acquire R2S4T2->S5T2P1: acquire R2S4T3S4,T3S3T3->S4T3P1: request R2S3T4S3,T4S3T3->S3T4P2: request R1

convert property check to LTL expression

image


alot of work are try reduce computation to save time


summary

  • use interactive and random simulations get the all reachable states and transction
  • use the states and transction build finite-state machine
  • check the is any counter example of assert
  • property check to LTL to check all the reachable state is fit the property

ref

  • https://www.cprover.org/cbmc/doc/cbmc-slides.pdf
  • https://spinroot.com/spin/Doc/Spin_tutorial_2004.pdf
  • https://www.cs.cmu.edu/~aldrich/courses/654-sp05/handouts/model-checking-5.pdf