Skip to content

Commit 585039a

Browse files
author
Enrico Steffinlongo
authored
Merge pull request #7079 from esteffin/esteffin/array-of-exprt
Translation of array_of_exprt to SMT 2 backend
2 parents 5c83574 + 4f070cd commit 585039a

File tree

9 files changed

+144
-29
lines changed

9 files changed

+144
-29
lines changed

.github/workflows/pull-request-checks.yaml

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -698,13 +698,22 @@ jobs:
698698
- name: Fetch dependencies
699699
run: |
700700
sudo apt-get update
701-
sudo apt-get install --no-install-recommends -y g++ gdb flex bison cmake ninja-build maven jq libxml2-utils dpkg-dev ccache z3
701+
sudo apt-get install --no-install-recommends -y g++ gdb flex bison cmake ninja-build maven jq libxml2-utils dpkg-dev ccache
702702
# remove libgcc-s1, which isn't normally available in Ubuntu 18.04
703703
target=$(dpkg-query -W --showformat='${Version}\n' gcc-8-base | head -n 1)
704704
# libgcc1 uses an epoch, thus the extra 1:
705705
sudo apt-get install -y --allow-downgrades --reinstall gcc g++ libgcc-s1- libstdc++6=$target liblsan0=$target libtsan0=$target libcc1-0=$target libgcc1=1:$target gdb=8.1.1-0ubuntu1
706-
- name: Confirm z3 solver is available and log the version installed
707-
run: z3 --version
706+
- name: Download z3 4.11.0 from the python wheel package, extract it and make sure it can be deployed
707+
run: |
708+
sudo apt-get install --no-install-recommends -y unzip
709+
# download the z3 python wheel package
710+
wget -O z3.4.11.0.whl https://github.com/Z3Prover/z3/releases/download/z3-4.11.0/z3_solver-4.11.0.0-py2.py3-none-manylinux1_x86_64.whl
711+
# unpack the bundle using python
712+
unzip z3.4.11.0.whl
713+
# make z3 executable and move it in /usr/local/bin
714+
chmod u+x ./z3_solver-4.11.0.0.data/data/bin/z3
715+
mv ./z3_solver-4.11.0.0.data/data/bin/z3 /usr/local/bin/
716+
z3 --version
708717
- name: Download cvc-5 from the releases page and make sure it can be deployed
709718
run: |
710719
wget -O cvc5 https://github.com/cvc5/cvc5/releases/download/cvc5-${{env.cvc5-version}}/cvc5-Linux
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
int main()
2+
{
3+
int example_array[10000];
4+
unsigned int index;
5+
__CPROVER_assume(index < 999);
6+
7+
__CPROVER_array_set(example_array, 43);
8+
__CPROVER_assert(example_array[index] != 43, "False array condition");
9+
10+
__CPROVER_array_set(example_array, 42);
11+
__CPROVER_assert(example_array[index] == 42, "Valid array condition");
12+
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
CORE
2+
array_of.c
3+
4+
Passing problem to incremental SMT2 solving
5+
line \d+ False array condition: FAILURE
6+
line \d+ Valid array condition: SUCCESS
7+
^EXIT=10$
8+
^SIGNAL=0$
9+
--
10+
--
11+
Test using __CPROVER_array_set consisting in an `array_of` node which sets all values of a given
12+
array to a given value.
13+
This test uses a forall SMT statement.

regression/cbmc-incr-smt2/nondeterministic-int-assert/control_flow.desc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ control_flow.c
33
--verbosity 10
44
Passing problem to incremental SMT2 solving via
55
Sending command to SMT2 solver - \(set-option :produce-models true\)
6-
Sending command to SMT2 solver - \(set-logic QF_AUFBV\)
6+
Sending command to SMT2 solver - \(set-logic ALL\)
77
Sending command to SMT2 solver - \(declare-fun |goto_symex::&92;guard#1| \(\) Bool\)
88
Sending command to SMT2 solver - \(define-fun |B1| \(\) Bool |goto_symex::&92;guard#1|\)
99
Sending command to SMT2 solver - \(declare-fun |main::1::x!0@1#1| \(\) \(_ BitVec 32\)\)

regression/cbmc-incr-smt2/nondeterministic-int-assert/incremental_solver_called.desc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ test.c
33
--verbosity 10
44
Passing problem to incremental SMT2 solving via
55
Sending command to SMT2 solver - \(set-option :produce-models true\)
6-
Sending command to SMT2 solver - \(set-logic QF_AUFBV\)
6+
Sending command to SMT2 solver - \(set-logic ALL\)
77
Sending command to SMT2 solver - \(define-fun |B0| \(\) Bool true\)
88
Sending command to SMT2 solver - \(declare-fun |main::1::x!0@1#1| \(\) \(_ BitVec 32\)\)
99
Sending command to SMT2 solver - \(define-fun |B1| \(\) Bool \(|=| |main::1::x!0@1#1| |main::1::x!0@1#1|\)\)

src/solvers/smt2_incremental/convert_expr_to_smt.cpp

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -906,8 +906,10 @@ static smt_termt convert_expr_to_smt(
906906
const array_of_exprt &array_of,
907907
const sub_expression_mapt &converted)
908908
{
909-
UNIMPLEMENTED_FEATURE(
910-
"Generation of SMT formula for array of expression: " + array_of.pretty());
909+
// This function is unreachable as the `array_of_exprt` nodes are already
910+
// fully converted by the incremental decision procedure functions
911+
// (smt2_incremental_decision_proceduret::define_array_function).
912+
UNHANDLED_CASE;
911913
}
912914

913915
static smt_termt convert_expr_to_smt(
@@ -1353,9 +1355,10 @@ static smt_termt convert_expr_to_smt(
13531355
const array_exprt &array_construction,
13541356
const sub_expression_mapt &converted)
13551357
{
1356-
UNIMPLEMENTED_FEATURE(
1357-
"Generation of SMT formula for array construction expression: " +
1358-
array_construction.pretty());
1358+
// This function is unreachable as the `array_exprt` nodes are already fully
1359+
// converted by the incremental decision procedure functions
1360+
// (smt2_incremental_decision_proceduret::define_array_function).
1361+
UNHANDLED_CASE;
13591362
}
13601363

13611364
static smt_termt convert_expr_to_smt(

src/solvers/smt2_incremental/smt2_incremental_decision_procedure.cpp

Lines changed: 45 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,7 @@ static std::vector<exprt> gather_dependent_expressions(const exprt &expr)
7171
if(
7272
can_cast_expr<symbol_exprt>(expr_node) ||
7373
can_cast_expr<array_exprt>(expr_node) ||
74+
can_cast_expr<array_of_exprt>(expr_node) ||
7475
can_cast_expr<nondet_symbol_exprt>(expr_node))
7576
{
7677
dependent_expressions.push_back(expr_node);
@@ -79,17 +80,10 @@ static std::vector<exprt> gather_dependent_expressions(const exprt &expr)
7980
return dependent_expressions;
8081
}
8182

82-
void smt2_incremental_decision_proceduret::define_array_function(
83-
const array_exprt &array)
83+
void smt2_incremental_decision_proceduret::initialize_array_elements(
84+
const array_exprt &array,
85+
const smt_identifier_termt &array_identifier)
8486
{
85-
const smt_sortt array_sort = convert_type_to_smt_sort(array.type());
86-
INVARIANT(
87-
array_sort.cast<smt_array_sortt>(),
88-
"Converting array typed expression to SMT should result in a term of array "
89-
"sort.");
90-
const smt_identifier_termt array_identifier = smt_identifier_termt{
91-
"array_" + std::to_string(array_sequence()), array_sort};
92-
solver_process->send(smt_declare_function_commandt{array_identifier, {}});
9387
const std::vector<exprt> &elements = array.operands();
9488
const typet &index_type = array.type().index_type();
9589
for(std::size_t i = 0; i < elements.size(); ++i)
@@ -100,6 +94,39 @@ void smt2_incremental_decision_proceduret::define_array_function(
10094
convert_expr_to_smt(elements.at(i)))};
10195
solver_process->send(element_definition);
10296
}
97+
}
98+
99+
void smt2_incremental_decision_proceduret::initialize_array_elements(
100+
const array_of_exprt &array,
101+
const smt_identifier_termt &array_identifier)
102+
{
103+
const smt_sortt index_type =
104+
convert_type_to_smt_sort(array.type().index_type());
105+
const smt_identifier_termt array_index_identifier{
106+
id2string(array_identifier.identifier()) + "_index", index_type};
107+
const smt_termt element_value = convert_expr_to_smt(array.what());
108+
109+
const smt_assert_commandt elements_definition{smt_forall_termt{
110+
{array_index_identifier},
111+
smt_core_theoryt::equal(
112+
smt_array_theoryt::select(array_identifier, array_index_identifier),
113+
element_value)}};
114+
solver_process->send(elements_definition);
115+
}
116+
117+
template <typename t_exprt>
118+
void smt2_incremental_decision_proceduret::define_array_function(
119+
const t_exprt &array)
120+
{
121+
const smt_sortt array_sort = convert_type_to_smt_sort(array.type());
122+
INVARIANT(
123+
array_sort.cast<smt_array_sortt>(),
124+
"Converting array typed expression to SMT should result in a term of array "
125+
"sort.");
126+
const smt_identifier_termt array_identifier{
127+
"array_" + std::to_string(array_sequence()), array_sort};
128+
solver_process->send(smt_declare_function_commandt{array_identifier, {}});
129+
initialize_array_elements(array, array_identifier);
103130
expression_identifiers.emplace(array, array_identifier);
104131
}
105132

@@ -168,9 +195,14 @@ void smt2_incremental_decision_proceduret::define_dependent_functions(
168195
solver_process->send(function);
169196
}
170197
}
171-
if(const auto array_expr = expr_try_dynamic_cast<array_exprt>(current))
198+
else if(const auto array_expr = expr_try_dynamic_cast<array_exprt>(current))
172199
define_array_function(*array_expr);
173-
if(
200+
else if(
201+
const auto array_of_expr = expr_try_dynamic_cast<array_of_exprt>(current))
202+
{
203+
define_array_function(*array_of_expr);
204+
}
205+
else if(
174206
const auto nondet_symbol =
175207
expr_try_dynamic_cast<nondet_symbol_exprt>(current))
176208
{
@@ -213,8 +245,7 @@ smt2_incremental_decision_proceduret::smt2_incremental_decision_proceduret(
213245
{
214246
solver_process->send(
215247
smt_set_option_commandt{smt_option_produce_modelst{true}});
216-
solver_process->send(smt_set_logic_commandt{
217-
smt_logic_quantifier_free_arrays_uninterpreted_functions_bit_vectorst{}});
248+
solver_process->send(smt_set_logic_commandt{smt_logic_allt{}});
218249
solver_process->send(object_size_function.declaration);
219250
}
220251

src/solvers/smt2_incremental/smt2_incremental_decision_procedure.h

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -55,11 +55,29 @@ class smt2_incremental_decision_proceduret final
5555
protected:
5656
// Implementation of protected decision_proceduret member function.
5757
resultt dec_solve() override;
58-
/// \brief Defines a function of array sort and asserts the element values.
58+
/// \brief Defines a function of array sort and asserts the element values
59+
/// from `array_exprt` or `array_of_exprt`.
5960
/// \details
6061
/// The new array function identifier is added to the
6162
/// `expression_identifiers` map.
62-
void define_array_function(const array_exprt &array);
63+
/// \note Statically fails if the template type is not a `array_exprt` or
64+
/// `array_of_exprt`.
65+
template <typename t_exprt>
66+
void define_array_function(const t_exprt &array);
67+
/// \brief Generate and send to the SMT solver clauses asserting that each
68+
/// array element is as specified by \p array.
69+
void initialize_array_elements(
70+
const array_exprt &array,
71+
const smt_identifier_termt &array_identifier);
72+
/// \brief Generate and send to the SMT solver clauses asserting that each
73+
/// array element is as specified by \p array.
74+
/// \note This function uses a forall SMT2 term. Using it in combination with
75+
/// arrays, bit vectors and uninterpreted functions requires the `ALL` SMT
76+
/// logic that is not in the SMT 2.6 standard, but that it has been tested
77+
/// working on Z3 and CVC5.
78+
void initialize_array_elements(
79+
const array_of_exprt &array,
80+
const smt_identifier_termt &array_identifier);
6381
/// \brief Defines any functions which \p expr depends on, which have not yet
6482
/// been defined, along with their dependencies in turn.
6583
void define_dependent_functions(const exprt &expr);

unit/solvers/smt2_incremental/smt2_incremental_decision_procedure.cpp

Lines changed: 32 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -171,9 +171,7 @@ TEST_CASE(
171171
test.sent_commands ==
172172
std::vector<smt_commandt>{
173173
smt_set_option_commandt{smt_option_produce_modelst{true}},
174-
smt_set_logic_commandt{
175-
// NOLINTNEXTLINE(whitespace/line_length)
176-
smt_logic_quantifier_free_arrays_uninterpreted_functions_bit_vectorst{}},
174+
smt_set_logic_commandt{smt_logic_allt{}},
177175
test.object_size_function.declaration});
178176
test.sent_commands.clear();
179177
SECTION("Set symbol to true.")
@@ -615,5 +613,36 @@ TEST_CASE(
615613
smt_declare_function_commandt{index_term, {}},
616614
smt_assert_commandt{smt_core_theoryt::equal(
617615
foo_term, smt_array_theoryt::select(array_term, index_term))}};
616+
REQUIRE(test.sent_commands == expected_commands);
617+
}
618+
SECTION("array_of_exprt - all elements set to a given value")
619+
{
620+
const array_of_exprt array_of_expr{
621+
from_integer(42, value_type), array_type};
622+
test.sent_commands.clear();
623+
test.procedure.set_to(
624+
equal_exprt{
625+
foo.symbol_expr(), index_exprt{array_of_expr, index.symbol_expr()}},
626+
true);
627+
const auto foo_term = smt_identifier_termt{"foo", smt_bit_vector_sortt{8}};
628+
const auto array_term = smt_identifier_termt{
629+
"array_0",
630+
smt_array_sortt{smt_bit_vector_sortt{32}, smt_bit_vector_sortt{8}}};
631+
const auto index_term =
632+
smt_identifier_termt{"index", smt_bit_vector_sortt{32}};
633+
const auto forall_term =
634+
smt_identifier_termt{"array_0_index", smt_bit_vector_sortt{32}};
635+
const std::vector<smt_commandt> expected_commands{
636+
smt_declare_function_commandt{foo_term, {}},
637+
smt_declare_function_commandt{array_term, {}},
638+
smt_assert_commandt{smt_forall_termt{
639+
{forall_term},
640+
smt_core_theoryt::equal(
641+
smt_array_theoryt::select(array_term, forall_term),
642+
smt_bit_vector_constant_termt{42, 8})}},
643+
smt_declare_function_commandt{index_term, {}},
644+
smt_assert_commandt{smt_core_theoryt::equal(
645+
foo_term, smt_array_theoryt::select(array_term, index_term))}};
646+
REQUIRE(test.sent_commands == expected_commands);
618647
}
619648
}

0 commit comments

Comments
 (0)