Skip to content

Commit 2e04b54

Browse files
Merge pull request #4217 from peterschrammel/move-bmct-jbmc
Move cbmc/bmc and all_properties to jbmc
2 parents 039ac77 + 14109a4 commit 2e04b54

13 files changed

+499
-453
lines changed

jbmc/src/jbmc/Makefile

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
1-
SRC = jbmc_main.cpp \
1+
SRC = all_properties.cpp \
2+
bmc.cpp \
3+
jbmc_main.cpp \
24
jbmc_parse_options.cpp \
35
# Empty last line
46

@@ -39,8 +41,6 @@ OBJ += ../$(CPROVER_DIR)/src/ansi-c/ansi-c$(LIBEXT) \
3941
../$(CPROVER_DIR)/src/util/util$(LIBEXT) \
4042
../miniz/miniz$(OBJEXT) \
4143
../$(CPROVER_DIR)/src/json/json$(LIBEXT) \
42-
../$(CPROVER_DIR)/src/cbmc/all_properties$(OBJEXT) \
43-
../$(CPROVER_DIR)/src/cbmc/bmc$(OBJEXT) \
4444
# Empty last line
4545

4646
INCLUDES= -I .. -I ../$(CPROVER_DIR)/src

jbmc/src/jbmc/all_properties.cpp

Lines changed: 303 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,303 @@
1+
/*******************************************************************\
2+
3+
Module: Symbolic Execution of ANSI-C
4+
5+
Author: Daniel Kroening, [email protected]
6+
7+
\*******************************************************************/
8+
9+
/// \file
10+
/// Symbolic Execution of ANSI-C
11+
12+
#include "all_properties_class.h"
13+
14+
#include <algorithm>
15+
#include <chrono>
16+
17+
#include <goto-checker/bmc_util.h>
18+
#include <goto-checker/report_util.h>
19+
20+
#include <util/json.h>
21+
#include <util/xml.h>
22+
23+
#include <solvers/prop/prop_conv.h>
24+
#include <solvers/sat/satcheck.h>
25+
26+
#include <goto-programs/json_goto_trace.h>
27+
#include <goto-programs/xml_goto_trace.h>
28+
#include <goto-symex/build_goto_trace.h>
29+
30+
void bmc_all_propertiest::goal_covered(const cover_goalst::goalt &)
31+
{
32+
for(auto &g : goal_map)
33+
{
34+
// failed already?
35+
if(g.second.status == goalt::statust::FAILURE)
36+
continue;
37+
38+
// check whether failed
39+
for(auto &c : g.second.instances)
40+
{
41+
literalt cond = c->cond_literal;
42+
43+
if(solver.l_get(cond).is_false())
44+
{
45+
g.second.status = goalt::statust::FAILURE;
46+
build_goto_trace(bmc.equation, c, solver, bmc.ns, g.second.goto_trace);
47+
break;
48+
}
49+
}
50+
}
51+
}
52+
53+
safety_checkert::resultt bmc_all_propertiest::operator()()
54+
{
55+
status() << "Passing problem to " << solver.decision_procedure_text() << eom;
56+
57+
auto solver_start = std::chrono::steady_clock::now();
58+
59+
convert_symex_target_equation(
60+
bmc.equation, bmc.prop_conv, get_message_handler());
61+
bmc.freeze_program_variables();
62+
63+
// Collect _all_ goals in `goal_map'.
64+
// This maps property IDs to 'goalt'
65+
forall_goto_functions(f_it, goto_functions)
66+
forall_goto_program_instructions(i_it, f_it->second.body)
67+
if(i_it->is_assert())
68+
goal_map[i_it->source_location.get_property_id()] = goalt(*i_it);
69+
70+
// get the conditions for these goals from formula
71+
// collect all 'instances' of the properties
72+
for(symex_target_equationt::SSA_stepst::iterator it =
73+
bmc.equation.SSA_steps.begin();
74+
it != bmc.equation.SSA_steps.end();
75+
it++)
76+
{
77+
if(it->is_assert())
78+
{
79+
irep_idt property_id = it->get_property_id();
80+
81+
if(property_id.empty())
82+
continue;
83+
84+
if(it->source.pc->is_goto())
85+
{
86+
// goto may yield an unwinding assertion
87+
goal_map[property_id].description = it->comment;
88+
}
89+
90+
goal_map[property_id].instances.push_back(it);
91+
}
92+
}
93+
94+
do_before_solving();
95+
96+
cover_goalst cover_goals(solver);
97+
98+
cover_goals.register_observer(*this);
99+
100+
for(const auto &g : goal_map)
101+
{
102+
// Our goal is to falsify a property, i.e., we will
103+
// add the negation of the property as goal.
104+
literalt p = !solver.convert(g.second.as_expr());
105+
cover_goals.add(p);
106+
}
107+
108+
status() << "Running " << solver.decision_procedure_text() << eom;
109+
110+
bool error = false;
111+
112+
const decision_proceduret::resultt result =
113+
cover_goals(get_message_handler());
114+
115+
if(result == decision_proceduret::resultt::D_ERROR)
116+
{
117+
error = true;
118+
for(auto &g : goal_map)
119+
if(g.second.status == goalt::statust::UNKNOWN)
120+
g.second.status = goalt::statust::ERROR;
121+
}
122+
else
123+
{
124+
for(auto &g : goal_map)
125+
if(g.second.status == goalt::statust::UNKNOWN)
126+
g.second.status = goalt::statust::SUCCESS;
127+
}
128+
129+
{
130+
auto solver_stop = std::chrono::steady_clock::now();
131+
132+
statistics()
133+
<< "Runtime decision procedure: "
134+
<< std::chrono::duration<double>(solver_stop - solver_start).count()
135+
<< "s" << eom;
136+
}
137+
138+
// report
139+
report(cover_goals);
140+
141+
if(error)
142+
return safety_checkert::resultt::ERROR;
143+
144+
bool safe = (cover_goals.number_covered() == 0);
145+
146+
if(safe)
147+
report_success(bmc.ui_message_handler); // legacy, might go away
148+
else
149+
report_failure(bmc.ui_message_handler); // legacy, might go away
150+
151+
return safe ? safety_checkert::resultt::SAFE
152+
: safety_checkert::resultt::UNSAFE;
153+
}
154+
155+
void bmc_all_propertiest::report(const cover_goalst &cover_goals)
156+
{
157+
switch(bmc.ui_message_handler.get_ui())
158+
{
159+
case ui_message_handlert::uit::PLAIN:
160+
{
161+
result() << "\n** Results:" << eom;
162+
163+
// collect goals in a vector
164+
std::vector<goal_mapt::const_iterator> goals;
165+
166+
for(auto g_it = goal_map.begin(); g_it != goal_map.end(); g_it++)
167+
goals.push_back(g_it);
168+
169+
// now determine an ordering for those goals:
170+
// 1. alphabetical ordering of file name
171+
// 2. numerical ordering of line number
172+
// 3. alphabetical ordering of goal ID
173+
std::sort(
174+
goals.begin(),
175+
goals.end(),
176+
[](goal_mapt::const_iterator git1, goal_mapt::const_iterator git2) {
177+
const auto &g1 = git1->second.source_location;
178+
const auto &g2 = git2->second.source_location;
179+
if(g1.get_file() != g2.get_file())
180+
return id2string(g1.get_file()) < id2string(g2.get_file());
181+
else if(!g1.get_line().empty() && !g2.get_line().empty())
182+
return std::stoul(id2string(g1.get_line())) <
183+
std::stoul(id2string(g2.get_line()));
184+
else
185+
return id2string(git1->first) < id2string(git2->first);
186+
});
187+
188+
// now show in the order we have determined
189+
190+
irep_idt previous_function;
191+
irep_idt current_file;
192+
for(const auto &g : goals)
193+
{
194+
const auto &l = g->second.source_location;
195+
196+
if(l.get_function() != previous_function)
197+
{
198+
if(!previous_function.empty())
199+
result() << '\n';
200+
previous_function = l.get_function();
201+
if(!previous_function.empty())
202+
{
203+
current_file = l.get_file();
204+
if(!current_file.empty())
205+
result() << current_file << ' ';
206+
if(!l.get_function().empty())
207+
result() << "function " << l.get_function();
208+
result() << eom;
209+
}
210+
}
211+
212+
result() << faint << '[' << g->first << "] " << reset;
213+
214+
if(l.get_file() != current_file)
215+
result() << "file " << l.get_file() << ' ';
216+
217+
if(!l.get_line().empty())
218+
result() << "line " << l.get_line() << ' ';
219+
220+
result() << g->second.description << ": ";
221+
222+
if(g->second.status == goalt::statust::SUCCESS)
223+
result() << green;
224+
else
225+
result() << red;
226+
227+
result() << g->second.status_string() << reset << eom;
228+
}
229+
230+
if(bmc.options.get_bool_option("trace"))
231+
{
232+
for(const auto &g : goal_map)
233+
if(g.second.status == goalt::statust::FAILURE)
234+
{
235+
result() << "\n"
236+
<< "Trace for " << g.first << ":"
237+
<< "\n";
238+
show_goto_trace(
239+
result(), bmc.ns, g.second.goto_trace, bmc.trace_options());
240+
result() << eom;
241+
}
242+
}
243+
244+
status() << "\n** " << cover_goals.number_covered() << " of "
245+
<< cover_goals.size() << " failed (" << cover_goals.iterations()
246+
<< " iteration" << (cover_goals.iterations() == 1 ? "" : "s")
247+
<< ")" << eom;
248+
}
249+
break;
250+
251+
case ui_message_handlert::uit::XML_UI:
252+
{
253+
for(const auto &g : goal_map)
254+
{
255+
xmlt xml_result(
256+
"result",
257+
{{"property", id2string(g.first)},
258+
{"status", g.second.status_string()}},
259+
{});
260+
261+
if(g.second.status == goalt::statust::FAILURE)
262+
convert(bmc.ns, g.second.goto_trace, xml_result.new_element());
263+
264+
result() << xml_result;
265+
}
266+
break;
267+
}
268+
269+
case ui_message_handlert::uit::JSON_UI:
270+
{
271+
if(result().tellp() > 0)
272+
result() << eom; // force end of previous message
273+
json_stream_objectt &json_result =
274+
bmc.ui_message_handler.get_json_stream().push_back_stream_object();
275+
json_stream_arrayt &result_array =
276+
json_result.push_back_stream_array("result");
277+
278+
for(const auto &g : goal_map)
279+
{
280+
json_stream_objectt &result = result_array.push_back_stream_object();
281+
result["property"] = json_stringt(g.first);
282+
result["description"] = json_stringt(g.second.description);
283+
result["status"] = json_stringt(g.second.status_string());
284+
285+
if(g.second.status == goalt::statust::FAILURE)
286+
{
287+
json_stream_arrayt &json_trace = result.push_back_stream_array("trace");
288+
convert<json_stream_arrayt>(
289+
bmc.ns, g.second.goto_trace, json_trace, bmc.trace_options());
290+
}
291+
}
292+
}
293+
break;
294+
}
295+
}
296+
297+
safety_checkert::resultt
298+
bmct::all_properties(const goto_functionst &goto_functions)
299+
{
300+
bmc_all_propertiest bmc_all_properties(goto_functions, prop_conv, *this);
301+
bmc_all_properties.set_message_handler(get_message_handler());
302+
return bmc_all_properties();
303+
}

0 commit comments

Comments
 (0)