Skip to content

Commit ab0a35c

Browse files
Merge pull request #1220 from romainbrenguier/bugfix/substitute_array_list#275
Making substitute_array_list ignore out of bounds indexes
2 parents 22f3a00 + c38549f commit ab0a35c

File tree

4 files changed

+77
-18
lines changed

4 files changed

+77
-18
lines changed

src/solvers/refinement/string_refinement.cpp

Lines changed: 19 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1623,16 +1623,20 @@ std::vector<exprt> string_refinementt::instantiate_not_contains(
16231623
axiom, index_set0, index_set1, generator);
16241624
}
16251625

1626-
/// replace array-lists by 'with' expressions
1627-
/// \par parameters: an expression containing array-list expressions
1626+
/// Replace array-lists by 'with' expressions.
1627+
/// For instance `array-list [ 0 , x , 1 , y ]` is replaced by
1628+
/// `ARRAYOF(0) WITH [0:=x] WITH [1:=y]`.
1629+
/// Indexes exceeding the maximal string length are ignored.
1630+
/// \param expr: an expression containing array-list expressions
1631+
/// \param string_max_length: maximum length allowed for strings
16281632
/// \return an expression containing no array-list
1629-
exprt string_refinementt::substitute_array_lists(exprt expr) const
1633+
exprt substitute_array_lists(exprt expr, size_t string_max_length)
16301634
{
16311635
for(size_t i=0; i<expr.operands().size(); ++i)
16321636
{
16331637
// TODO: only copy when necessary
1634-
exprt op(expr.operands()[i]);
1635-
expr.operands()[i]=substitute_array_lists(op);
1638+
exprt op=(expr.operands()[i]);
1639+
expr.operands()[i]=substitute_array_lists(op, string_max_length);
16361640
}
16371641

16381642
if(expr.id()=="array-list")
@@ -1643,18 +1647,17 @@ exprt string_refinementt::substitute_array_lists(exprt expr) const
16431647
"operands"));
16441648
typet &char_type=expr.operands()[1].type();
16451649
array_typet arr_type(char_type, infinity_exprt(char_type));
1646-
array_of_exprt new_arr(from_integer(0, char_type),
1647-
arr_type);
1648-
1649-
with_exprt ret_expr(new_arr,
1650-
expr.operands()[0],
1651-
expr.operands()[1]);
1650+
exprt ret_expr=array_of_exprt(from_integer(0, char_type), arr_type);
16521651

1653-
for(size_t i=1; i<expr.operands().size()/2; i++)
1652+
for(size_t i=0; i<expr.operands().size()/2; i++)
16541653
{
1655-
ret_expr=with_exprt(ret_expr,
1656-
expr.operands()[i*2],
1657-
expr.operands()[i*2+1]);
1654+
const exprt &index=expr.operands()[i*2];
1655+
const exprt &value=expr.operands()[i*2+1];
1656+
mp_integer index_value;
1657+
bool not_constant=to_integer(index, index_value);
1658+
if(not_constant ||
1659+
(index_value>=0 && index_value<string_max_length))
1660+
ret_expr=with_exprt(ret_expr, index, value);
16581661
}
16591662
return ret_expr;
16601663
}
@@ -1692,7 +1695,7 @@ exprt string_refinementt::get(const exprt &expr) const
16921695

16931696
ecopy=supert::get(ecopy);
16941697

1695-
return substitute_array_lists(ecopy);
1698+
return substitute_array_lists(ecopy, generator.max_string_length);
16961699
}
16971700

16981701
/// Creates a solver with `axiom` as the only formula added and runs it. If it

src/solvers/refinement/string_refinement.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -136,8 +136,6 @@ class string_refinementt: public bv_refinementt
136136
std::vector<exprt> instantiate_not_contains(
137137
const string_not_contains_constraintt &axiom);
138138

139-
exprt substitute_array_lists(exprt) const;
140-
141139
exprt compute_inverse_function(
142140
const exprt &qvar, const exprt &val, const exprt &f);
143141

@@ -164,6 +162,8 @@ class string_refinementt: public bv_refinementt
164162
std::string string_of_array(const array_exprt &arr);
165163
};
166164

165+
exprt substitute_array_lists(exprt expr, size_t string_max_length);
166+
167167
/// Utility function for concretization of strings. Copies concretized values to
168168
/// the left to initialize the unconcretized indices of concrete_array.
169169
/// \param concrete_array: the vector to populate

unit/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ SRC += unit_tests.cpp \
2525
solvers/refinement/string_constraint_generator_valueof/is_digit_with_radix.cpp \
2626
solvers/refinement/string_constraint_generator_valueof/is_digit_with_radix_lower_case.cpp \
2727
solvers/refinement/string_constraint_instantiation/instantiate_not_contains.cpp \
28+
solvers/refinement/string_refinement/substitute_array_list.cpp \
2829
catch_example.cpp \
2930
# Empty last line
3031

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
/*******************************************************************\
2+
3+
Module: Unit tests for get_numeric_value_from_character in
4+
solvers/refinement/string_constraint_generator_valueof.cpp
5+
6+
Author: DiffBlue Limited. All rights reserved.
7+
8+
\*******************************************************************/
9+
10+
#include <catch.hpp>
11+
12+
#include <util/arith_tools.h>
13+
#include <util/std_types.h>
14+
#include <util/std_expr.h>
15+
#include <solvers/refinement/string_refinement.h>
16+
#include <iostream>
17+
18+
SCENARIO("substitute_array_list",
19+
"[core][solvers][refinement][string_refinement]")
20+
{
21+
const typet char_type=unsignedbv_typet(16);
22+
const typet int_type=signedbv_typet(32);
23+
exprt arr("array-list");
24+
const exprt index0=from_integer(0, int_type);
25+
const exprt charx=from_integer('x', char_type);
26+
const exprt index1=from_integer(1, int_type);
27+
const exprt chary=from_integer('y', char_type);
28+
const exprt index100=from_integer(100, int_type);
29+
30+
// arr is `array-list [ 0 , 'x' , 1 , 'y' , 2 , 'z']`
31+
arr.operands()=
32+
{ index0, charx, index1, chary, index100, from_integer('z', char_type) };
33+
34+
// Max length is 2, so index 2 should get ignored.
35+
const exprt subst=substitute_array_lists(arr, 2);
36+
37+
// Check that `subst = e1 WITH [1:='y']`
38+
REQUIRE(subst.id()==ID_with);
39+
REQUIRE(subst.operands().size()==3);
40+
const exprt &e1=subst.op0();
41+
REQUIRE(subst.op1()==index1);
42+
REQUIRE(subst.op2()==chary);
43+
44+
// Check that `e1 = e2 WITH [0:='x']`
45+
REQUIRE(e1.id()==ID_with);
46+
REQUIRE(e1.operands().size()==3);
47+
const exprt &e2=e1.op0();
48+
REQUIRE(e1.op1()==index0);
49+
REQUIRE(e1.op2()==charx);
50+
51+
// Check that `e1 = ARRAY_OF 0`
52+
REQUIRE(e2.id()==ID_array_of);
53+
REQUIRE(e2.operands().size()==1);
54+
REQUIRE(e2.op0()==from_integer(0, char_type));
55+
}

0 commit comments

Comments
 (0)