Skip to content

Commit c43f13a

Browse files
authored
Merge pull request #7538 from NlightNFotis/structured_verification_results
Add a structured verification results class in the C++ API
2 parents 417d362 + 35bf812 commit c43f13a

File tree

6 files changed

+379
-0
lines changed

6 files changed

+379
-0
lines changed

src/libcprover-cpp/api.cpp

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -177,6 +177,60 @@ void api_sessiont::verify_model() const
177177
verifier.report();
178178
}
179179

180+
// TODO: This is a temporary function - it's basically `verify_model`, tweaked
181+
// to return the results in a structured format. It's temporary in the sense
182+
// that this will get folded into the `verify_model` function, but I want to do
183+
// this slightly later because modifying the interface of `verify_model` from
184+
// the C++ end breaks the Rust API for now, and I want to take steps one at
185+
// a time.
186+
verification_resultt api_sessiont::produce_results()
187+
{
188+
PRECONDITION(implementation->model);
189+
190+
// Remove inline assembler; this needs to happen before adding the library.
191+
remove_asm(*implementation->model);
192+
193+
// add the library
194+
messaget log{*implementation->message_handler};
195+
log.status() << "Adding CPROVER library (" << config.ansi_c.arch << ")"
196+
<< messaget::eom;
197+
link_to_library(
198+
*implementation->model,
199+
*implementation->message_handler,
200+
cprover_c_library_factory);
201+
202+
// Common removal of types and complex constructs
203+
if(::process_goto_program(
204+
*implementation->model, *implementation->options, log))
205+
{
206+
return {};
207+
}
208+
209+
// add failed symbols
210+
// needs to be done before pointer analysis
211+
add_failed_symbols(implementation->model->symbol_table);
212+
213+
// label the assertions
214+
// This must be done after adding assertions and
215+
// before using the argument of the "property" option.
216+
// Do not re-label after using the property slicer because
217+
// this would cause the property identifiers to change.
218+
label_properties(*implementation->model);
219+
220+
remove_skip(*implementation->model);
221+
222+
ui_message_handlert ui_message_handler(*implementation->message_handler);
223+
all_properties_verifier_with_trace_storaget<multi_path_symex_checkert>
224+
verifier(
225+
*implementation->options, ui_message_handler, *implementation->model);
226+
verification_resultt result;
227+
auto results = verifier();
228+
result.set_result(results);
229+
auto properties = verifier.get_properties();
230+
result.set_properties(properties);
231+
return result;
232+
}
233+
180234
void api_sessiont::drop_unused_functions() const
181235
{
182236
INVARIANT(

src/libcprover-cpp/api.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ struct api_session_implementationt;
1818
// as the design principle is to be followed.)
1919

2020
#include "api_options.h" // IWYU pragma: keep
21+
#include "verification_result.h" // IWYU pragma: keep
2122

2223
/// Opaque message type. Properties of messages to be fetched through further
2324
/// api calls.
@@ -80,6 +81,9 @@ struct api_sessiont
8081
// A simple API version information function.
8182
std::unique_ptr<std::string> get_api_version() const;
8283

84+
/// Run the verification engine and return results.
85+
verification_resultt produce_results();
86+
8387
private:
8488
std::unique_ptr<api_session_implementationt> implementation;
8589
};
Lines changed: 151 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,151 @@
1+
// Copyright (c) 2023 Fotis Koutoulakis for Diffblue Ltd.
2+
3+
/// \file
4+
/// Interface for the various verification engines providing results
5+
// in a structured form.
6+
7+
#include "verification_result.h"
8+
9+
#include <util/invariant.h>
10+
#include <util/make_unique.h>
11+
12+
#include <goto-checker/properties.h>
13+
14+
#include <algorithm>
15+
#include <string>
16+
#include <vector>
17+
18+
class verification_resultt::verification_result_implt
19+
{
20+
propertiest _properties;
21+
resultt _verifier_result;
22+
23+
public:
24+
verification_result_implt() = default;
25+
verification_result_implt(const verification_result_implt &other) = default;
26+
~verification_result_implt() = default;
27+
28+
void set_properties(propertiest &properties);
29+
void set_result(resultt &verification_result);
30+
31+
resultt get_result();
32+
const propertiest &get_properties();
33+
};
34+
35+
// Impl
36+
37+
void verification_resultt::verification_result_implt::set_properties(
38+
propertiest &properties)
39+
{
40+
_properties = properties;
41+
}
42+
43+
void verification_resultt::verification_result_implt::set_result(
44+
resultt &result)
45+
{
46+
_verifier_result = result;
47+
}
48+
49+
resultt verification_resultt::verification_result_implt::get_result()
50+
{
51+
return _verifier_result;
52+
}
53+
54+
const propertiest &
55+
verification_resultt::verification_result_implt::get_properties()
56+
{
57+
return _properties;
58+
}
59+
60+
// Verification_result
61+
62+
verification_resultt::verification_resultt()
63+
: _impl(util_make_unique<verification_resultt::verification_result_implt>())
64+
{
65+
}
66+
67+
verification_resultt::~verification_resultt()
68+
{
69+
}
70+
71+
verification_resultt::verification_resultt(const verification_resultt &other)
72+
: _impl(util_make_unique<verification_result_implt>(*other._impl))
73+
{
74+
}
75+
76+
verification_resultt &
77+
verification_resultt::operator=(verification_resultt &&) = default;
78+
verification_resultt &
79+
verification_resultt::operator=(const verification_resultt &other)
80+
{
81+
*_impl = *other._impl;
82+
return *this;
83+
}
84+
85+
void verification_resultt::set_properties(propertiest &properties)
86+
{
87+
_impl->set_properties(properties);
88+
}
89+
90+
void verification_resultt::set_result(resultt &result)
91+
{
92+
_impl->set_result(result);
93+
}
94+
95+
verifier_resultt verification_resultt::final_result() const
96+
{
97+
switch(_impl->get_result())
98+
{
99+
case resultt::ERROR:
100+
return verifier_resultt::ERROR;
101+
case resultt::FAIL:
102+
return verifier_resultt::FAIL;
103+
case resultt::PASS:
104+
return verifier_resultt::PASS;
105+
case resultt::UNKNOWN:
106+
return verifier_resultt::UNKNOWN;
107+
}
108+
// Required to silence compiler warnings that are promoted as errors!
109+
UNREACHABLE;
110+
}
111+
112+
std::vector<std::string> verification_resultt::get_property_ids() const
113+
{
114+
std::vector<std::string> result;
115+
for(const auto &props : _impl->get_properties())
116+
{
117+
result.push_back(as_string(props.first));
118+
}
119+
return result;
120+
}
121+
122+
std::string verification_resultt::get_property_description(
123+
const std::string &property_id) const
124+
{
125+
auto irepidt_property = irep_idt(property_id);
126+
const auto description =
127+
_impl->get_properties().at(irepidt_property).description;
128+
return description;
129+
}
130+
131+
prop_statust
132+
verification_resultt::get_property_status(const std::string &property_id) const
133+
{
134+
auto irepidt_property = irep_idt(property_id);
135+
switch(_impl->get_properties().at(irepidt_property).status)
136+
{
137+
case property_statust::ERROR:
138+
return prop_statust::ERROR;
139+
case property_statust::FAIL:
140+
return prop_statust::FAIL;
141+
case property_statust::NOT_CHECKED:
142+
return prop_statust::NOT_CHECKED;
143+
case property_statust::NOT_REACHABLE:
144+
return prop_statust::NOT_REACHABLE;
145+
case property_statust::PASS:
146+
return prop_statust::PASS;
147+
case property_statust::UNKNOWN:
148+
return prop_statust::UNKNOWN;
149+
}
150+
UNREACHABLE;
151+
}
Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
// Copyright (c) 2023 Fotis Koutoulakis for Diffblue Ltd.
2+
3+
/// \file
4+
/// Interface for the various verification engines providing results
5+
// in a structured form.
6+
7+
#ifndef CPROVER_LIBCPROVER_CPP_VERIFICATION_RESULT_H
8+
#define CPROVER_LIBCPROVER_CPP_VERIFICATION_RESULT_H
9+
10+
#include <map>
11+
#include <memory>
12+
#include <string>
13+
#include <vector>
14+
15+
#ifndef USE_STD_STRING
16+
# define USE_DSTRING
17+
#endif
18+
19+
#ifdef USE_DSTRING
20+
class dstringt;
21+
typedef dstringt irep_idt;
22+
#else
23+
typedef std::string irep_idt;
24+
#endif
25+
26+
struct property_infot;
27+
using propertiest = std::map<irep_idt, property_infot>;
28+
enum class resultt;
29+
30+
// The enumerations here mirror the ones in properties.h.
31+
// The reason we do so is that we want to expose the same information
32+
// to users of the API, without including (and therefore, exposing)
33+
// CBMC internal headers.
34+
35+
enum class prop_statust
36+
{
37+
/// The property was not checked (also used for initialization)
38+
NOT_CHECKED,
39+
/// The checker was unable to determine the status of the property
40+
UNKNOWN,
41+
/// The property was proven to be unreachable
42+
NOT_REACHABLE,
43+
/// The property was not violated
44+
PASS,
45+
/// The property was violated
46+
FAIL,
47+
/// An error occurred during goto checking
48+
ERROR
49+
};
50+
51+
enum class verifier_resultt
52+
{
53+
UNKNOWN,
54+
/// No properties were violated
55+
PASS,
56+
/// Some properties were violated
57+
FAIL,
58+
/// An error occurred during goto checking
59+
ERROR
60+
};
61+
62+
struct verification_resultt
63+
{
64+
verification_resultt();
65+
verification_resultt(const verification_resultt &other);
66+
~verification_resultt();
67+
verification_resultt &operator=(verification_resultt &&);
68+
verification_resultt &operator=(const verification_resultt &other);
69+
70+
void set_result(resultt &result);
71+
void set_properties(propertiest &properties);
72+
73+
verifier_resultt final_result() const;
74+
std::vector<std::string> get_property_ids() const;
75+
std::string get_property_description(const std::string &property_id) const;
76+
prop_statust get_property_status(const std::string &property_id) const;
77+
78+
private:
79+
class verification_result_implt;
80+
std::unique_ptr<verification_result_implt> _impl;
81+
};
82+
83+
#endif // CPROVER_GOTO_CHECKER_VERIFICATION_RESULT_H

unit/libcprover-cpp/test2.c

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
// Input file to test reading through API, not for compiling!
2+
// Compared to test.c, this is supposed to have a passing assertion.
3+
4+
int main(int argc, char *argv[])
5+
{
6+
int arr[] = {0, 1, 2, 3, 4};
7+
__CPROVER_assert(arr[3] == 3, "expected success: arr[3] to be 3");
8+
}

0 commit comments

Comments
 (0)