Skip to content

Unsoundness for LLVM functions that return non-fresh pointers #641

@brianhuffman

Description

@brianhuffman

This is a similar bug to #640, but without using NULL.

Here's the C code:

#include <stdint.h>
#include <stdlib.h>

uint64_t *foo (uint64_t *x) {
	return x;
}

int bar (uint64_t *x) {
	return (x == foo(x));
}

And here's the saw-script, which can prove both that bar always returns 0 and that bar always returns 1:

bc <- llvm_load_module "return_same.bc";

let i64 = llvm_int 64;

foo_ov <-
  crucible_llvm_verify bc "foo" [] false
    do {
      x <- crucible_alloc i64;
      crucible_execute_func [x];
      y <- crucible_alloc i64;
      crucible_return y;
    }
    z3;

bar_ov0 <-
  crucible_llvm_verify bc "bar" [foo_ov] false
    do {
      x <- crucible_alloc i64;
      crucible_execute_func [x];
      crucible_return (crucible_term {{ 0 : [32] }});
    }
    z3;

bar_ov1 <-
  crucible_llvm_verify bc "bar" [] false
    do {
      x <- crucible_alloc i64;
      crucible_execute_func [x];
      crucible_return (crucible_term {{ 1 : [32] }});
    }
    z3;

The problem is that the verification of foo should fail, as the spec says that the return value of foo should be a freshly-created pointer, while it has actually copied the pointer from an input argument. To be sound, we need to check that supposedly-fresh pointers are actually disjoint from all other pointers in scope.

Metadata

Metadata

Assignees

No one assigned

    Labels

    subsystem: crucible-llvmIssues related to LLVM bitcode verification with crucible-llvmtype: bugIssues reporting bugs or unexpected/unwanted behaviorunsoundnessIssues that can lead to unsoundness or false verification

    Type

    No type

    Projects

    No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions