Skip to content

Memory primitives should handle invalid pointers #6045

Closed
@feliperodri

Description

@feliperodri

CBMC version: 5.27.0 (cbmc-5.26.0-148-g7ced011bd-dirty)
Operating system: macOS Mojave 10.14.6
Exact command line resulting in the issue: cbmc main.c --malloc-may-fail --malloc-fail-null --trace
What behaviour did you expect: line 7 assertion __CPROVER_r_ok(ptr, 0): FAILURE
What happened instead: VERIFICATION SUCCESSFUL

To explain the behavior, let's consider the following example.

// main.c
#include <stdlib.h>
#include <assert.h>

int main() {
  void *ptr = malloc(0);
  __CPROVER_assume(ptr != NULL);
  assert(__CPROVER_r_ok(ptr, 0));
}

I expect the assertion to fail, because ptr could be an invalid pointer; however, it succeeds.

CBMC version 5.27.0 (cbmc-5.26.0-148-g7ced011bd-dirty) 64-bit x86_64 macos
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.0034956s
size of program expression: 94 steps
simple slicing removed 5 assignments
Generated 1 VCC(s), 1 remaining after simplification
Runtime Postprocess Equation: 1.1753e-05s
Passing problem to propositional reduction
converting SSA
Runtime Convert SSA: 0.000522958s
Running propositional reduction
Post-processing
Runtime Post-process: 8.1631e-05s
Solving with MiniSAT 2.2.1 with simplifier
437 variables, 313 clauses
SAT checker inconsistent: instance is UNSATISFIABLE
Runtime Solver: 9.8288e-05s
Runtime decision procedure: 0.000650914s

** Results:
<builtin-library-malloc> function malloc
[malloc.assertion.1] line 26 max allocation size exceeded: SUCCESS
[malloc.assertion.2] line 31 max allocation may fail: SUCCESS

main.c function main
[main.assertion.1] line 8 assertion __CPROVER_r_ok(ptr, 0): SUCCESS

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

I expect that the first thing __CPROVER_r_ok would check is whether the pointer is valid or not. If not valid, return false.
I also try to verify this program using --pointer-primitive-check flag, but I got another unexpected behavior.
Command line: cbmc main.c --malloc-may-fail --malloc-fail-null --pointer-primitive-check --trace

CBMC version 5.27.0 (cbmc-5.26.0-148-g7ced011bd-dirty) 64-bit x86_64 macos
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.00497527s
size of program expression: 99 steps
simple slicing removed 5 assignments
Generated 6 VCC(s), 6 remaining after simplification
Runtime Postprocess Equation: 1.4961e-05s
Passing problem to propositional reduction
converting SSA
Runtime Convert SSA: 0.000804849s
Running propositional reduction
Post-processing
Runtime Post-process: 0.000148184s
Solving with MiniSAT 2.2.1 with simplifier
508 variables, 679 clauses
SAT checker: instance is SATISFIABLE
Runtime Solver: 0.00109353s
Runtime decision procedure: 0.00196439s
Building error trace
Running propositional reduction
Solving with MiniSAT 2.2.1 with simplifier
508 variables, 372 clauses
SAT checker: instance is UNSATISFIABLE
Runtime Solver: 1.8796e-05s
Runtime decision procedure: 3.933e-05s

** Results:
<builtin-library-malloc> function malloc
[malloc.assertion.1] line 26 max allocation size exceeded: SUCCESS
[malloc.assertion.2] line 31 max allocation may fail: SUCCESS

main.c function main
[main.assertion.1] line 8 assertion __CPROVER_r_ok(ptr, 0): SUCCESS
[main.pointer_primitives.1] line 8 pointer invalid in R_OK(ptr, (__CPROVER_size_t)0): SUCCESS
[main.pointer_primitives.2] line 8 deallocated dynamic object in R_OK(ptr, (__CPROVER_size_t)0): SUCCESS
[main.pointer_primitives.3] line 8 dead object in R_OK(ptr, (__CPROVER_size_t)0): SUCCESS
[main.pointer_primitives.4] line 8 pointer outside dynamic object bounds in R_OK(ptr, (__CPROVER_size_t)0): FAILURE
[main.pointer_primitives.5] line 8 pointer outside object bounds in R_OK(ptr, (__CPROVER_size_t)0): SUCCESS

Trace for main.pointer_primitives.4:

State 26 file main.c function main line 6 thread 0
----------------------------------------------------
  ptr=NULL (00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000)

State 30 file main.c function main line 6 thread 0
----------------------------------------------------
  malloc_size=0ul (00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000)

State 59 file main.c function main line 6 thread 0
----------------------------------------------------
  ptr=(const void *)dynamic_object1 (00000010 00000000 00000000 00000000 00000000 00000000 00000000 00000000)

Assumption:
  file main.c line 7 function main
  ptr != (void *)0

Violated property:
  file main.c function main line 8 thread 0
  pointer outside dynamic object bounds in R_OK(ptr, (__CPROVER_size_t)0)
  POINTER_OBJECT(NULL) == POINTER_OBJECT(ptr) || !IS_DYNAMIC_OBJECT(ptr) || POINTER_OFFSET(ptr) >= 0l && OBJECT_SIZE(ptr) >= (unsigned long int)POINTER_OFFSET(ptr) + 1ul



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

Again, if cbmc checked for validity first, I think we'd also avoid this problem.

Metadata

Metadata

Assignees

Labels

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions