1
- use cxx:: { CxxString , CxxVector } ;
1
+ #![ doc = include_str ! ( "../tutorial.md" ) ]
2
+ #![ warn( missing_docs) ]
2
3
4
+ /// The main API module for interfacing with CProver tools (`cbmc`, `goto-analyzer`, etc).
3
5
#[ cxx:: bridge]
4
- pub mod ffi {
6
+ pub mod cprover_api {
5
7
6
8
unsafe extern "C++" {
7
9
include ! ( "libcprover-cpp/api.h" ) ;
8
10
include ! ( "include/c_api.h" ) ;
9
11
12
+ /// Central organisational handle of the API. This directly corresponds to the
13
+ /// C++-API type `api_sessiont`. To initiate a session interaction, call [new_api_session].
10
14
type api_sessiont ;
11
15
12
- // API Functions
16
+ /// Provide a unique pointer to the API handle. This will be required to interact
17
+ /// with the API calls, and thus, is expected to be the first call before any other
18
+ /// interaction with the API.
13
19
fn new_api_session ( ) -> UniquePtr < api_sessiont > ;
20
+
21
+ /// Return the API version - note that this is coming from the C++ API, which
22
+ /// returns the API version of CBMC (which should map to the version of `libcprover.a`)
23
+ /// the Rust API has mapped against.
14
24
fn get_api_version ( & self ) -> UniquePtr < CxxString > ;
25
+ /// Provided a C++ Vector of Strings (use [translate_vector_of_string] to translate
26
+ /// a Rust `Vec<String` into a `CxxVector<CxxString>` before passing it to the function),
27
+ /// load the models from the files in the vector and link them together.
15
28
fn load_model_from_files ( & self , files : & CxxVector < CxxString > ) -> Result < ( ) > ;
29
+ /// Execute a verification engine run against the loaded model.
30
+ /// *ATTENTION*: A model must be loaded before this function is run.
16
31
fn verify_model ( & self ) -> Result < ( ) > ;
32
+ /// Run a validation check on the goto-model that has been loaded.
33
+ /// Corresponds to the CProver CLI option `--validate-goto-model`.
17
34
fn validate_goto_model ( & self ) -> Result < ( ) > ;
35
+ /// Drop functions that aren't used from the model. Corresponds to
36
+ /// the CProver CLI option `--drop-unused-functions`
18
37
fn drop_unused_functions ( & self ) -> Result < ( ) > ;
19
38
20
- // Helper/Utility functions
21
- fn translate_vector_of_string ( elements : Vec < String > ) -> & ' static CxxVector < CxxString > ;
39
+ // WARNING: Please don't use this function - use its public interface in [ffi_util::translate_rust_vector_to_cpp].
40
+ // The reason this is here is that it's implemented on the C++ shim, and to link this function against
41
+ // its implementation it needs to be declared within the `unsafe extern "C++"` block of the FFI bridge.
42
+ #[ doc( hidden) ]
43
+ fn _translate_vector_of_string ( elements : Vec < String > ) -> & ' static CxxVector < CxxString > ;
44
+ /// Print messages accumulated into the message buffer from CProver's end.
22
45
fn get_messages ( ) -> & ' static CxxVector < CxxString > ;
23
46
}
24
-
25
- extern "Rust" {
26
- fn print_response ( vec : & CxxVector < CxxString > ) ;
27
- fn translate_response_buffer ( vec : & CxxVector < CxxString > ) -> Vec < String > ;
28
- }
29
47
}
30
48
31
- /// This is a utility function, whose job is to translate the responses from the C++
32
- /// API ( which we get in the form of a C ++ std:: vector<std: string>) into a form that
33
- /// can be easily consumed by other Rust programs.
34
- pub fn translate_response_buffer ( vec : & CxxVector < CxxString > ) -> Vec < String > {
35
- vec. iter ( )
36
- . map ( |s| s. to_string_lossy ( ) . into_owned ( ) )
37
- . collect ( )
38
- }
49
+ /// Module containing utility functions for translating between types across
50
+ /// the FFI boundary.
51
+ pub mod ffi_util {
52
+ use crate :: cprover_api:: _translate_vector_of_string;
53
+ use cxx:: CxxString ;
54
+ use cxx:: CxxVector ;
55
+
56
+ /// This function translates the responses from the C++ API (which we get in the
57
+ /// form of a C++ std::vector<std:string>) into the equivalent Rust type `Vec<String>`.
58
+ /// Dual to [translate_rust_vector_to_cpp].
59
+ pub fn translate_cpp_vector_to_rust ( vec : & CxxVector < CxxString > ) -> Vec < String > {
60
+ vec. iter ( )
61
+ . map ( |s| s. to_string_lossy ( ) . into_owned ( ) )
62
+ . collect ( )
63
+ }
39
64
40
- /// This is a utility function, whose aim is to simplify direct printing of the messages
41
- /// that we get from CBMC's C++ API. Underneath, it's using translate_response_buffer
42
- /// to translate the C++ types into Rust types and then prints out the strings contained
43
- /// in the resultant rust vector.
44
- pub fn print_response ( vec : & CxxVector < CxxString > ) {
45
- let vec: Vec < String > = translate_response_buffer ( vec) ;
65
+ /// This function aims to simplify direct printing of the messages that we get
66
+ /// from CBMC's C++ API.
67
+ pub fn print_response ( vec : & Vec < String > ) {
68
+ for s in vec {
69
+ println ! ( "{}" , s) ;
70
+ }
71
+ }
46
72
47
- for s in vec {
48
- println ! ( "{}" , s) ;
73
+ /// Translate a Rust `Vec<String>` into a C++ acceptable `std::vector<std::string>`.
74
+ /// Dual to [translate_cpp_vector_to_rust].
75
+ pub fn translate_rust_vector_to_cpp ( elements : Vec < String > ) -> & ' static CxxVector < CxxString > {
76
+ _translate_vector_of_string ( elements)
49
77
}
50
78
}
51
79
52
- // To test run "CBMC_LIB_DIR=<path_to_build/libs> SAT_IMPL=minisat2 cargo test -- --test-threads=1 --nocapture"
80
+ // To test run "CBMC_LIB_DIR=<path_to_build/libs> CBMC_VERSION=<version> cargo test -- --test-threads=1 --nocapture"
53
81
#[ cfg( test) ]
54
82
mod tests {
55
83
use super :: * ;
@@ -58,7 +86,7 @@ mod tests {
58
86
59
87
#[ test]
60
88
fn it_works ( ) {
61
- let client = ffi :: new_api_session ( ) ;
89
+ let client = cprover_api :: new_api_session ( ) ;
62
90
let result = client. get_api_version ( ) ;
63
91
64
92
let_cxx_string ! ( expected_version = "0.1" ) ;
@@ -69,21 +97,21 @@ mod tests {
69
97
fn translate_vector_of_rust_string_to_cpp ( ) {
70
98
let vec: Vec < String > = vec ! [ "other/example.c" . to_owned( ) , "/tmp/example2.c" . to_owned( ) ] ;
71
99
72
- let vect = ffi :: translate_vector_of_string ( vec) ;
100
+ let vect = ffi_util :: translate_rust_vector_to_cpp ( vec) ;
73
101
assert_eq ! ( vect. len( ) , 2 ) ;
74
102
}
75
103
76
104
#[ test]
77
105
fn it_can_load_model_from_file ( ) {
78
- let binding = ffi :: new_api_session ( ) ;
106
+ let binding = cprover_api :: new_api_session ( ) ;
79
107
let client = match binding. as_ref ( ) {
80
108
Some ( api_ref) => api_ref,
81
109
None => panic ! ( "Failed to acquire API session handle" ) ,
82
110
} ;
83
111
84
112
let vec: Vec < String > = vec ! [ "other/example.c" . to_owned( ) ] ;
85
113
86
- let vect = ffi :: translate_vector_of_string ( vec) ;
114
+ let vect = ffi_util :: translate_rust_vector_to_cpp ( vec) ;
87
115
assert_eq ! ( vect. len( ) , 1 ) ;
88
116
89
117
// Invoke load_model_from_files and see if the model
@@ -104,21 +132,21 @@ mod tests {
104
132
// This is also why a print instruction is commented out (as a guide for someone
105
133
// else in case they want to inspect the output).
106
134
let validation_msg = "Validating consistency of goto-model supplied to API session" ;
107
- let msgs = ffi :: get_messages ( ) ;
108
- let msgs_assert = translate_response_buffer ( msgs) . clone ( ) ;
135
+ let msgs = cprover_api :: get_messages ( ) ;
136
+ let msgs_assert = ffi_util :: translate_cpp_vector_to_rust ( msgs) . clone ( ) ;
109
137
110
138
assert ! ( msgs_assert. contains( & String :: from( validation_msg) ) ) ;
111
139
112
- // print_response(msgs );
140
+ // ffi_util:: print_response(msgs_assert );
113
141
}
114
142
115
143
#[ test]
116
144
fn it_can_verify_the_loaded_model ( ) {
117
- let client = ffi :: new_api_session ( ) ;
145
+ let client = cprover_api :: new_api_session ( ) ;
118
146
119
147
let vec: Vec < String > = vec ! [ "other/example.c" . to_owned( ) ] ;
120
148
121
- let vect = ffi :: translate_vector_of_string ( vec) ;
149
+ let vect = ffi_util :: translate_rust_vector_to_cpp ( vec) ;
122
150
123
151
if let Err ( _) = client. load_model_from_files ( vect) {
124
152
eprintln ! ( "Failed to load model from files: {:?}" , vect) ;
@@ -138,23 +166,23 @@ mod tests {
138
166
139
167
let verification_msg = "VERIFICATION FAILED" ;
140
168
141
- let msgs = ffi :: get_messages ( ) ;
142
- let msgs_assert = translate_response_buffer ( msgs) . clone ( ) ;
169
+ let msgs = cprover_api :: get_messages ( ) ;
170
+ let msgs_assert = ffi_util :: translate_cpp_vector_to_rust ( msgs) . clone ( ) ;
143
171
144
172
assert ! ( msgs_assert. contains( & String :: from( verification_msg) ) ) ;
145
173
}
146
174
147
175
#[ test]
148
176
fn it_can_drop_unused_functions_from_model ( ) {
149
- let binding = ffi :: new_api_session ( ) ;
177
+ let binding = cprover_api :: new_api_session ( ) ;
150
178
let client = match binding. as_ref ( ) {
151
179
Some ( api_ref) => api_ref,
152
180
None => panic ! ( "Failed to acquire API session handle" ) ,
153
181
} ;
154
182
155
183
let vec: Vec < String > = vec ! [ "other/example.c" . to_owned( ) ] ;
156
184
157
- let vect = ffi :: translate_vector_of_string ( vec) ;
185
+ let vect = ffi_util :: translate_rust_vector_to_cpp ( vec) ;
158
186
assert_eq ! ( vect. len( ) , 1 ) ;
159
187
160
188
if let Err ( _) = client. load_model_from_files ( vect) {
@@ -171,8 +199,8 @@ mod tests {
171
199
let instrumentation_msg = "Performing instrumentation pass: dropping unused functions" ;
172
200
let instrumentation_msg2 = "Dropping 8 of 11 functions (3 used)" ;
173
201
174
- let msgs = ffi :: get_messages ( ) ;
175
- let msgs_assert = translate_response_buffer ( msgs) . clone ( ) ;
202
+ let msgs = cprover_api :: get_messages ( ) ;
203
+ let msgs_assert = ffi_util :: translate_cpp_vector_to_rust ( msgs) . clone ( ) ;
176
204
177
205
assert ! ( msgs_assert. contains( & String :: from( instrumentation_msg) ) ) ;
178
206
assert ! ( msgs_assert. contains( & String :: from( instrumentation_msg2) ) ) ;
0 commit comments