diff --git a/jbmc/regression/jbmc/simplify_expr_termination/test.class b/jbmc/regression/jbmc/simplify_expr_termination/test.class new file mode 100644 index 00000000000..e10a48a9a29 Binary files /dev/null and b/jbmc/regression/jbmc/simplify_expr_termination/test.class differ diff --git a/jbmc/regression/jbmc/simplify_expr_termination/test.desc b/jbmc/regression/jbmc/simplify_expr_termination/test.desc new file mode 100644 index 00000000000..877d071af8e --- /dev/null +++ b/jbmc/regression/jbmc/simplify_expr_termination/test.desc @@ -0,0 +1,10 @@ +CORE +test.class +--function test.check +^VERIFICATION FAILED$ +^EXIT=10$ +^SIGNAL=0$ +-- +^warning: ignoring +-- +Checks that a non-termination bug no longer occurs in simplify_byte_extract diff --git a/jbmc/regression/jbmc/simplify_expr_termination/test.java b/jbmc/regression/jbmc/simplify_expr_termination/test.java new file mode 100644 index 00000000000..51999734a5d --- /dev/null +++ b/jbmc/regression/jbmc/simplify_expr_termination/test.java @@ -0,0 +1,11 @@ +public class test { + + public static int check() + { + boolean[] assigned = new boolean[3]; + if (assigned[0] == false) { + assert false; + } + return 1; + } +} diff --git a/src/util/simplify_expr.cpp b/src/util/simplify_expr.cpp index c2e07be9630..4b719aac548 100644 --- a/src/util/simplify_expr.cpp +++ b/src/util/simplify_expr.cpp @@ -1593,7 +1593,7 @@ exprt simplify_exprt::bits2expr( return nil_exprt(); } -std::string simplify_exprt::expr2bits( +optionalt simplify_exprt::expr2bits( const exprt &expr, bool little_endian) { @@ -1630,11 +1630,12 @@ std::string simplify_exprt::expr2bits( std::string result; forall_operands(it, expr) { - std::string tmp=expr2bits(*it, little_endian); - if(tmp.empty()) - return tmp; // failed - result+=tmp; + auto tmp=expr2bits(*it, little_endian); + if(!tmp.has_value()) + return {}; // failed + result+=tmp.value(); } + return result; } else if(expr.id()==ID_array) @@ -1642,15 +1643,16 @@ std::string simplify_exprt::expr2bits( std::string result; forall_operands(it, expr) { - std::string tmp=expr2bits(*it, little_endian); - if(tmp.empty()) - return tmp; // failed - result+=tmp; + auto tmp=expr2bits(*it, little_endian); + if(!tmp.has_value()) + return {}; // failed + result+=tmp.value(); } + return result; } - return ""; + return {}; } bool simplify_exprt::simplify_byte_extract(byte_extract_exprt &expr) @@ -1734,12 +1736,19 @@ bool simplify_exprt::simplify_byte_extract(byte_extract_exprt &expr) return true; if(expr.op().id()==ID_array_of && - expr.op().op0().id()==ID_constant) + to_array_of_expr(expr.op()).op().id()==ID_constant) { - std::string const_bits= - expr2bits(expr.op().op0(), + const auto const_bits_opt= + expr2bits(to_array_of_expr(expr.op()).op(), byte_extract_id()==ID_byte_extract_little_endian); + if(!const_bits_opt.has_value()) + return true; + + std::string const_bits=const_bits_opt.value(); + + DATA_INVARIANT(!const_bits.empty(), "bit representation must be non-empty"); + // double the string until we have sufficiently many bits while(mp_integer(const_bits.size())size())==el_size+offset*8) { std::string bits_cut= std::string( - bits, + bits.value(), integer2size_t(offset*8), integer2size_t(el_size)); diff --git a/src/util/simplify_expr_class.h b/src/util/simplify_expr_class.h index a1760e72a9b..5e192292666 100644 --- a/src/util/simplify_expr_class.h +++ b/src/util/simplify_expr_class.h @@ -151,7 +151,8 @@ class simplify_exprt // bit-level conversions exprt bits2expr( const std::string &bits, const typet &type, bool little_endian); - std::string expr2bits(const exprt &expr, bool little_endian); + + optionalt expr2bits(const exprt &, bool little_endian); protected: const namespacet &ns; diff --git a/src/util/simplify_expr_struct.cpp b/src/util/simplify_expr_struct.cpp index 331d04c3001..ba308ac8ea6 100644 --- a/src/util/simplify_expr_struct.cpp +++ b/src/util/simplify_expr_struct.cpp @@ -190,11 +190,12 @@ bool simplify_exprt::simplify_member(exprt &expr) if(target_size!=-1) { mp_integer target_bits=target_size*8; - std::string bits=expr2bits(op, true); + const auto bits=expr2bits(op, true); - if(mp_integer(bits.size())>=target_bits) + if(bits.has_value() && + mp_integer(bits->size())>=target_bits) { - std::string bits_cut=std::string(bits, 0, integer2size_t(target_bits)); + std::string bits_cut=std::string(*bits, 0, integer2size_t(target_bits)); exprt tmp=bits2expr(bits_cut, expr.type(), true);