Skip to content

Commit c76d69a

Browse files
authored
Merge pull request #4162 from peterschrammel/fix-trace-truncation
Correctly truncate error traces
2 parents d5740b3 + cbd61b2 commit c76d69a

13 files changed

+176
-34
lines changed
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
#include <assert.h>
2+
3+
int main(int argc, char **argv)
4+
{
5+
assert(4 != argc);
6+
argc++;
7+
argc--;
8+
assert(argc >= 1);
9+
assert(argc != 4);
10+
argc++;
11+
argc--;
12+
assert(argc + 1 != 5);
13+
return 0;
14+
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
CORE
2+
main.c
3+
--trace
4+
activate-multi-line-match
5+
EXIT=10
6+
SIGNAL=0
7+
VERIFICATION FAILED
8+
Trace for main\.assertion\.1:(\n.*){16} assertion 4 \!= argc(\n.*){5}Trace for main\.assertion\.3:(\n.*){30} assertion argc != 4(\n.*){5}Trace for main\.assertion\.4:(\n.*){44} assertion argc \+ 1 != 5
9+
\*\* 3 of 4 failed
10+
--
11+
^warning: ignoring
12+
--
13+
We have one counterexample violating multiple properties.
14+
Make sure the traces are correctly truncated.

src/goto-checker/all_properties_verifier_with_trace_storage.h

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ Author: Daniel Kroening, Peter Schrammel
1414

1515
#include "goto_verifier.h"
1616

17+
#include "bmc_util.h"
1718
#include "goto_trace_storage.h"
1819
#include "incremental_goto_checker.h"
1920
#include "properties.h"
@@ -37,11 +38,23 @@ class all_properties_verifier_with_trace_storaget : public goto_verifiert
3738

3839
resultt operator()() override
3940
{
40-
while(incremental_goto_checker(properties).progress !=
41-
incremental_goto_checkert::resultt::progresst::DONE)
41+
while(true)
4242
{
43-
// we've got an error trace; store it and link it to the failed properties
44-
(void)traces.insert(incremental_goto_checker.build_trace());
43+
const auto result = incremental_goto_checker(properties);
44+
if(result.progress == incremental_goto_checkert::resultt::progresst::DONE)
45+
break;
46+
47+
// we've got an error trace
48+
message_building_error_trace(log);
49+
for(const auto &property_id : result.updated_properties)
50+
{
51+
if(properties.at(property_id).status == property_statust::FAIL)
52+
{
53+
// get correctly truncated error trace for property and store it
54+
(void)traces.insert(
55+
incremental_goto_checker.build_trace(property_id));
56+
}
57+
}
4558

4659
++iterations;
4760
}

src/goto-checker/bmc_util.cpp

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,19 +32,35 @@ Author: Daniel Kroening, Peter Schrammel
3232

3333
#include "symex_bmc.h"
3434

35+
void message_building_error_trace(messaget &log)
36+
{
37+
log.status() << "Building error trace" << messaget::eom;
38+
}
39+
3540
void build_error_trace(
3641
goto_tracet &goto_trace,
3742
const namespacet &ns,
3843
const symex_target_equationt &symex_target_equation,
3944
const prop_convt &prop_conv,
4045
ui_message_handlert &ui_message_handler)
4146
{
42-
messaget msg(ui_message_handler);
43-
msg.status() << "Building error trace" << messaget::eom;
47+
messaget log(ui_message_handler);
48+
message_building_error_trace(log);
4449

4550
build_goto_trace(symex_target_equation, prop_conv, ns, goto_trace);
4651
}
4752

53+
ssa_step_predicatet
54+
ssa_step_matches_failing_property(const irep_idt &property_id)
55+
{
56+
return [property_id](
57+
symex_target_equationt::SSA_stepst::const_iterator step,
58+
const prop_convt &prop_conv) {
59+
return step->is_assert() && step->get_property_id() == property_id &&
60+
prop_conv.l_get(step->cond_literal).is_false();
61+
};
62+
}
63+
4864
void output_error_trace(
4965
const goto_tracet &goto_trace,
5066
const namespacet &ns,

src/goto-checker/bmc_util.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ Author: Daniel Kroening, Peter Schrammel
1515
#include <memory>
1616

1717
#include <goto-programs/safety_checker.h>
18+
#include <goto-symex/build_goto_trace.h>
1819
#include <goto-symex/path_storage.h>
1920

2021
#include "properties.h"
@@ -35,6 +36,14 @@ void convert_symex_target_equation(
3536
prop_convt &,
3637
message_handlert &);
3738

39+
/// Returns a function that checks whether an SSA step is an assertion
40+
/// with \p property_id. Usually used for `build_goto_trace`.
41+
ssa_step_predicatet
42+
ssa_step_matches_failing_property(const irep_idt &property_id);
43+
44+
/// Outputs a message that an error trace is being built
45+
void message_building_error_trace(messaget &);
46+
3847
void build_error_trace(
3948
goto_tracet &,
4049
const namespacet &,

src/goto-checker/cover_goals_verifier_with_trace_storage.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ Author: Daniel Kroening, Peter Schrammel
1414

1515
#include "goto_verifier.h"
1616

17+
#include "bmc_util.h"
1718
#include "cover_goals_report_util.h"
1819
#include "goto_trace_storage.h"
1920
#include "incremental_goto_checker.h"
@@ -41,7 +42,8 @@ class cover_goals_verifier_with_trace_storaget : public goto_verifiert
4142
incremental_goto_checkert::resultt::progresst::DONE)
4243
{
4344
// we've got a trace; store it and link it to the covered goals
44-
(void)traces.insert_all(incremental_goto_checker.build_trace());
45+
message_building_error_trace(log);
46+
(void)traces.insert_all(incremental_goto_checker.build_full_trace());
4547

4648
++iterations;
4749
}

src/goto-checker/goto_trace_provider.h

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@ Author: Daniel Kroening, Peter Schrammel
1212
#ifndef CPROVER_GOTO_CHECKER_GOTO_TRACE_PROVIDER_H
1313
#define CPROVER_GOTO_CHECKER_GOTO_TRACE_PROVIDER_H
1414

15+
#include <util/irep.h>
16+
1517
class goto_tracet;
1618
class namespacet;
1719

@@ -20,8 +22,15 @@ class namespacet;
2022
class goto_trace_providert
2123
{
2224
public:
23-
/// Builds and returns a trace
24-
virtual goto_tracet build_trace() const = 0;
25+
/// Builds and returns the complete trace
26+
virtual goto_tracet build_full_trace() const = 0;
27+
28+
/// Builds and returns the trace up to the first failed property
29+
virtual goto_tracet build_shortest_trace() const = 0;
30+
31+
/// Builds and returns the trace for the FAILed property
32+
/// with the given \p property_id
33+
virtual goto_tracet build_trace(const irep_idt &property_id) const = 0;
2534

2635
/// Returns the namespace associated with the traces
2736
virtual const namespacet &get_namespace() const = 0;

src/goto-checker/multi_path_symex_checker.cpp

Lines changed: 29 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -109,20 +109,44 @@ operator()(propertiest &properties)
109109
return result;
110110
}
111111

112-
goto_tracet multi_path_symex_checkert::build_trace() const
112+
goto_tracet multi_path_symex_checkert::build_full_trace() const
113+
{
114+
goto_tracet goto_trace;
115+
build_goto_trace(
116+
equation,
117+
equation.SSA_steps.end(),
118+
property_decider.get_solver(),
119+
ns,
120+
goto_trace);
121+
122+
return goto_trace;
123+
}
124+
125+
goto_tracet multi_path_symex_checkert::build_shortest_trace() const
113126
{
114127
if(options.get_bool_option("beautify"))
115128
{
116129
counterexample_beautificationt()(
117130
dynamic_cast<boolbvt &>(property_decider.get_solver()), equation);
118131
}
132+
119133
goto_tracet goto_trace;
120-
::build_error_trace(
121-
goto_trace,
122-
ns,
134+
build_goto_trace(equation, property_decider.get_solver(), ns, goto_trace);
135+
136+
return goto_trace;
137+
}
138+
139+
goto_tracet
140+
multi_path_symex_checkert::build_trace(const irep_idt &property_id) const
141+
{
142+
goto_tracet goto_trace;
143+
build_goto_trace(
123144
equation,
145+
ssa_step_matches_failing_property(property_id),
124146
property_decider.get_solver(),
125-
ui_message_handler);
147+
ns,
148+
goto_trace);
149+
126150
return goto_trace;
127151
}
128152

src/goto-checker/multi_path_symex_checker.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,9 @@ class multi_path_symex_checkert : public multi_path_symex_only_checkert,
3939
/// in P_i. Such additional properties will be ignored.
4040
resultt operator()(propertiest &) override;
4141

42-
goto_tracet build_trace() const override;
42+
goto_tracet build_full_trace() const override;
43+
goto_tracet build_shortest_trace() const override;
44+
goto_tracet build_trace(const irep_idt &) const override;
4345
const namespacet &get_namespace() const override;
4446

4547
void output_error_witness(const goto_tracet &) override;

src/goto-checker/report_util.cpp

Lines changed: 21 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -175,14 +175,9 @@ static void output_single_property_plain(
175175
<< messaget::eom;
176176
}
177177

178-
static void
179-
output_properties_plain(const propertiest &properties, messaget &log)
178+
static std::vector<propertiest::const_iterator>
179+
get_sorted_properties(const propertiest &properties)
180180
{
181-
if(properties.empty())
182-
return;
183-
184-
log.result() << "\n** Results:" << messaget::eom;
185-
// collect properties in a vector
186181
std::vector<propertiest::const_iterator> sorted_properties;
187182
for(auto p_it = properties.begin(); p_it != properties.end(); p_it++)
188183
sorted_properties.push_back(p_it);
@@ -204,6 +199,17 @@ output_properties_plain(const propertiest &properties, messaget &log)
204199
else
205200
return id2string(pit1->first) < id2string(pit2->first);
206201
});
202+
return sorted_properties;
203+
}
204+
205+
static void output_properties_plain(
206+
const std::vector<propertiest::const_iterator> &sorted_properties,
207+
messaget &log)
208+
{
209+
if(sorted_properties.empty())
210+
return;
211+
212+
log.result() << "\n** Results:" << messaget::eom;
207213
// now show in the order we have determined
208214
irep_idt previous_function;
209215
irep_idt current_file;
@@ -253,7 +259,8 @@ void output_properties(
253259
{
254260
case ui_message_handlert::uit::PLAIN:
255261
{
256-
output_properties_plain(properties, log);
262+
const auto sorted_properties = get_sorted_properties(properties);
263+
output_properties_plain(sorted_properties, log);
257264
output_iterations(properties, iterations, log);
258265
break;
259266
}
@@ -292,18 +299,19 @@ void output_properties_with_traces(
292299
{
293300
case ui_message_handlert::uit::PLAIN:
294301
{
295-
output_properties_plain(properties, log);
296-
for(const auto &property_pair : properties)
302+
const auto sorted_properties = get_sorted_properties(properties);
303+
output_properties_plain(sorted_properties, log);
304+
for(const auto &property_it : sorted_properties)
297305
{
298-
if(property_pair.second.status == property_statust::FAIL)
306+
if(property_it->second.status == property_statust::FAIL)
299307
{
300308
log.result() << "\n"
301-
<< "Trace for " << property_pair.first << ":"
309+
<< "Trace for " << property_it->first << ":"
302310
<< "\n";
303311
show_goto_trace(
304312
log.result(),
305313
traces.get_namespace(),
306-
traces[property_pair.first],
314+
traces[property_it->first],
307315
trace_options);
308316
log.result() << messaget::eom;
309317
}

src/goto-checker/single_path_symex_checker.cpp

Lines changed: 32 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -110,21 +110,49 @@ operator()(propertiest &properties)
110110
return result;
111111
}
112112

113-
goto_tracet single_path_symex_checkert::build_trace() const
113+
goto_tracet single_path_symex_checkert::build_full_trace() const
114+
{
115+
goto_tracet goto_trace;
116+
build_goto_trace(
117+
property_decider->get_equation(),
118+
property_decider->get_equation().SSA_steps.end(),
119+
property_decider->get_solver(),
120+
ns,
121+
goto_trace);
122+
123+
return goto_trace;
124+
}
125+
126+
goto_tracet single_path_symex_checkert::build_shortest_trace() const
114127
{
115128
if(options.get_bool_option("beautify"))
116129
{
117130
counterexample_beautificationt()(
118131
dynamic_cast<boolbvt &>(property_decider->get_solver()),
119132
property_decider->get_equation());
120133
}
134+
121135
goto_tracet goto_trace;
122-
::build_error_trace(
123-
goto_trace,
136+
build_goto_trace(
137+
property_decider->get_equation(),
138+
property_decider->get_solver(),
124139
ns,
140+
goto_trace);
141+
142+
return goto_trace;
143+
}
144+
145+
goto_tracet
146+
single_path_symex_checkert::build_trace(const irep_idt &property_id) const
147+
{
148+
goto_tracet goto_trace;
149+
build_goto_trace(
125150
property_decider->get_equation(),
151+
ssa_step_matches_failing_property(property_id),
126152
property_decider->get_solver(),
127-
ui_message_handler);
153+
ns,
154+
goto_trace);
155+
128156
return goto_trace;
129157
}
130158

src/goto-checker/single_path_symex_checker.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,9 @@ class single_path_symex_checkert : public single_path_symex_only_checkert,
3434

3535
resultt operator()(propertiest &) override;
3636

37-
goto_tracet build_trace() const override;
37+
goto_tracet build_full_trace() const override;
38+
goto_tracet build_shortest_trace() const override;
39+
goto_tracet build_trace(const irep_idt &) const override;
3840
const namespacet &get_namespace() const override;
3941

4042
void output_error_witness(const goto_tracet &) override;

src/goto-checker/stop_on_fail_verifier.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,8 @@ class stop_on_fail_verifiert : public goto_verifiert
5050

5151
case resultt::FAIL:
5252
{
53-
goto_tracet goto_trace = incremental_goto_checker.build_trace();
53+
message_building_error_trace(log);
54+
goto_tracet goto_trace = incremental_goto_checker.build_shortest_trace();
5455
output_error_trace(
5556
goto_trace,
5657
incremental_goto_checker.get_namespace(),

0 commit comments

Comments
 (0)