Skip to content

Commit da9922e

Browse files
committed
Fixes array value in traces for Z3 SMT
This is a fix for how we parse Z3 array output to reconstruct values in traces. This is specific bug fix for Z3 array output.
1 parent 2f9da2b commit da9922e

File tree

2 files changed

+53
-18
lines changed

2 files changed

+53
-18
lines changed

src/solvers/smt2/smt2_conv.cpp

Lines changed: 38 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -282,6 +282,7 @@ exprt smt2_convt::get(const exprt &expr) const
282282

283283
if(it!=identifier_map.end())
284284
return it->second.value;
285+
return expr;
285286
}
286287
else if(expr.id()==ID_nondet_symbol)
287288
{
@@ -472,31 +473,50 @@ constant_exprt smt2_convt::parse_literal(
472473
exprt smt2_convt::parse_array(
473474
const irept &src,
474475
const array_typet &type)
476+
{
477+
std::unordered_map<size_t, exprt> operands_map;
478+
walk_array_tree(&operands_map, src, type);
479+
exprt::operandst operands;
480+
size_t i = 0;
481+
auto found_op = operands_map.find(i);
482+
while(found_op != operands_map.end())
483+
{
484+
operands.emplace_back(found_op->second);
485+
i++;
486+
found_op = operands_map.find(i);
487+
}
488+
return array_exprt(operands, type);
489+
}
490+
491+
void smt2_convt::walk_array_tree(
492+
std::unordered_map<size_t, exprt> *operands_map,
493+
const irept &src,
494+
const array_typet &type)
475495
{
476496
if(src.get_sub().size()==4 && src.get_sub()[0].id()=="store")
477497
{
498+
// This is the SMT syntax being parsed here
478499
// (store array index value)
479-
if(src.get_sub().size()!=4)
480-
return nil_exprt();
481-
482-
exprt array=parse_array(src.get_sub()[1], type);
483-
exprt index=parse_rec(src.get_sub()[2], type.size().type());
484-
exprt value=parse_rec(src.get_sub()[3], type.subtype());
485-
486-
return with_exprt(array, index, value);
500+
// Recurse
501+
walk_array_tree(operands_map, src.get_sub()[1], type);
502+
const auto index_expr = parse_rec(src.get_sub()[2], type.size().type());
503+
const constant_exprt index_constant = to_constant_expr(index_expr);
504+
mp_integer tempint;
505+
bool failure = to_integer(index_constant, tempint);
506+
if(failure)
507+
return;
508+
size_t index = tempint.to_ulong();
509+
exprt value = parse_rec(src.get_sub()[3], type.subtype());
510+
operands_map->emplace(index, value);
487511
}
488-
else if(src.get_sub().size()==2 &&
489-
src.get_sub()[0].get_sub().size()==3 &&
490-
src.get_sub()[0].get_sub()[0].id()=="as" &&
491-
src.get_sub()[0].get_sub()[1].id()=="const")
512+
else if(src.get_sub().size() == 3 && src.get_sub()[0].id() == "let")
492513
{
493-
// This is produced by Z3.
494-
// ((as const (Array (_ BitVec 64) (_ BitVec 8))) #x00)))
495-
exprt value=parse_rec(src.get_sub()[1], type.subtype());
496-
return array_of_exprt(value, type);
514+
// This is produced by Z3
515+
// (let (....) (....))
516+
walk_array_tree(
517+
operands_map, src.get_sub()[1].get_sub()[0].get_sub()[1], type);
518+
walk_array_tree(operands_map, src.get_sub()[2], type);
497519
}
498-
else
499-
return nil_exprt();
500520
}
501521

502522
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<size_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)