Skip to content

Commit 403a129

Browse files
authored
Merge pull request #6210 from TGWDB/SMT-z3-trace-fix
SMT Z3 trace fix
2 parents 54c385e + d125b1a commit 403a129

File tree

9 files changed

+132
-17
lines changed

9 files changed

+132
-17
lines changed

regression/cbmc/enum-trace1/test_json.desc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
CORE broken-smt-backend
1+
CORE
22
main.c
33
--json-ui --function test --trace
44
activate-multi-line-match

regression/cbmc/json-interface1/test.desc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
CORE broken-smt-backend
1+
CORE
22
--json-interface
33
< test.json
44
activate-multi-line-match

regression/cbmc/json1/test.desc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
CORE broken-smt-backend
1+
CORE
22
main.c
33
--json-ui --stop-on-fail
44
activate-multi-line-match

regression/cbmc/z3/trace-char.c

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
void main(int argc, char **argv)
2+
{
3+
char arr[] = {'0', '1', '2', '3', '4', '5', '6', '7'};
4+
assert(arr[0] == '2');
5+
}

regression/cbmc/z3/trace-char.desc

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
CORE smt-backend broken-cprover-smt-backend
2+
trace-char.c
3+
--trace --smt2 --z3
4+
^EXIT=10$
5+
^SIGNAL=0$
6+
arr=\{ arr
7+
arr=\{ '0', '1', '2', '3', '4', '5', '6', '7' \}
8+
--
9+
arr=(assignment removed)
10+
error running SMT2 solver
11+
--
12+
Run cbmc with the --z3 and --trace options with arrays to confirm that
13+
char arrays are displayed in traces.

regression/cbmc/z3/trace.c

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
void main(int argc, char **argv)
2+
{
3+
int arr[] = {0, 1, 2, 3, 4, 5, 6, 17};
4+
assert(arr[0] == 2);
5+
}

regression/cbmc/z3/trace.desc

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
CORE smt-backend broken-cprover-smt-backend
2+
trace.c
3+
--trace --smt2 --z3
4+
^EXIT=10$
5+
^SIGNAL=0$
6+
arr=\{ arr
7+
arr=\{ 0, 1, 2, 3, 4, 5, 6, 17 \}
8+
--
9+
arr=(assignment removed)
10+
error running SMT2 solver
11+
--
12+
Run cbmc with the --z3 and --trace options with arrays to confirm that
13+
int arrays are displayed in traces.

src/solvers/smt2/smt2_conv.cpp

Lines changed: 78 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -283,6 +283,7 @@ exprt smt2_convt::get(const exprt &expr) const
283283

284284
if(it!=identifier_map.end())
285285
return it->second.value;
286+
return expr;
286287
}
287288
else if(expr.id()==ID_nondet_symbol)
288289
{
@@ -319,6 +320,15 @@ exprt smt2_convt::get(const exprt &expr) const
319320
}
320321
else if(expr.is_constant())
321322
return expr;
323+
else if(const auto &array = expr_try_dynamic_cast<array_exprt>(expr))
324+
{
325+
exprt array_copy = *array;
326+
for(auto &element : array_copy.operands())
327+
{
328+
element = get(element);
329+
}
330+
return array_copy;
331+
}
322332

323333
return nil_exprt();
324334
}
@@ -464,31 +474,85 @@ constant_exprt smt2_convt::parse_literal(
464474
exprt smt2_convt::parse_array(
465475
const irept &src,
466476
const array_typet &type)
477+
{
478+
std::unordered_map<int64_t, exprt> operands_map;
479+
walk_array_tree(&operands_map, src, type);
480+
exprt::operandst operands;
481+
// Try to find the default value, if there is none then set it
482+
auto maybe_default_op = operands_map.find(-1);
483+
exprt default_op;
484+
if(maybe_default_op == operands_map.end())
485+
default_op = nil_exprt();
486+
else
487+
default_op = maybe_default_op->second;
488+
int64_t i = 0;
489+
auto maybe_size = numeric_cast<std::int64_t>(type.size());
490+
if(maybe_size.has_value())
491+
{
492+
while(i < maybe_size.value())
493+
{
494+
auto found_op = operands_map.find(i);
495+
if(found_op != operands_map.end())
496+
operands.emplace_back(found_op->second);
497+
else
498+
operands.emplace_back(default_op);
499+
i++;
500+
}
501+
}
502+
else
503+
{
504+
// Array size is unknown, keep adding with known indexes in order
505+
// until we fail to find one.
506+
auto found_op = operands_map.find(i);
507+
while(found_op != operands_map.end())
508+
{
509+
operands.emplace_back(found_op->second);
510+
i++;
511+
found_op = operands_map.find(i);
512+
}
513+
operands.emplace_back(default_op);
514+
}
515+
return array_exprt(operands, type);
516+
}
517+
518+
void smt2_convt::walk_array_tree(
519+
std::unordered_map<int64_t, exprt> *operands_map,
520+
const irept &src,
521+
const array_typet &type)
467522
{
468523
if(src.get_sub().size()==4 && src.get_sub()[0].id()=="store")
469524
{
525+
// This is the SMT syntax being parsed here
470526
// (store array index value)
471-
if(src.get_sub().size()!=4)
472-
return nil_exprt();
473-
474-
exprt array=parse_array(src.get_sub()[1], type);
475-
exprt index=parse_rec(src.get_sub()[2], type.size().type());
476-
exprt value=parse_rec(src.get_sub()[3], type.subtype());
477-
478-
return with_exprt(array, index, value);
527+
// Recurse
528+
walk_array_tree(operands_map, src.get_sub()[1], type);
529+
const auto index_expr = parse_rec(src.get_sub()[2], type.size().type());
530+
const constant_exprt index_constant = to_constant_expr(index_expr);
531+
mp_integer tempint;
532+
bool failure = to_integer(index_constant, tempint);
533+
if(failure)
534+
return;
535+
long index = tempint.to_long();
536+
exprt value = parse_rec(src.get_sub()[3], type.subtype());
537+
operands_map->emplace(index, value);
538+
}
539+
else if(src.get_sub().size() == 3 && src.get_sub()[0].id() == "let")
540+
{
541+
// This is produced by Z3
542+
// (let (....) (....))
543+
walk_array_tree(
544+
operands_map, src.get_sub()[1].get_sub()[0].get_sub()[1], type);
545+
walk_array_tree(operands_map, src.get_sub()[2], type);
479546
}
480547
else if(src.get_sub().size()==2 &&
481548
src.get_sub()[0].get_sub().size()==3 &&
482549
src.get_sub()[0].get_sub()[0].id()=="as" &&
483550
src.get_sub()[0].get_sub()[1].id()=="const")
484551
{
485-
// This is produced by Z3.
486-
// ((as const (Array (_ BitVec 64) (_ BitVec 8))) #x00)))
487-
exprt value=parse_rec(src.get_sub()[1], type.subtype());
488-
return array_of_exprt(value, type);
552+
// (as const type_info default_value)
553+
exprt default_value = parse_rec(src.get_sub()[1], type.subtype());
554+
operands_map->emplace(-1, default_value);
489555
}
490-
else
491-
return nil_exprt();
492556
}
493557

494558
exprt smt2_convt::parse_union(

src/solvers/smt2/smt2_conv.h

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -159,8 +159,23 @@ class smt2_convt : public stack_decision_proceduret
159159
constant_exprt parse_literal(const irept &, const typet &type);
160160
struct_exprt parse_struct(const irept &s, const struct_typet &type);
161161
exprt parse_union(const irept &s, const union_typet &type);
162+
/// This function is for parsing array output from SMT solvers
163+
/// when "(get-value |???|)" returns an array object.
164+
/// \param s: is the irept parsed from the SMT output
165+
/// \param type: is the expected type
166+
/// \returns an exprt that represents the array
162167
exprt parse_array(const irept &s, const array_typet &type);
163168
exprt parse_rec(const irept &s, const typet &type);
169+
/// This function walks the SMT output and populates a
170+
/// map with index/value pairs for the array
171+
/// \param operands_map: is a map of the operands to the array
172+
/// being constructed indexed by their index.
173+
/// \param src: is the irept source for the SMT output
174+
/// \param type: is the type of the array
175+
void walk_array_tree(
176+
std::unordered_map<int64_t, exprt> *operands_map,
177+
const irept &src,
178+
const array_typet &type);
164179

165180
// we use this to build a bit-vector encoding of the FPA theory
166181
void convert_floatbv(const exprt &expr);

0 commit comments

Comments
 (0)