Skip to content

Spurious malloc behavior for large allocations #6130

Closed
@feliperodri

Description

@feliperodri

CBMC version: develop
Operating system: macOs Majave
Exact command line resulting in the issue: cbmc main.c --malloc-may-fail --malloc-fail-null --pointer-overflow-check --pointer-check
What behaviour did you expect: Consistent behaviour using malloc for large allocations.
What happened instead:

Consider the following example.

     1  #include <stdlib.h>
     2  #include <stdint.h>
     3  #include <assert.h>
     4
     5  int main () {
     6      size_t size;
     7      //size = SIZE_MAX;
     8      uint8_t *ptr = malloc(size);
     9      __CPROVER_assume(ptr != NULL);
    10      uint8_t *ptr_end = ptr + size;
    11      assert(ptr <= ptr_end);
    12  }

Running this example with cbmc main.c --malloc-may-fail --malloc-fail-null --pointer-overflow-check --pointer-check leads to verification failure.

...
[main.pointer_arithmetic.16] line 11 pointer relation: dead object in ptr_end: SUCCESS
[main.pointer_arithmetic.17] line 11 pointer relation: pointer outside object bounds in ptr_end: FAILURE
[main.pointer_arithmetic.18] line 11 pointer relation: invalid integer address in ptr_end: SUCCESS

** 1 of 22 failed (2 iterations)
VERIFICATION FAILED

Running this example with cbmc main.c --pointer-overflow-check --pointer-check leads to another kind of verification failure.

...
[main.pointer_arithmetic.4] line 10 pointer arithmetic: dead object in ptr + (signed long int)size: SUCCESS
[main.pointer_arithmetic.5] line 10 pointer arithmetic: pointer outside object bounds in ptr + (signed long int)size: FAILURE
[main.pointer_arithmetic.6] line 10 pointer arithmetic: invalid integer address in ptr + (signed long int)size: SUCCESS
...
[main.pointer_arithmetic.16] line 11 pointer relation: dead object in ptr_end: SUCCESS
[main.pointer_arithmetic.17] line 11 pointer relation: pointer outside object bounds in ptr_end: FAILURE
[main.pointer_arithmetic.18] line 11 pointer relation: invalid integer address in ptr_end: SUCCESS

** 2 of 22 failed (3 iterations)
VERIFICATION FAILED

If we include line 7, we get different results too.
Using cbmc main.c --malloc-may-fail --malloc-fail-null --pointer-overflow-check --pointer-check.

...
[main.pointer_arithmetic.14] line 11 pointer relation: pointer invalid in ptr_end: SUCCESS
[main.pointer_arithmetic.15] line 11 pointer relation: deallocated dynamic object in ptr_end: SUCCESS
[main.pointer_arithmetic.16] line 11 pointer relation: dead object in ptr_end: SUCCESS
[main.pointer_arithmetic.17] line 11 pointer relation: pointer outside object bounds in ptr_end: SUCCESS
[main.pointer_arithmetic.18] line 11 pointer relation: invalid integer address in ptr_end: SUCCESS

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

Using cbmc main.c --pointer-overflow-check --pointer-check.

CBMC version 5.30.1 (cbmc-5.21.0-1027-g64974b018-dirty) 64-bit x86_64 linux
Parsing main.c
Converting
Type-checking main
Generating GOTO Program
Adding CPROVER library (x86_64)
Removal of function pointers and virtual functions
Generic Property Instrumentation
Running with 8 object bits, 56 offset bits (default)
Starting Bounded Model Checking
Runtime Symex: 0.00208319s
size of program expression: 87 steps
simple slicing removed 5 assignments
Generated 20 VCC(s), 3 remaining after simplification
Runtime Postprocess Equation: 1.2301e-05s
Passing problem to propositional reduction
converting SSA
array too large for flattening

Why do we have completely different results here? Am I missing something? What is CBMC behaviour for allocation attempts where size is larger than __CPROVER_max_malloc_size? What is the definition of __CPROVER_max_malloc_size?

Often, we need to use in our proofs the following trick

/**
 * CBMC has an internal representation in which each object has an index and a (signed) offset
 * A buffer cannot be larger than the max size of the offset
 * The Makefile is expected to set CBMC_OBJECT_BITS to the value of --object-bits
 */
#define MAX_MALLOC (SIZE_MAX >> (CBMC_OBJECT_BITS + 1))

size_t size;
__CPROVER_assume(size < MAX_MALLOC);
void *ptr = malloc(size);

Why should this be even necessary here? Wouldn't malloc take care of such cases?

cc. @tautschnig @SaswatPadhi

Metadata

Metadata

Labels

awsBugs or features of importance to AWS CBMC usersaws-highbug

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions