Skip to content

Commit 3bdc70f

Browse files
committed
Change is_constantt logic to enumerate not-constant expressions
Rather than adding more-and-more expressions to the enumeration just call out those that are _not_ constant ((nondet) symbols and side-effect expressions as well as any access that may be out of bounds). With the additional const-ness we need to make Array_UF22 a bit more complicated (less constant) to continue to demonstrate the problem.
1 parent ef76a0f commit 3bdc70f

File tree

3 files changed

+33
-23
lines changed

3 files changed

+33
-23
lines changed

regression/cbmc/Array_UF22/main.c

+3-2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
int main()
22
{
3-
int a[2] = {0};
4-
int b[2] = {0};
3+
int x;
4+
int a[2] = {x};
5+
int b[2] = {x};
56
__CPROVER_assert(__CPROVER_array_equal(a, b), "equal");
67
}

src/util/expr_util.cpp

+29-20
Original file line numberDiff line numberDiff line change
@@ -228,29 +228,32 @@ const exprt &skip_typecast(const exprt &expr)
228228
/// "constants"
229229
bool is_constantt::is_constant(const exprt &expr) const
230230
{
231-
if(expr.is_constant())
232-
return true;
231+
if(
232+
expr.id() == ID_symbol || expr.id() == ID_nondet_symbol ||
233+
expr.id() == ID_side_effect)
234+
{
235+
return false;
236+
}
233237

234238
if(expr.id() == ID_address_of)
235239
{
236240
return is_constant_address_of(to_address_of_expr(expr).object());
237241
}
238-
else if(
239-
expr.id() == ID_typecast || expr.id() == ID_array_of ||
240-
expr.id() == ID_plus || expr.id() == ID_mult || expr.id() == ID_array ||
241-
expr.id() == ID_with || expr.id() == ID_struct || expr.id() == ID_union ||
242-
expr.id() == ID_empty_union || expr.id() == ID_equal ||
243-
expr.id() == ID_notequal || expr.id() == ID_lt || expr.id() == ID_le ||
244-
expr.id() == ID_gt || expr.id() == ID_ge || expr.id() == ID_if ||
245-
expr.id() == ID_not || expr.id() == ID_and || expr.id() == ID_or ||
246-
expr.id() == ID_bitnot || expr.id() == ID_bitand || expr.id() == ID_bitor ||
247-
expr.id() == ID_bitxor || expr.id() == ID_byte_update_big_endian ||
248-
expr.id() == ID_byte_update_little_endian)
242+
else if(auto index = expr_try_dynamic_cast<index_exprt>(expr))
249243
{
250-
return std::all_of(
251-
expr.operands().begin(), expr.operands().end(), [this](const exprt &e) {
252-
return is_constant(e);
253-
});
244+
if(!is_constant(index->array()) || !index->index().is_constant())
245+
return false;
246+
247+
const auto &array_type = to_array_type(index->array().type());
248+
if(!array_type.size().is_constant())
249+
return false;
250+
251+
const mp_integer size =
252+
numeric_cast_v<mp_integer>(to_constant_expr(array_type.size()));
253+
const mp_integer index_int =
254+
numeric_cast_v<mp_integer>(to_constant_expr(index->index()));
255+
256+
return index_int >= 0 && index_int < size;
254257
}
255258
else if(auto be = expr_try_dynamic_cast<byte_extract_exprt>(expr))
256259
{
@@ -269,7 +272,7 @@ bool is_constantt::is_constant(const exprt &expr) const
269272
numeric_cast_v<mp_integer>(to_constant_expr(be->offset())) *
270273
be->get_bits_per_byte();
271274

272-
return offset_bits + *extract_bits <= *op_bits;
275+
return offset_bits >= 0 && offset_bits + *extract_bits <= *op_bits;
273276
}
274277
else if(auto eb = expr_try_dynamic_cast<extractbits_exprt>(expr))
275278
{
@@ -292,8 +295,14 @@ bool is_constantt::is_constant(const exprt &expr) const
292295
return lower_bound >= 0 && lower_bound <= upper_bound &&
293296
upper_bound < src_bits;
294297
}
295-
296-
return false;
298+
else
299+
{
300+
// std::all_of returns true when there are no operands
301+
return std::all_of(
302+
expr.operands().begin(), expr.operands().end(), [this](const exprt &e) {
303+
return is_constant(e);
304+
});
305+
}
297306
}
298307

299308
/// this function determines which reference-typed expressions are constant

src/util/expr_util.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,7 @@ const exprt &skip_typecast(const exprt &expr);
8282

8383
/// Determine whether an expression is constant. A literal constant is
8484
/// constant, but so are, e.g., sums over constants or addresses of objects.
85-
/// An implementation derive from this class to refine what it considers
85+
/// An implementation may derive from this class to refine what it considers
8686
/// constant in a particular context by overriding is_constant and/or
8787
/// is_constant_address_of.
8888
class is_constantt

0 commit comments

Comments
 (0)