Skip to content

Commit 449e22f

Browse files
committed
Add translation of CBMC exceptions to the Rust Result type
1 parent 4a5c1f9 commit 449e22f

File tree

4 files changed

+64
-10
lines changed

4 files changed

+64
-10
lines changed

src/libcprover-rust/include/c_api.h

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22

33
#pragma once
44

5+
#include <util/exception_utils.h>
6+
57
#include <memory>
68

79
// NOLINTNEXTLINE(build/include)
@@ -16,3 +18,30 @@ translate_vector_of_string(rust::Vec<rust::String> elements);
1618
// Exposure of the C++ object oriented API through free-standing functions.
1719
std::unique_ptr<api_sessiont> new_api_session();
1820
std::vector<std::string> const &get_messages();
21+
22+
// NOLINTNEXTLINE(readability/namespace)
23+
namespace rust
24+
{
25+
// NOLINTNEXTLINE(readability/namespace)
26+
namespace behavior
27+
{
28+
template <typename Try, typename Fail>
29+
static void trycatch(Try &&func, Fail &&fail) noexcept
30+
{
31+
try
32+
{
33+
func();
34+
}
35+
catch(const cprover_exception_baset &e)
36+
{
37+
fail(e.what());
38+
}
39+
catch(const invariant_failedt &i)
40+
{
41+
fail(i.what());
42+
}
43+
}
44+
45+
} // namespace behavior
46+
47+
} // namespace rust
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
util

src/libcprover-rust/src/c_api.cc

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@
1717

1818
std::vector<std::string> output;
1919

20+
extern bool cbmc_invariants_should_throw;
21+
2022
std::vector<std::string> const &
2123
translate_vector_of_string(rust::Vec<rust::String> elements)
2224
{
@@ -35,6 +37,9 @@ std::unique_ptr<api_sessiont> new_api_session()
3537
{
3638
// Create a new API session and register the default API callback for that.
3739
api_sessiont *api{new api_sessiont()};
40+
// We need to configure invariants to be throwing exceptions instead of
41+
// reporting to stderr and calling abort()
42+
cbmc_invariants_should_throw = true;
3843

3944
// This lambda needs to be non-capturing in order for it to be convertible
4045
// to a function pointer, to pass to the API.

src/libcprover-rust/src/lib.rs

Lines changed: 29 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,10 @@ pub mod ffi {
1111
// API Functions
1212
fn new_api_session() -> UniquePtr<api_sessiont>;
1313
fn get_api_version(&self) -> UniquePtr<CxxString>;
14-
fn load_model_from_files(&self, files: &CxxVector<CxxString>);
15-
fn verify_model(&self);
16-
fn validate_goto_model(&self);
17-
fn drop_unused_functions(&self);
14+
fn load_model_from_files(&self, files: &CxxVector<CxxString>) -> Result<()>;
15+
fn verify_model(&self) -> Result<()>;
16+
fn validate_goto_model(&self) -> Result<()>;
17+
fn drop_unused_functions(&self) -> Result<()>;
1818

1919
// Helper/Utility functions
2020
fn translate_vector_of_string(elements: Vec<String>) -> &'static CxxVector<CxxString>;
@@ -37,11 +37,12 @@ fn print_response(vec: &CxxVector<CxxString>) {
3737
}
3838
}
3939

40-
// To test run "CBMC_LIB_DIR=<path_to_build/libs> cargo test -- --test-threads=1 --nocapture"
40+
// To test run "CBMC_LIB_DIR=<path_to_build/libs> SAT_IMPL=minisat2 cargo test -- --test-threads=1 --nocapture"
4141
#[cfg(test)]
4242
mod tests {
4343
use super::*;
4444
use cxx::let_cxx_string;
45+
use std::process;
4546

4647
#[test]
4748
fn it_works() {
@@ -75,7 +76,11 @@ mod tests {
7576

7677
// Invoke load_model_from_files and see if the model
7778
// has been loaded.
78-
client.load_model_from_files(vect);
79+
if let Err(_) = client.load_model_from_files(vect) {
80+
eprintln!("Failed to load model from files: {:?}", vect);
81+
process::exit(1);
82+
}
83+
7984
// Validate integrity of passed goto-model.
8085
client.validate_goto_model();
8186

@@ -90,12 +95,19 @@ mod tests {
9095
let vec: Vec<String> = vec!["other/example.c".to_owned()];
9196

9297
let vect = ffi::translate_vector_of_string(vec);
93-
client.load_model_from_files(vect);
98+
99+
if let Err(_) = client.load_model_from_files(vect) {
100+
eprintln!("Failed to load model from files: {:?}", vect);
101+
process::exit(1);
102+
}
94103

95104
// Validate integrity of goto-model
96105
client.validate_goto_model();
97106

98-
client.verify_model();
107+
if let Err(_) = client.verify_model() {
108+
eprintln!("Failed to verify model from files: {:?}", vect);
109+
process::exit(1);
110+
}
99111

100112
let msgs = ffi::get_messages();
101113
print_response(msgs);
@@ -114,10 +126,17 @@ mod tests {
114126
let vect = ffi::translate_vector_of_string(vec);
115127
assert_eq!(vect.len(), 1);
116128

117-
client.load_model_from_files(vect);
129+
if let Err(_) = client.load_model_from_files(vect) {
130+
eprintln!("Failed to load model from files: {:?}", vect);
131+
process::exit(1);
132+
}
118133
// Perform a drop of any unused functions.
119-
client.drop_unused_functions();
134+
if let Err(err) = client.drop_unused_functions() {
135+
eprintln!("Error during client call: {:?}", err);
136+
process::exit(1);
137+
}
120138

139+
println!("Just before we print the messages");
121140
let msgs = ffi::get_messages();
122141
print_response(msgs);
123142
}

0 commit comments

Comments
 (0)