Skip to content

Performance issue with large arrays #7012

Open
@SaswatPadhi

Description

@SaswatPadhi

CBMC version: f9bd83e

CBMC seems to be struggling to prove unbounded correctness under large allocations. Here is a super simplified version of a proof that I and @akshayutture are working on:

struct elem { char c[ESIZE]; };

int main() {
  struct elem *a = malloc(ASIZE * sizeof(struct elem));

  for(unsigned i = 0; i < ASIZE; ++i)
  __CPROVER_assigns(i, __CPROVER_POINTER_OBJECT(a))
  __CPROVER_loop_invariant(1 == 1)
  {
    a[i].c[0] = 0;
  }
}

The loop isn’t doing anything interesting and the invariant is trivial. The only “expensive” operations here are the initial malloc and the subsequent havoc (for the assigns clause).

We verify this example using:

$ goto-cc -o test.1.o -DESIZE=100 -DASIZE=1000 test.c
$ goto-instrument --apply-loop-contracts test.1.o test.2.o
$ cbmc test.2.o

Here are the proof times we observe:

 Elem Size | Array Size | Proof time 
-----------+------------+------------
    100    |    1000    |    0.5 s
    500    |    1000    |     2 s
   1000    |     500    |     2 s
   1000    |    1000    |     5 s
    500    |   10000    |    24 s

@tautschnig figured out that this is because CBMC is not using array theory in this case and it bit blasts the large array which leads to the performance degradation.

He suggested the following workaround for initializing the a array:

  unsigned long asize;
  struct elem *a = malloc(asize * sizeof(struct elem));
  __CPROVER_assume(asize == ASIZE);

and indeed it fixes the performance issue that we notice above.

I am leaving this issue open so we fix this issue within CBMC at some point in the future.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions