Skip to content

Spurious malloc behavior for large allocations #6130

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

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

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