Skip to content

Commit 0f7b21c

Browse files
committed
Add validation for array select argument sorts
1 parent 787b3c1 commit 0f7b21c

File tree

7 files changed

+133
-87
lines changed

7 files changed

+133
-87
lines changed
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
// Author: Diffblue Ltd.
2+
3+
#ifndef CPROVER_SOLVERS_SMT2_INCREMENTAL_RESPONSE_OR_ERROR_H
4+
#define CPROVER_SOLVERS_SMT2_INCREMENTAL_RESPONSE_OR_ERROR_H
5+
6+
#include <util/invariant.h>
7+
#include <util/optional.h>
8+
9+
#include <string>
10+
#include <vector>
11+
12+
/// Holds either a valid parsed response or response sub-tree of type \tparam
13+
/// smtt or a collection of message strings explaining why the given input was
14+
/// not valid.
15+
template <class smtt>
16+
class response_or_errort final
17+
{
18+
public:
19+
explicit response_or_errort(smtt smt) : smt{std::move(smt)}
20+
{
21+
}
22+
23+
explicit response_or_errort(std::string message)
24+
: messages{std::move(message)}
25+
{
26+
}
27+
28+
explicit response_or_errort(std::vector<std::string> messages)
29+
: messages{std::move(messages)}
30+
{
31+
}
32+
33+
/// \brief Gets the smt response if the response is valid, or returns nullptr
34+
/// otherwise.
35+
const smtt *get_if_valid() const
36+
{
37+
INVARIANT(
38+
smt.has_value() == messages.empty(),
39+
"The response_or_errort class must be in the valid state or error state, "
40+
"exclusively.");
41+
return smt.has_value() ? &smt.value() : nullptr;
42+
}
43+
44+
/// \brief Gets the error messages if the response is invalid, or returns
45+
/// nullptr otherwise.
46+
const std::vector<std::string> *get_if_error() const
47+
{
48+
INVARIANT(
49+
smt.has_value() == messages.empty(),
50+
"The response_or_errort class must be in the valid state or error state, "
51+
"exclusively.");
52+
return smt.has_value() ? nullptr : &messages;
53+
}
54+
55+
private:
56+
// The below two fields could be a single `std::variant` field, if there was
57+
// an implementation of it available in the cbmc repository. However at the
58+
// time of writing we are targeting C++11, `std::variant` was introduced in
59+
// C++17 and we have no backported version.
60+
optionalt<smtt> smt;
61+
std::vector<std::string> messages;
62+
};
63+
64+
#endif // CPROVER_SOLVERS_SMT2_INCREMENTAL_RESPONSE_OR_ERROR_H

src/solvers/smt2_incremental/smt_array_theory.cpp

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -14,15 +14,24 @@ smt_sortt smt_array_theoryt::selectt::return_sort(
1414
return array.get_sort().cast<smt_array_sortt>()->element_sort();
1515
}
1616

17-
void smt_array_theoryt::selectt::validate(
17+
std::vector<std::string> smt_array_theoryt::selectt::validation_errors(
1818
const smt_termt &array,
1919
const smt_termt &index)
2020
{
2121
const auto array_sort = array.get_sort().cast<smt_array_sortt>();
22-
INVARIANT(array_sort, "\"select\" may only select from an array.");
23-
INVARIANT(
24-
array_sort->index_sort() == index.get_sort(),
25-
"Sort of arrays index must match the sort of the index supplied.");
22+
if(!array_sort)
23+
return {"\"select\" may only select from an array."};
24+
if(array_sort->index_sort() != index.get_sort())
25+
return {"Sort of arrays index must match the sort of the index supplied."};
26+
return {};
27+
}
28+
29+
void smt_array_theoryt::selectt::validate(
30+
const smt_termt &array,
31+
const smt_termt &index)
32+
{
33+
const auto validation_errors = selectt::validation_errors(array, index);
34+
INVARIANT(validation_errors.empty(), validation_errors[0]);
2635
}
2736

2837
const smt_function_application_termt::factoryt<smt_array_theoryt::selectt>

src/solvers/smt2_incremental/smt_array_theory.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@ class smt_array_theoryt
1313
static const char *identifier();
1414
static smt_sortt
1515
return_sort(const smt_termt &array, const smt_termt &index);
16+
static std::vector<std::string>
17+
validation_errors(const smt_termt &array, const smt_termt &index);
1618
static void validate(const smt_termt &array, const smt_termt &index);
1719
};
1820
static const smt_function_application_termt::factoryt<selectt> select;

src/solvers/smt2_incremental/smt_response_validation.cpp

Lines changed: 2 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -29,45 +29,6 @@ static response_or_errort<smt_termt> validate_term(
2929
const irept &parse_tree,
3030
const std::unordered_map<irep_idt, smt_identifier_termt> &identifier_table);
3131

32-
template <class smtt>
33-
response_or_errort<smtt>::response_or_errort(smtt smt) : smt{std::move(smt)}
34-
{
35-
}
36-
37-
template <class smtt>
38-
response_or_errort<smtt>::response_or_errort(std::string message)
39-
: messages{std::move(message)}
40-
{
41-
}
42-
43-
template <class smtt>
44-
response_or_errort<smtt>::response_or_errort(std::vector<std::string> messages)
45-
: messages{std::move(messages)}
46-
{
47-
}
48-
49-
template <class smtt>
50-
const smtt *response_or_errort<smtt>::get_if_valid() const
51-
{
52-
INVARIANT(
53-
smt.has_value() == messages.empty(),
54-
"The response_or_errort class must be in the valid state or error state, "
55-
"exclusively.");
56-
return smt.has_value() ? &smt.value() : nullptr;
57-
}
58-
59-
template <class smtt>
60-
const std::vector<std::string> *response_or_errort<smtt>::get_if_error() const
61-
{
62-
INVARIANT(
63-
smt.has_value() == messages.empty(),
64-
"The response_or_errort class must be in the valid state or error state, "
65-
"exclusively.");
66-
return smt.has_value() ? nullptr : &messages;
67-
}
68-
69-
template class response_or_errort<smt_responset>;
70-
7132
// Implementation detail of `collect_messages` below.
7233
template <typename argumentt, typename... argumentst>
7334
void collect_messages_impl(
@@ -297,8 +258,8 @@ static optionalt<response_or_errort<smt_termt>> try_select_validation(
297258
const auto messages = collect_messages(array, index);
298259
if(!messages.empty())
299260
return response_or_errort<smt_termt>{messages};
300-
return response_or_errort<smt_termt>{
301-
smt_array_theoryt::select(*array.get_if_valid(), *index.get_if_valid())};
261+
return {smt_array_theoryt::select.validation(
262+
*array.get_if_valid(), *index.get_if_valid())};
302263
}
303264

304265
static response_or_errort<smt_termt> validate_term(

src/solvers/smt2_incremental/smt_response_validation.h

Lines changed: 2 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -3,40 +3,10 @@
33
#ifndef CPROVER_SOLVERS_SMT2_INCREMENTAL_SMT_RESPONSE_VALIDATION_H
44
#define CPROVER_SOLVERS_SMT2_INCREMENTAL_SMT_RESPONSE_VALIDATION_H
55

6-
#include <solvers/smt2_incremental/smt_responses.h>
7-
#include <util/invariant.h>
86
#include <util/nodiscard.h>
9-
#include <util/optional.h>
10-
11-
#include <string>
12-
#include <vector>
13-
14-
/// Holds either a valid parsed response or response sub-tree of type \tparam
15-
/// smtt or a collection of message strings explaining why the given input was
16-
/// not valid.
17-
template <class smtt>
18-
class response_or_errort final
19-
{
20-
public:
21-
explicit response_or_errort(smtt smt);
22-
explicit response_or_errort(std::string message);
23-
explicit response_or_errort(std::vector<std::string> messages);
247

25-
/// \brief Gets the smt response if the response is valid, or returns nullptr
26-
/// otherwise.
27-
const smtt *get_if_valid() const;
28-
/// \brief Gets the error messages if the response is invalid, or returns
29-
/// nullptr otherwise.
30-
const std::vector<std::string> *get_if_error() const;
31-
32-
private:
33-
// The below two fields could be a single `std::variant` field, if there was
34-
// an implementation of it available in the cbmc repository. However at the
35-
// time of writing we are targeting C++11, `std::variant` was introduced in
36-
// C++17 and we have no backported version.
37-
optionalt<smtt> smt;
38-
std::vector<std::string> messages;
39-
};
8+
#include <solvers/smt2_incremental/response_or_error.h>
9+
#include <solvers/smt2_incremental/smt_responses.h>
4010

4111
NODISCARD response_or_errort<smt_responset> validate_smt_response(
4212
const irept &parse_tree,

src/solvers/smt2_incremental/smt_terms.h

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55

66
#include <util/irep.h>
77

8+
#include <solvers/smt2_incremental/response_or_error.h>
89
#include <solvers/smt2_incremental/smt_index.h>
910
#include <solvers/smt2_incremental/smt_sorts.h>
1011
#include <solvers/smt2_incremental/type_traits.h>
@@ -204,6 +205,20 @@ class smt_function_application_termt : public smt_termt
204205
function.identifier(), std::move(return_sort), indices(function)},
205206
{std::forward<argument_typest>(arguments)...}};
206207
}
208+
209+
template <typename... argument_typest>
210+
response_or_errort<smt_termt>
211+
validation(argument_typest &&... arguments) const
212+
{
213+
const auto validation_errors = function.validation_errors(arguments...);
214+
if(!validation_errors.empty())
215+
return response_or_errort<smt_termt>{validation_errors};
216+
auto return_sort = function.return_sort(arguments...);
217+
return response_or_errort<smt_termt>{smt_function_application_termt{
218+
smt_identifier_termt{
219+
function.identifier(), std::move(return_sort), indices(function)},
220+
{std::forward<argument_typest>(arguments)...}}};
221+
}
207222
};
208223
};
209224

unit/solvers/smt2_incremental/smt_response_validation.cpp

Lines changed: 34 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -176,15 +176,40 @@ TEST_CASE("smt get-value response validation", "[core][smt2_incremental]")
176176
smt_array_sortt{
177177
smt_bit_vector_sortt{32}, smt_bit_vector_sortt{32}}}});
178178

179-
const response_or_errort<smt_responset> response_get_select =
180-
validate_smt_response(
181-
*smt2irep("(((select |b| (_ bv10 32)) #x0000002a))").parsed_output,
182-
identifier_table);
183-
184-
CHECK(
185-
*response_get_select.get_if_valid() ==
186-
smt_get_value_responset{{smt_get_value_responset::valuation_pairt{
187-
select, smt_bit_vector_constant_termt{0x2A, 32}}}});
179+
SECTION("Valid application of smt_array_theoryt::select")
180+
{
181+
const response_or_errort<smt_responset> response_get_select =
182+
validate_smt_response(
183+
*smt2irep("(((select |b| (_ bv10 32)) #x0000002a))").parsed_output,
184+
identifier_table);
185+
CHECK(
186+
*response_get_select.get_if_valid() ==
187+
smt_get_value_responset{{smt_get_value_responset::valuation_pairt{
188+
select, smt_bit_vector_constant_termt{0x2A, 32}}}});
189+
}
190+
SECTION("Invalid due to selecting from non-array")
191+
{
192+
const response_or_errort<smt_responset> response_get_select =
193+
validate_smt_response(
194+
*smt2irep("(((select (_ bv10 32) (_ bv10 32)) #x0000002a))")
195+
.parsed_output,
196+
identifier_table);
197+
CHECK(
198+
*response_get_select.get_if_error() ==
199+
std::vector<std::string>{
200+
"\"select\" may only select from an array."});
201+
}
202+
SECTION("Invalid due to selecting invalid index sort")
203+
{
204+
const response_or_errort<smt_responset> response_get_select =
205+
validate_smt_response(
206+
*smt2irep("(((select |b| (_ bv10 16)) #x0000002a))").parsed_output,
207+
identifier_table);
208+
CHECK(
209+
*response_get_select.get_if_error() ==
210+
std::vector<std::string>{
211+
"Sort of arrays index must match the sort of the index supplied."});
212+
}
188213
}
189214
SECTION("Descriptors which are bit vector constants")
190215
{

0 commit comments

Comments
 (0)