Skip to content
Snippets Groups Projects
Commit dbe6defa authored by Per Lindgren's avatar Per Lindgren
Browse files

Cargo klee examples

parent c81e7e95
Branches
No related tags found
No related merge requests found
target
**/*.rs.bk
Cargo.lock
{
"cSpell.ignoreWords": [
"cmake",
"core",
"cstr",
"datatypes",
"ktest",
"libklee",
"libz",
"llvm",
"mkdir",
"runtest",
"rustc",
"satisfiability"
"satisfiability",
"skylake",
"znver"
]
}
\ No newline at end of file
# KLEE tutorial
Installing and testing klee.
- Installing and testing klee.
- Manual use of the KLEE tools for C and Rust programs.
- Simplified usage adopting `klee-sys` and `cargo klee`.
## Dependencies
......@@ -28,7 +32,6 @@ Under arch with `yay` installed simply:
> sudo apt install z3 libz3-4 libz3-cil libz3-dev libz3-java libz3-jni libz3-ocaml-de
## Install KLEE from source
The instructions recommend LLVM 9, but the current master (2.2-pre) supports LLVM 11 (which is what you would have under arch as of 2020-12-07).
......@@ -107,8 +110,24 @@ Here you learn:
---
## klee-sys and Cargo-klee
See the `cargo-klee-examples` folder.
Here you learn:
- an easy way to compile and run KLEE on Rust code
- an easy way to replay test cases for Rust programs
TODO:
More interesting verification problems using `cargo klee`.
--
## Why KLEE on Rust
Out the box, Rust provides superior memory safety and guarantees to well defined behavior. However there are cases where the Rust compiler (rustc) cannot statically (at compile time) ensure these guarantees. For such cases (e.g., division by zero, slice/array indexing etc.) Rust injects code for run-time verification that emit a `panic!` (with appropriate error message). While still being safe (the code never runs into memory unsafety or undefined behavior) this limits the reliability (availability) of the system (as its very hard to recover from a `panic!`.) In practice, the developer would typically reboot/reset the system (and store some error code/trace for post-mortem analysis).
With KLEE we can do better! We bind Rust `panic!` to KLEE `abort` (a path termination), and let. For all reachable `panic!`s, KLEE will provide a concrete test, which we can replay and address in our source code. When done, we have a proof of `panic` freedom and thus defined behavior, with huge impact to reliability (and security) of the system at hand.
\ No newline at end of file
With KLEE we can do better! We bind Rust `panic!` to KLEE `abort` (a path termination), and let. For all reachable `panic!`s, KLEE will provide a concrete test, which we can replay and address in our source code. When done, we have a proof of `panic` freedom and thus defined behavior, with huge impact to reliability (and security) of the system at hand.
/target
**/*.rs.bk
Cargo.lock
[package]
name = "cargo_klee_examples"
version = "0.1.0"
authors = ["pln <Per Lindgren>"]
edition = "2018"
[dependencies.klee-sys]
git = "https://gitlab.henriktjader.com/KLEE/klee-sys.git"
version = "0.2.0"
[dependencies.panic-klee]
git = "https://gitlab.henriktjader.com/pln/panic-klee.git"
version = "0.1.0"
[profile.dev]
panic = "abort"
incremental = false # better optimization
lto = true # better optimization
codegen-units = 1 # better optimization
[profile.release]
panic = "abort"
debug = true # better debugging
incremental = false # better optimization
lto = true # better optimization
codegen-units = 1 # better optimization
[features]
klee-analysis = ["klee-sys/klee-analysis"]
# Examples on `cargo-klee` usage
## Install
Clone the [cargo-klee](https://gitlab.henriktjader.com/pln/cargo-klee).
Follow install instructions.
## Examples
- `examples/get_sign.rs`, same simple example again but now using the `cargo klee` cargo sub-command. The example also uses `klee-sys` bindings.
// get_sign.rs
// Showcase how we automatically can interface Rust to KLEE
//
#![no_std]
#![no_main]
use klee_sys::klee_make_symbolic;
use panic_klee as _;
fn get_sign(x: i32) -> i32 {
if x == 0 {
return 0;
}
if x < 0 {
return -1;
} else {
return 1;
}
}
#[no_mangle]
fn main() {
let mut a: i32 = 0;
klee_make_symbolic!(&mut a, "a");
get_sign(a);
}
// A) Compile a Rust program for KLEE analysis.
//
// The bindings to klee are abstracted into `klee-sys`.
// The panic handler into `panic_klee` (essentially KLEE `abort`).
// The tedious build process into `cargo klee`.
//
// > cargo klee -help
//
// The default is to generate LLVM-IR run KLEE on the generated LLVM-IR.
// This enables the `klee-analysis` feature of `klee-sys`.
//
// Using the `-v` option we see verbose output.
//
// > cargo klee -v --example get_sign
// "cargo" "rustc" "-v" "--features" "klee-analysis" "--example" "get_sign" "--color=always" "--" "-C" "linker=true" "-C" "lto" "--emit=llvm-ir"
// ...
//
// KLEE: Using Z3 solver backend
//
// KLEE: done: total instructions = 92
// KLEE: done: completed paths = 3
// KLEE: done: generated tests = 3
// This should be familiar to the build you did in the previous exercise.
//
// Now locate the generated tests. Give the relative path to `klee-last`.
//
// [your answer here]
//
// B) Replay test cases
//
// By giving the `-r` (or `--replay`), you can easily replay the test cases:
//
// > cargo klee -v -r -g --example get_sign
//
// (gdb) set environment KTEST_FILE=klee-last/test000001.ktest
// (gdb) break get_sign
// (gdb) run
//
// What path of the program does this path trigger?
//
// [your answer here]
//
// Just out of curiosity, you may test the other test cases as well...
//
// B) UX/IX
//
// Compare to the "stock KLEE for C" experience.
//
// How does `klee-sys` and `cargo-klee` score on a 0..5 scale?
//
// [your answer here]
//
// If below 5, what could be done to improve the UX/IX?
//
// [your answer here]
//
// C) Inner workings.
//
// Have a look on the source code of `klee-sys`.
// You will find that it is very similar to the code you saw in the
// previous exercise.
//
// Try to follow the `klee-analysis` feature.
// What modules in `klee-sys` does this feature enable?
//
// [your answer here]
//
// Have a look at the source code of `cargo klee`.
// (The actual sub-command is in the folder `cargo-klee`.)
//
// Try to figure out how the correct `.ll` file is determined.
// Which one will it pick, and why?
//
// [your answer here]
//
// Actually this is one of the "bad seeds" in the internal design.
// Seems there is no "stable" way of controlling/retrieving the "metadata"
// (i.e., the hashing). Ideas welcome!
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment