Skip to content

Commit 05875e1

Browse files
Merge pull request #922 from romainbrenguier/pull-request/arrays-in-trace
Better output of arrays in json
2 parents a9de859 + f950ffc commit 05875e1

File tree

5 files changed

+135
-4
lines changed

5 files changed

+135
-4
lines changed
Binary file not shown.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
CORE
2+
test.class
3+
--refine-strings --function test.check --json-ui --trace --string-max-length 100 --cover location
4+
^EXIT=0$
5+
^SIGNAL=0$
6+
\"data\".*\"tmp_object_factory\$6.*\"
7+
--
8+
This checks that tmp_object_factory$6 gets affected to the data field
9+
of some strings, which was not the case in previous versions of cbmc,
10+
as it was just ignored by the json output.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
public class test
2+
{
3+
public static int check(String s)
4+
{
5+
int i=Integer.parseInt(s);
6+
return i;
7+
}
8+
}

src/goto-programs/json_goto_trace.cpp

+105-2
Original file line numberDiff line numberDiff line change
@@ -14,11 +14,112 @@ Author: Daniel Kroening
1414
#include <cassert>
1515

1616
#include <util/json_expr.h>
17+
#include <util/arith_tools.h>
1718

1819
#include <langapi/language_util.h>
1920

2021
#include "json_goto_trace.h"
2122

23+
/// Replaces in src, expressions of the form pointer_offset(constant) by that
24+
/// constant.
25+
/// \param src: an expression
26+
void remove_pointer_offsets(exprt &src)
27+
{
28+
if(src.id()==ID_pointer_offset && src.op0().id()==ID_constant)
29+
src=src.op0();
30+
else
31+
for(auto &op : src.operands())
32+
remove_pointer_offsets(op);
33+
}
34+
35+
/// Replaces in src, expressions of the form pointer_offset(array_symbol) by a
36+
/// constant value of 0. This is meant to simplify array expressions.
37+
/// \param src: an expression
38+
/// \param array_symbol: a symbol expression representing an array
39+
void remove_pointer_offsets(exprt &src, const symbol_exprt &array_symbol)
40+
{
41+
if(src.id()==ID_pointer_offset &&
42+
src.op0().id()==ID_constant &&
43+
src.op0().op0().id()==ID_address_of &&
44+
src.op0().op0().op0().id()==ID_index)
45+
{
46+
const index_exprt &idx=to_index_expr(src.op0().op0().op0());
47+
const irep_idt &array_id=to_symbol_expr(idx.array()).get_identifier();
48+
if(idx.array().id()==ID_symbol &&
49+
array_id==array_symbol.get_identifier() &&
50+
to_constant_expr(idx.index()).value_is_zero_string())
51+
src=from_integer(0, src.type());
52+
}
53+
else
54+
for(auto &op : src.operands())
55+
remove_pointer_offsets(op, array_symbol);
56+
}
57+
58+
/// Simplify the expression in index as much as possible to try to get an
59+
/// unsigned constant.
60+
/// \param idx: an expression representing an index in an array
61+
/// \param out: a reference to an unsigned value of type size_t, which will hold
62+
/// the result of the simplification if it is successful
63+
/// \return Boolean flag that is true if the `idx` expression could not be
64+
/// simplified into a unsigned constant value.
65+
bool simplify_index(const exprt &idx, std::size_t &out)
66+
{
67+
if(idx.id()==ID_constant)
68+
{
69+
std::string value_str(id2string(to_constant_expr(idx).get_value()));
70+
mp_integer int_value=binary2integer(value_str, false);
71+
if(int_value>std::numeric_limits<std::size_t>::max())
72+
return true;
73+
out=int_value.to_long();
74+
return false;
75+
}
76+
else if(idx.id()==ID_plus)
77+
{
78+
std::size_t l, r;
79+
if(!simplify_index(idx.op0(), l) && !simplify_index(idx.op1(), r))
80+
{
81+
out=l+r;
82+
return false;
83+
}
84+
}
85+
86+
return true;
87+
}
88+
89+
/// Simplify an expression before putting it in the json format
90+
/// \param src: an expression potentialy containing array accesses (index_expr)
91+
/// \return an expression similar in meaning to src but where array accesses
92+
/// have been simplified
93+
exprt simplify_array_access(const exprt &src)
94+
{
95+
if(src.id()==ID_index && to_index_expr(src).array().id()==ID_symbol)
96+
{
97+
// Case where the array is a symbol.
98+
const symbol_exprt &array_symbol=to_symbol_expr(to_index_expr(src).array());
99+
exprt simplified_index=to_index_expr(src).index();
100+
// We remove potential appearances of `pointer_offset(array_symbol)`
101+
remove_pointer_offsets(simplified_index, array_symbol);
102+
return index_exprt(array_symbol, simplified_index);
103+
}
104+
else if(src.id()==ID_index && to_index_expr(src).array().id()==ID_array)
105+
{
106+
// Case where the array is given by an array of expressions
107+
exprt index=to_index_expr(src).index();
108+
remove_pointer_offsets(index);
109+
110+
// We look for an actual integer value for the index
111+
std::size_t i;
112+
if(!simplify_index(index, i))
113+
return to_index_expr(src).array().operands()[i];
114+
}
115+
return src;
116+
}
117+
118+
/// Produce a json representation of a trace.
119+
/// \param ns: a namespace
120+
/// \param goto_trace: a trace in a goto program
121+
/// \param dest: referecence to a json object in which the goto trace will be
122+
/// added
22123
void convert(
23124
const namespacet &ns,
24125
const goto_tracet &goto_trace,
@@ -84,7 +185,8 @@ void convert(
84185
json_objectt full_lhs_value;
85186

86187
assert(step.full_lhs.is_not_nil());
87-
full_lhs_string=from_expr(ns, identifier, step.full_lhs);
188+
exprt simplified=simplify_array_access(step.full_lhs);
189+
full_lhs_string=from_expr(ns, identifier, simplified);
88190

89191
const symbolt *symbol;
90192
irep_idt base_name, display_name;
@@ -98,7 +200,8 @@ void convert(
98200

99201
json_assignment["mode"]=json_stringt(id2string(symbol->mode));
100202
assert(step.full_lhs_value.is_not_nil());
101-
full_lhs_value=json(step.full_lhs_value, ns, symbol->mode);
203+
exprt simplified=simplify_array_access(step.full_lhs_value);
204+
full_lhs_value=json(simplified, ns, symbol->mode);
102205
}
103206
else
104207
{

src/util/json_expr.cpp

+12-2
Original file line numberDiff line numberDiff line change
@@ -52,16 +52,26 @@ static exprt simplify_json_expr(
5252
id2string(to_member_expr(
5353
src.op0()).get_component_name()).find("@")!=std::string::npos)
5454
{
55-
// simplify things of the form &member_expr(object, @class_identifier)
55+
// simplify expressions of the form &member_expr(object, @class_identifier)
5656
return simplify_json_expr(src.op0(), ns);
5757
}
58+
else if(src.id()==ID_address_of &&
59+
src.operands().size()==1 &&
60+
src.op0().id()==ID_index &&
61+
to_index_expr(src.op0()).index().id()==ID_constant &&
62+
to_constant_expr(
63+
to_index_expr(src.op0()).index()).value_is_zero_string())
64+
{
65+
// simplify expressions of the form &array[0]
66+
return simplify_json_expr(to_index_expr(src.op0()).array(), ns);
67+
}
5868
else if(src.id()==ID_member &&
5969
src.operands().size()==1 &&
6070
id2string(
6171
to_member_expr(src).get_component_name())
6272
.find("@")!=std::string::npos)
6373
{
64-
// simplify things of the form member_expr(object, @class_identifier)
74+
// simplify expressions of the form member_expr(object, @class_identifier)
6575
return simplify_json_expr(src.op0(), ns);
6676
}
6777

0 commit comments

Comments
 (0)