Skip to content

Commit 8ae1794

Browse files
committed
Restore member-of-union expressions in trace output
byte_extract operations precisely capture the semantics, but aren't meaningful to users.
1 parent 2858b18 commit 8ae1794

File tree

10 files changed

+89
-42
lines changed

10 files changed

+89
-42
lines changed

regression/cbmc/xml-trace/test.desc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ VERIFICATION FAILED
77
<assignment assignment_type="state" base_name="u" display_name="test::u" hidden="false" identifier="test::u" mode="C" step_nr="\d+" thread="0">
88
<location file=".*" function="test" line="\d+" working-directory=".*"/>
99
<type>union myunion</type>
10-
<full_lhs>byte_extract_little_endian\(u, 0ll?, .*int.*\)</full_lhs>
10+
<full_lhs>u</full_lhs>
1111
<full_lhs_value binary="[01]+">\d+ll?</full_lhs_value>
1212
<value>\{ \.i=\d+ll? \}</value>
1313
<value_expression>

src/goto-programs/goto_trace.cpp

Lines changed: 28 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -19,36 +19,25 @@ Author: Daniel Kroening
1919
#include <util/byte_operators.h>
2020
#include <util/format_expr.h>
2121
#include <util/range.h>
22+
#include <util/std_expr.h>
2223
#include <util/string_utils.h>
2324
#include <util/symbol.h>
2425

2526
#include <langapi/language_util.h>
2627

2728
#include "printf_formatter.h"
29+
#include "rewrite_union.h"
2830

29-
static optionalt<symbol_exprt> get_object_rec(const exprt &src)
31+
optionalt<symbol_exprt>
32+
goto_trace_stept::get_lhs_object(const namespacet &ns) const
3033
{
31-
if(src.id()==ID_symbol)
32-
return to_symbol_expr(src);
33-
else if(src.id()==ID_member)
34-
return get_object_rec(to_member_expr(src).struct_op());
35-
else if(src.id()==ID_index)
36-
return get_object_rec(to_index_expr(src).array());
37-
else if(src.id()==ID_typecast)
38-
return get_object_rec(to_typecast_expr(src).op());
39-
else if(
40-
src.id() == ID_byte_extract_little_endian ||
41-
src.id() == ID_byte_extract_big_endian)
42-
{
43-
return get_object_rec(to_byte_extract_expr(src).op());
44-
}
45-
else
46-
return {}; // give up
47-
}
34+
object_descriptor_exprt ode;
35+
ode.build(full_lhs, ns);
4836

49-
optionalt<symbol_exprt> goto_trace_stept::get_lhs_object() const
50-
{
51-
return get_object_rec(full_lhs);
37+
if(ode.root_object().id() == ID_symbol)
38+
return to_symbol_expr(ode.root_object());
39+
else
40+
return {};
5241
}
5342

5443
void goto_tracet::output(
@@ -59,9 +48,7 @@ void goto_tracet::output(
5948
step.output(ns, out);
6049
}
6150

62-
void goto_trace_stept::output(
63-
const namespacet &,
64-
std::ostream &out) const
51+
void goto_trace_stept::output(const namespacet &ns, std::ostream &out) const
6552
{
6653
out << "*** ";
6754

@@ -126,7 +113,9 @@ void goto_trace_stept::output(
126113
if(!comment.empty())
127114
out << " " << comment << '\n';
128115

129-
out << " " << format(pc->get_condition()) << '\n';
116+
exprt condition{pc->get_condition()};
117+
restore_union(condition, ns);
118+
out << " " << format(condition) << '\n';
130119
out << '\n';
131120
}
132121
}
@@ -397,9 +386,9 @@ void show_compact_goto_trace(
397386

398387
if(step.pc->is_assert())
399388
{
400-
out << " "
401-
<< from_expr(ns, step.function_id, step.pc->get_condition())
402-
<< '\n';
389+
exprt condition{step.pc->get_condition()};
390+
restore_union(condition, ns);
391+
out << " " << from_expr(ns, step.function_id, condition) << '\n';
403392
}
404393

405394
out << '\n';
@@ -425,7 +414,7 @@ void show_compact_goto_trace(
425414
trace_value(
426415
out,
427416
ns,
428-
step.get_lhs_object(),
417+
step.get_lhs_object(ns),
429418
step.full_lhs,
430419
step.full_lhs_value,
431420
options);
@@ -524,9 +513,9 @@ void show_full_goto_trace(
524513

525514
if(step.pc->is_assert())
526515
{
527-
out << " "
528-
<< from_expr(ns, step.function_id, step.pc->get_condition())
529-
<< '\n';
516+
exprt condition{step.pc->get_condition()};
517+
restore_union(condition, ns);
518+
out << " " << from_expr(ns, step.function_id, condition) << '\n';
530519
}
531520

532521
out << '\n';
@@ -570,7 +559,7 @@ void show_full_goto_trace(
570559
trace_value(
571560
out,
572561
ns,
573-
step.get_lhs_object(),
562+
step.get_lhs_object(ns),
574563
step.full_lhs,
575564
step.full_lhs_value,
576565
options);
@@ -587,7 +576,12 @@ void show_full_goto_trace(
587576

588577
out << " ";
589578
trace_value(
590-
out, ns, step.get_lhs_object(), step.full_lhs, step.full_lhs_value, options);
579+
out,
580+
ns,
581+
step.get_lhs_object(ns),
582+
step.full_lhs,
583+
step.full_lhs_value,
584+
options);
591585
break;
592586

593587
case goto_trace_stept::typet::OUTPUT:

src/goto-programs/goto_trace.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -126,7 +126,7 @@ class goto_trace_stept
126126
exprt full_lhs;
127127

128128
// the object being assigned
129-
optionalt<symbol_exprt> get_lhs_object() const;
129+
optionalt<symbol_exprt> get_lhs_object(const namespacet &ns) const;
130130

131131
// A constant with the new value of the lhs
132132
exprt full_lhs_value;

src/goto-programs/graphml_witness.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -434,7 +434,7 @@ void graphml_witnesst::operator()(const goto_tracet &goto_trace)
434434
data_t.data = std::to_string(it->thread_nr);
435435
}
436436

437-
const auto lhs_object = it->get_lhs_object();
437+
const auto lhs_object = it->get_lhs_object(ns);
438438
if(
439439
it->type == goto_trace_stept::typet::ASSIGNMENT &&
440440
lhs_object.has_value())

src/goto-programs/json_goto_trace.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ void convert_decl(
6565
const jsont &json_location = conversion_dependencies.location;
6666
const namespacet &ns = conversion_dependencies.ns;
6767

68-
auto lhs_object=step.get_lhs_object();
68+
auto lhs_object = step.get_lhs_object(ns);
6969

7070
irep_idt identifier =
7171
lhs_object.has_value()?lhs_object->get_identifier():irep_idt();

src/goto-programs/rewrite_union.cpp

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -124,3 +124,51 @@ void rewrite_union(goto_modelt &goto_model)
124124
{
125125
rewrite_union(goto_model.goto_functions);
126126
}
127+
128+
/// Undo the union access -> byte_extract replacement that rewrite_union did for
129+
/// the purpose of displaying expressions to users.
130+
/// \param expr: expression to inspect and possibly transform
131+
/// \param ns: namespace
132+
/// \return True if, and only if, the expression is unmodified
133+
static bool restore_union_rec(exprt &expr, const namespacet &ns)
134+
{
135+
bool unmodified = true;
136+
137+
Forall_operands(it, expr)
138+
unmodified &= restore_union_rec(*it, ns);
139+
140+
if(expr.id() == byte_extract_id())
141+
{
142+
byte_extract_exprt &be = to_byte_extract_expr(expr);
143+
if(
144+
(be.op().type().id() == ID_union ||
145+
be.op().type().id() == ID_union_tag) &&
146+
be.offset().is_zero())
147+
{
148+
const union_typet &union_type = to_union_type(ns.follow(be.op().type()));
149+
150+
for(const auto &comp : union_type.components())
151+
{
152+
if(be.type() == comp.type())
153+
{
154+
expr = member_exprt{be.op(), comp.get_name(), be.type()};
155+
return false;
156+
}
157+
}
158+
}
159+
}
160+
161+
return unmodified;
162+
}
163+
164+
/// Undo the union access -> byte_extract replacement that rewrite_union did for
165+
/// the purpose of displaying expressions to users.
166+
/// \param expr: expression to inspect and possibly transform
167+
/// \param ns: namespace
168+
void restore_union(exprt &expr, const namespacet &ns)
169+
{
170+
exprt tmp = expr;
171+
172+
if(!restore_union_rec(tmp, ns))
173+
expr.swap(tmp);
174+
}

src/goto-programs/rewrite_union.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,4 +24,6 @@ void rewrite_union(goto_functionst::goto_functiont &);
2424
void rewrite_union(goto_functionst &);
2525
void rewrite_union(goto_modelt &);
2626

27+
void restore_union(exprt &, const namespacet &);
28+
2729
#endif // CPROVER_GOTO_PROGRAMS_REWRITE_UNION_H

src/goto-programs/vcd_goto_trace.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,7 @@ void output_vcd(
8888
{
8989
if(step.is_assignment())
9090
{
91-
auto lhs_object=step.get_lhs_object();
91+
auto lhs_object = step.get_lhs_object(ns);
9292
if(lhs_object.has_value())
9393
{
9494
irep_idt identifier=lhs_object->get_identifier();
@@ -115,7 +115,7 @@ void output_vcd(
115115
{
116116
if(step.is_assignment())
117117
{
118-
auto lhs_object = step.get_lhs_object();
118+
auto lhs_object = step.get_lhs_object(ns);
119119
if(lhs_object.has_value())
120120
{
121121
irep_idt identifier = lhs_object->get_identifier();

src/goto-programs/xml_goto_trace.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ xmlt full_lhs_value(const goto_trace_stept &step, const namespacet &ns)
3131
if(value.is_nil())
3232
return value_xml;
3333

34-
const auto &lhs_object = step.get_lhs_object();
34+
const auto &lhs_object = step.get_lhs_object(ns);
3535
const irep_idt identifier =
3636
lhs_object.has_value() ? lhs_object->get_identifier() : irep_idt();
3737
value_xml.data = from_expr(ns, identifier, value);
@@ -91,7 +91,7 @@ void convert(
9191
case goto_trace_stept::typet::ASSIGNMENT:
9292
case goto_trace_stept::typet::DECL:
9393
{
94-
auto lhs_object = step.get_lhs_object();
94+
auto lhs_object = step.get_lhs_object(ns);
9595
irep_idt identifier =
9696
lhs_object.has_value() ? lhs_object->get_identifier() : irep_idt();
9797
xmlt &xml_assignment = dest.new_element("assignment");

src/goto-symex/build_goto_trace.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@ Author: Daniel Kroening
2222

2323
#include <solvers/decision_procedure.h>
2424

25+
#include <goto-programs/rewrite_union.h>
26+
2527
#include "partial_order_concurrency.h"
2628

2729
static exprt build_full_lhs_rec(
@@ -378,6 +380,7 @@ void build_goto_trace(
378380
SSA_step.ssa_full_lhs),
379381
ns);
380382
replace_nondet_in_type(goto_trace_step.full_lhs, decision_procedure);
383+
restore_union(goto_trace_step.full_lhs, ns);
381384
}
382385

383386
if(SSA_step.ssa_full_lhs.is_not_nil())

0 commit comments

Comments
 (0)