-
Notifications
You must be signed in to change notification settings - Fork 44
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
uc-crux-llvm: User-provided specifications for external functions #982
Comments
After a bit more reflection I now think that the ideal input language for this feature would be more rich than what UC-Crux currently provides via the
The precondition would be a constraint on the program state which specifies when the spec applies (e.g., For example, the following is a spec for a division function, stating that the output is symbolic and non-negative if the numerator is non-negative and denominator is positive or if both the numerator is non-positive and denominator is negative. - name: div
specs:
- # spec 1: non-negative / positive = non-negative
pre:
- args:
- # numerator
signed-greater-or-equal: 0
- # denominator
signed-greater: 0
post:
- ret:
symbolic:
signed-greater-or-equal: 0
- # spec 2: non-positive / negative = non-negative
pre:
- args:
- # numerator
signed-less-or-equal: 0
- # denominator
signed-less: 0
post:
- ret:
symbolic:
greater-or-equal: 0
# neither under-approximate nor over-approximate
soundness: neither
# failure to match all specs is an error (1), also see below
match-failure: error If the behavior in case of failure to match preconditions is an error, then UC-Crux could also use the specs to infer preconditions on callers of the external function, i.e., the caller should guarantee that it satisfies the intersection of the preconditions of the specs for the external function at the callsite. For example, in the above spec, If the user doesn't provide a postcondition for an override, the default behavior would also be to fall back to the unsound skipping. It would only really make sense to provide such overrides if failure to match preconditions is treated as an error. It would also be nice to provide a way to specify values that aren't concrete nor symbolic, but are derived from existing values. For instance,
which might be specified like so: - name: fgets
specs:
- pre: {}
post:
- ret:
# NULL, i.e., EOF or error
constant: 0
- pre: {}
post:
- ret:
# s, i.e., success
arg: 0
soundness: neither |
Are there any existing formats we might take advantage of for this? I don't have a list of candidates offhand, but it is worth us thinking about collectively |
Great question. I also don't know of any, but I looked into a few verification tools. I couldn't find anything for 2LS or Seahorn, but it looks like none of Angr, CBMC, KLEE, Infer, or SMACK use a common or reusable format for procedure summaries. AngrAngr allows symbolic function summaries (example: fgetc), which are very much like Crucible's Haskell overrides. CBMCCBMC provides simple C models of libc functions. These appear to be sound and precise. From their docs, it sounds to me like they expect to have C definitions for all functions, and don't support over- or under-approximate user-provided specs. Quotes from CMBC docs
KLEEKLEE relies on being able to call external functions. It can concretize symbolic arguments in order to do so. InferInfer has a bunch of different analyses, at least one allows specifying really basic properties of external functions as command-line arguments, e.g.:
SMACKSMACK allows inline Boogie code, which can be used to provide definitions of external functions. |
I don't know if you've locked in terminology, but reading
|
I've been exploring the space of possible implementations of this feature. It's actually a little complicated! The following are notes mostly to myself. Implementation notesThe general idea would be to replace the postcondition ( Seems easy enough, but the issue is that we'd end up with have a So here are the alternatives for generating or preserving evidence that a
We'd have this same issue even if the code wasn't dependently-typed - it's just that our only option would be (2), type-checking every time we want to use a spec. Currently leaning towards (1c). |
This functionality will be useful for implementing #982.
This functionality will be useful for implementing #982.
This functionality will be useful for implementing #982.
This functionality will be useful for implementing #982.
UC-Crux has the ability to skip over execution of declared but not defined functions, e.g., from a third-party library or libc. This is practical, but it has its disadvantages:
For libc functions in particular, we could manually implement overrides (in Haskell) for some of them. Sound overrides could live in
crucible-llvm
, and unsound ones in UC-Crux. However, this takes considerable effort and still doesn't work for other third-party libraries.Instead, we should implement deserialization of function postconditions (#981), probably from YAML, along with specifications of whether the provided postconditions are overapproximate, underapproximate, both, or neither (for the sake of #932 and tracking of unsoundness). This would mostly require making non-GADT versions of UC-Crux's data structures and working out how to convert to/from them.
The text was updated successfully, but these errors were encountered: