Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Unsound compositional proof #30

Closed
msaaltink opened this issue Jul 1, 2015 · 4 comments · Fixed by #549
Closed

Unsound compositional proof #30

msaaltink opened this issue Jul 1, 2015 · 4 comments · Fixed by #549

Comments

@msaaltink
Copy link
Contributor

I'm getting an unsound result from a composite proof of this simple code:

#include <stdint.h>

uint32_t side_effect(uint32_t *a) {
  uint32_t v;
  v = *a;
  *a = 0;
  return v;
}

uint32_t foo(uint32_t x) {
  uint32_t b = x;
  side_effect(&b);
  return side_effect(&b);
}

Here's the SAWscript:

c <- llvm_load_module "side.bc";

let side_spec = do {
  a <- llvm_ptr "a" (llvm_int 32);
  llvm_return {{ a }};
  llvm_ensure_eq "*a" {{ 0:[32] }};
  llvm_verify_tactic abc;
  };

side_proof <- llvm_verify c "side_effect" [] side_spec;

let foo_spec = do {
  x <- llvm_var "x" (llvm_int 32);
  llvm_return {{ x }};
  llvm_verify_tactic abc;
  };

bad <- llvm_verify c "foo" [side_proof] foo_spec;

This supposed proof works fine in the latest saw-script interpreter. Oddly enough, a non-compositional proof knows the righty answer:

foo_fn <- llvm_extract c "foo" llvm_pure;
prove_print abc {{\x -> foo_fn x == 0}};
@atomb atomb added the bug label Aug 5, 2015
@atomb
Copy link
Contributor

atomb commented Aug 31, 2015

This is fixed in 43cc206. The code to override functions based on previous proofs had an embarrassing bug: it completely ignored state changes made by the overridden function, propagating only the return value. It's no longer quite so broken.

@atomb atomb closed this as completed Aug 31, 2015
@msaaltink
Copy link
Contributor Author

Not quite so broken, yes, but still broken. Consider this small change to the example, where one of the effects is commented out of the first specification:

c <- llvm_load_module "side.bc";

let part_side_spec = do {
  a <- llvm_ptr "a" (llvm_int 32);
  llvm_return {{ a }};
  // llvm_ensure_eq "*a" {{ 0:[32] }};
  llvm_verify_tactic abc;
  };

side_proof <- llvm_verify c "side_effect" [] part_side_spec;

Fine so far, that's a true fact, albeit an incomplete description. It can be used unsoundly:

let foo_spec = do {
  x <- llvm_var "x" (llvm_int 32);
  llvm_return {{ x }};
  llvm_verify_tactic abc;
  };

bad <- llvm_verify c "foo" [side_proof] foo_spec;

Typically, specifications for called routines will need to make some honest statement about what they can modify, but this is missing here.

@TomMD TomMD reopened this Dec 15, 2015
@atomb
Copy link
Contributor

atomb commented Dec 15, 2015

This is a known issue which should have already had its own ticket. I believe I'd mentioned it to you in earlier discussions, @msaaltink. Apologies if I didn't.

One of the key reasons for a formalization of what these specifications mean is that, for the memory model used by the LLVM simulator, it's unclear exactly what we need to check to ensure that functions do not have effects beyond what's specified.

@langston-barrett
Copy link
Contributor

langston-barrett commented May 17, 2019

I'm not sure if this would fix all instances of this unsoundness, but a first approximation might be: For each variable (global, parameter, etc.) appearing in a precondition, unless it's value is also uniquely determined by a postcondition*, creating a new postcondition stating that it's value doesn't change.

It might be best if the SAW manual included a note about this for 0.3.

*This is probably the challenging bit.

@atomb atomb modified the milestones: 1.0, 0.4 Oct 1, 2019
chameco added a commit to chameco/saw-script that referenced this issue Oct 16, 2019
atomb pushed a commit that referenced this issue Oct 21, 2019
* Invalidate memory before executing postcondition
* Do not implicitly allocate mutable global variables. Instead, use a new crucible_alloc_global function.
* Refactor unwieldy additions to verifyPrestate and executeCond
* Update integration test suite
* Add some integration tests for issue #30
* Add source location for global allocations
* Bump crucible submodule

Fixes #30.
atomb pushed a commit that referenced this issue Oct 22, 2019
Ptival pushed a commit that referenced this issue Oct 31, 2019
* Invalidate memory before executing postcondition
* Do not implicitly allocate mutable global variables. Instead, use a new crucible_alloc_global function.
* Refactor unwieldy additions to verifyPrestate and executeCond
* Update integration test suite
* Add some integration tests for issue #30
* Add source location for global allocations
* Bump crucible submodule

Fixes #30.
Ptival pushed a commit that referenced this issue Oct 31, 2019
brianhuffman pushed a commit that referenced this issue Apr 26, 2021
Make test binary load, translate, and typecheck `Cryptol.cry`.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging a pull request may close this issue.

4 participants