Skip to content

Commit c3ebf1e

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 247380f commit c3ebf1e

File tree

6 files changed

+82
-5
lines changed

6 files changed

+82
-5
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: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -128,7 +128,7 @@ void goto_trace_stept::output(
128128
if(!comment.empty())
129129
out << " " << comment << '\n';
130130

131-
out << " " << format(pc->get_condition()) << '\n';
131+
out << " " << format(original_condition) << '\n';
132132
out << '\n';
133133
}
134134
}
@@ -414,7 +414,7 @@ void show_compact_goto_trace(
414414
if(step.pc->is_assert())
415415
{
416416
out << " "
417-
<< from_expr(ns, step.function_id, step.pc->get_condition())
417+
<< from_expr(ns, step.function_id, step.original_condition)
418418
<< '\n';
419419
}
420420

@@ -541,7 +541,7 @@ void show_full_goto_trace(
541541
if(step.pc->is_assert())
542542
{
543543
out << " "
544-
<< from_expr(ns, step.function_id, step.pc->get_condition())
544+
<< from_expr(ns, step.function_id, step.original_condition)
545545
<< '\n';
546546
}
547547

@@ -558,7 +558,7 @@ void show_full_goto_trace(
558558
if(!step.pc->source_location.is_nil())
559559
out << " " << step.pc->source_location << '\n';
560560

561-
out << " " << from_expr(ns, step.function_id, step.pc->get_condition())
561+
out << " " << from_expr(ns, step.function_id, step.original_condition)
562562
<< '\n';
563563
}
564564
break;

src/goto-programs/goto_trace.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,7 @@ class goto_trace_stept
117117
// for assume, assert, goto
118118
bool cond_value;
119119
exprt cond_expr;
120+
exprt original_condition;
120121

121122
// for assert
122123
irep_idt property_id;
@@ -161,6 +162,7 @@ class goto_trace_stept
161162
full_lhs.make_nil();
162163
full_lhs_value.make_nil();
163164
cond_expr.make_nil();
165+
original_condition.make_nil();
164166
}
165167

166168
/// Use \p dest to establish sharing among ireps.

src/goto-programs/rewrite_union.cpp

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ Author: Daniel Kroening, [email protected]
1515
#include <util/byte_operators.h>
1616
#include <util/c_types.h>
1717
#include <util/pointer_expr.h>
18+
#include <util/pointer_offset_size.h>
1819
#include <util/std_code.h>
1920

2021
#include <goto-programs/goto_model.h>
@@ -120,3 +121,65 @@ void rewrite_union(goto_modelt &goto_model)
120121
{
121122
rewrite_union(goto_model.goto_functions);
122123
}
124+
125+
/// Undo the union access -> byte_extract replacement that rewrite_union did for
126+
/// the purpose of displaying expressions to users.
127+
/// \param expr: expression to inspect and possibly transform
128+
/// \param ns: namespace
129+
/// \return True if, and only if, the expression is unmodified
130+
static bool restore_union_rec(exprt &expr, const namespacet &ns)
131+
{
132+
bool unmodified = true;
133+
134+
Forall_operands(it, expr)
135+
unmodified &= restore_union_rec(*it, ns);
136+
137+
if(
138+
expr.id() == ID_byte_extract_little_endian ||
139+
expr.id() == ID_byte_extract_big_endian)
140+
{
141+
byte_extract_exprt &be = to_byte_extract_expr(expr);
142+
if(be.op().type().id() == ID_union || be.op().type().id() == ID_union_tag)
143+
{
144+
const union_typet &union_type = to_union_type(ns.follow(be.op().type()));
145+
146+
for(const auto &comp : union_type.components())
147+
{
148+
if(be.offset().is_zero() && be.type() == comp.type())
149+
{
150+
expr = member_exprt{be.op(), comp.get_name(), be.type()};
151+
return false;
152+
}
153+
else if(
154+
comp.type().id() == ID_array || comp.type().id() == ID_struct ||
155+
comp.type().id() == ID_struct_tag)
156+
{
157+
optionalt<exprt> result = get_subexpression_at_offset(
158+
member_exprt{be.op(), comp.get_name(), comp.type()},
159+
be.offset(),
160+
be.type(),
161+
ns);
162+
if(result.has_value())
163+
{
164+
expr = *result;
165+
return false;
166+
}
167+
}
168+
}
169+
}
170+
}
171+
172+
return unmodified;
173+
}
174+
175+
/// Undo the union access -> byte_extract replacement that rewrite_union did for
176+
/// the purpose of displaying expressions to users.
177+
/// \param expr: expression to inspect and possibly transform
178+
/// \param ns: namespace
179+
void restore_union(exprt &expr, const namespacet &ns)
180+
{
181+
exprt tmp = expr;
182+
183+
if(!restore_union_rec(tmp, ns))
184+
expr.swap(tmp);
185+
}

src/goto-programs/rewrite_union.h

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

25+
void restore_union(exprt &, const namespacet &);
26+
2527
#endif // CPROVER_GOTO_PROGRAMS_REWRITE_UNION_H

src/goto-symex/build_goto_trace.cpp

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@ Author: Daniel Kroening
2121

2222
#include <solvers/decision_procedure.h>
2323

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

2628
static exprt build_full_lhs_rec(
@@ -377,6 +379,7 @@ void build_goto_trace(
377379
SSA_step.ssa_full_lhs),
378380
ns);
379381
replace_nondet_in_type(goto_trace_step.full_lhs, decision_procedure);
382+
restore_union(goto_trace_step.full_lhs, ns);
380383
}
381384

382385
if(SSA_step.ssa_full_lhs.is_not_nil())
@@ -409,6 +412,13 @@ void build_goto_trace(
409412
decision_procedure.get(SSA_step.cond_handle).is_true();
410413
}
411414

415+
if(SSA_step.source.pc->is_assert() || SSA_step.source.pc->is_assume())
416+
{
417+
goto_trace_step.original_condition =
418+
SSA_step.source.pc->get_condition();
419+
restore_union(goto_trace_step.original_condition, ns);
420+
}
421+
412422
if(ssa_step_it == last_step_to_keep)
413423
return;
414424
}

0 commit comments

Comments
 (0)