Skip to content

Commit 74c7764

Browse files
authored
Merge pull request #7035 from esteffin/esteffin/is-invalid-pointer-to-smt
Add support for is_invalid_pointer in new SMT2 backend
2 parents 3c3ce18 + 1cea202 commit 74c7764

File tree

10 files changed

+147
-35
lines changed

10 files changed

+147
-35
lines changed
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
#include <assert.h>
2+
#include <stdlib.h>
3+
4+
void main()
5+
{
6+
// special value of the invalid pointer (object bits = 1 and offset = 0), as
7+
// checked for by __CPROVER_is_invalid_pointer()
8+
char *p = (size_t)1 << (sizeof(char *) * 8 - 8);
9+
__CPROVER_assert(
10+
__CPROVER_is_invalid_pointer(p), "INVALID pointer, so passing");
11+
int i;
12+
__CPROVER_assert(
13+
__CPROVER_is_invalid_pointer(&i), "VALID pointer, so failing");
14+
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
CORE
2+
pointer_is_invalid.c
3+
4+
Passing problem to incremental SMT2 solving
5+
\[main\.assertion\.1\] line \d+ INVALID pointer, so passing: SUCCESS
6+
\[main\.assertion\.2\] line \d+ VALID pointer, so failing: FAILURE
7+
^VERIFICATION FAILED$
8+
^EXIT=10$
9+
^SIGNAL=0$
10+
--
11+
--
12+
Tests that an inconsistent assumption involving the special invalid pointer
13+
value and __CPROVER_r_ok() can be detected via assert(0).

regression/cbmc-incr-smt2/pointers/pointer_object3.c

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,9 @@ int main()
1212
__CPROVER_POINTER_OBJECT(NULL) != 0,
1313
"expected to fail with object ID == 0");
1414
// In the case where the program contains a single address of operation,
15-
// the pointer object is going to be 1.
15+
// the pointer object is going to be 2 (1 is invalid pointer that is tested
16+
// somewhere else).
1617
__CPROVER_assert(
17-
__CPROVER_POINTER_OBJECT(&foo) != 1,
18-
"expected to fail with object ID == 1");
18+
__CPROVER_POINTER_OBJECT(&foo) != 2,
19+
"expected to fail with object ID == 2");
1920
}

regression/cbmc-incr-smt2/pointers/pointer_object3.desc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ CORE
22
pointer_object3.c
33

44
\[main\.assertion\.1] line \d+ expected to fail with object ID == 0: FAILURE
5-
\[main\.assertion\.2] line \d+ expected to fail with object ID == 1: FAILURE
5+
\[main\.assertion\.2] line \d+ expected to fail with object ID == 2: FAILURE
66
^VERIFICATION FAILED$
77
^EXIT=10$
88
^SIGNAL=0$

src/solvers/smt2_incremental/convert_expr_to_smt.cpp

Lines changed: 24 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1046,20 +1046,37 @@ static smt_termt convert_expr_to_smt(
10461046

10471047
static smt_termt convert_expr_to_smt(
10481048
const is_invalid_pointer_exprt &is_invalid_pointer,
1049+
const smt_object_mapt &object_map,
10491050
const sub_expression_mapt &converted)
10501051
{
1051-
UNIMPLEMENTED_FEATURE(
1052-
"Generation of SMT formula for is invalid pointer expression: " +
1053-
is_invalid_pointer.pretty());
1052+
const exprt &pointer_expr(to_unary_expr(is_invalid_pointer).op());
1053+
const bitvector_typet *pointer_type =
1054+
type_try_dynamic_cast<bitvector_typet>(pointer_expr.type());
1055+
INVARIANT(pointer_type, "Pointer object should have a bitvector-based type.");
1056+
const std::size_t object_bits = config.bv_encoding.object_bits;
1057+
const std::size_t width = pointer_type->get_width();
1058+
INVARIANT(
1059+
width >= object_bits,
1060+
"Width should be at least as big as the number of object bits.");
1061+
1062+
const auto extract_op = smt_bit_vector_theoryt::extract(
1063+
width - 1, width - object_bits)(converted.at(pointer_expr));
1064+
1065+
const auto &invalid_pointer = object_map.at(make_invalid_pointer_expr());
1066+
1067+
const smt_termt invalid_pointer_address = smt_bit_vector_constant_termt(
1068+
invalid_pointer.unique_id, config.bv_encoding.object_bits);
1069+
1070+
return smt_core_theoryt::equal(invalid_pointer_address, extract_op);
10541071
}
10551072

10561073
static smt_termt convert_expr_to_smt(
1057-
const string_constantt &is_invalid_pointer,
1074+
const string_constantt &string_constant,
10581075
const sub_expression_mapt &converted)
10591076
{
10601077
UNIMPLEMENTED_FEATURE(
1061-
"Generation of SMT formula for is invalid pointer expression: " +
1062-
is_invalid_pointer.pretty());
1078+
"Generation of SMT formula for string constant expression: " +
1079+
string_constant.pretty());
10631080
}
10641081

10651082
static smt_termt convert_expr_to_smt(
@@ -1643,7 +1660,7 @@ static smt_termt dispatch_expr_to_smt_conversion(
16431660
const auto is_invalid_pointer =
16441661
expr_try_dynamic_cast<is_invalid_pointer_exprt>(expr))
16451662
{
1646-
return convert_expr_to_smt(*is_invalid_pointer, converted);
1663+
return convert_expr_to_smt(*is_invalid_pointer, object_map, converted);
16471664
}
16481665
if(const auto string_constant = expr_try_dynamic_cast<string_constantt>(expr))
16491666
{

src/solvers/smt2_incremental/object_tracking.cpp

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,11 @@
99
#include <util/std_expr.h>
1010
#include <util/string_constant.h>
1111

12+
exprt make_invalid_pointer_expr()
13+
{
14+
return constant_exprt(ID_invalid, pointer_type(void_type()));
15+
}
16+
1217
exprt find_object_base_expression(const address_of_exprt &address_of)
1318
{
1419
auto current = std::ref(address_of.object());
@@ -47,12 +52,28 @@ static decision_procedure_objectt make_null_object()
4752
return null_object;
4853
}
4954

55+
static decision_procedure_objectt make_invalid_pointer_object()
56+
{
57+
decision_procedure_objectt invalid_pointer_object;
58+
// Using unique_id = 1, so 0 is the NULL object, 1 is the invalid object and
59+
// other valid objects have unique_id > 1.
60+
invalid_pointer_object.unique_id = 1;
61+
invalid_pointer_object.base_expression = make_invalid_pointer_expr();
62+
invalid_pointer_object.size = from_integer(0, size_type());
63+
return invalid_pointer_object;
64+
}
65+
5066
smt_object_mapt initial_smt_object_map()
5167
{
5268
smt_object_mapt object_map;
5369
decision_procedure_objectt null_object = make_null_object();
54-
exprt base = null_object.base_expression;
55-
object_map.emplace(std::move(base), std::move(null_object));
70+
exprt null_object_base = null_object.base_expression;
71+
object_map.emplace(std::move(null_object_base), std::move(null_object));
72+
decision_procedure_objectt invalid_pointer_object =
73+
make_invalid_pointer_object();
74+
exprt invalid_pointer_object_base = invalid_pointer_object.base_expression;
75+
object_map.emplace(
76+
std::move(invalid_pointer_object_base), std::move(invalid_pointer_object));
5677
return object_map;
5778
}
5879

src/solvers/smt2_incremental/object_tracking.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,4 +115,7 @@ bool objects_are_already_tracked(
115115
const exprt &expression,
116116
const smt_object_mapt &object_map);
117117

118+
/// \brief Create the invalid pointer constant
119+
exprt make_invalid_pointer_expr();
120+
118121
#endif // CPROVER_SOLVERS_SMT2_INCREMENTAL_OBJECT_TRACKING_H

unit/solvers/smt2_incremental/convert_expr_to_smt.cpp

Lines changed: 30 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -222,6 +222,27 @@ TEST_CASE(
222222
REQUIRE_THROWS(test.convert(or_exprt{{true_exprt{}}}));
223223
}
224224

225+
TEST_CASE(
226+
"expr to smt conversion for \"is_invalid_pointer\" operator",
227+
"[core][smt2_incremental]")
228+
{
229+
const std::size_t object_bits = config.bv_encoding.object_bits;
230+
const auto test =
231+
expr_to_smt_conversion_test_environmentt::make(test_archt::x86_64);
232+
const pointer_typet pointer_type = ::pointer_type(void_type());
233+
const std::size_t pointer_width = pointer_type.get_width();
234+
const constant_exprt invalid_ptr{
235+
integer2bvrep(1ul << (pointer_width - object_bits), pointer_width),
236+
pointer_type};
237+
const is_invalid_pointer_exprt is_invalid_ptr{invalid_ptr};
238+
const smt_termt expected_smt_term = smt_core_theoryt::equal(
239+
smt_bit_vector_constant_termt{1, config.bv_encoding.object_bits},
240+
smt_bit_vector_theoryt::extract(
241+
pointer_width - 1,
242+
pointer_width - object_bits)(test.convert(invalid_ptr)));
243+
CHECK(test.convert(is_invalid_ptr) == expected_smt_term);
244+
}
245+
225246
TEST_CASE(
226247
"expr to smt conversion for \"xor\" operator",
227248
"[core][smt2_incremental]")
@@ -1358,20 +1379,20 @@ TEST_CASE(
13581379
{
13591380
config.bv_encoding.object_bits = 8;
13601381
const auto converted = test.convert(address_of_foo);
1361-
CHECK(test.object_map.at(foo).unique_id == 1);
1382+
CHECK(test.object_map.at(foo).unique_id == 2);
13621383
CHECK(
13631384
converted == smt_bit_vector_theoryt::concat(
1364-
smt_bit_vector_constant_termt{1, 8},
1385+
smt_bit_vector_constant_termt{2, 8},
13651386
smt_bit_vector_constant_termt{0, 56}));
13661387
}
13671388
SECTION("16 object bits")
13681389
{
13691390
config.bv_encoding.object_bits = 16;
13701391
const auto converted = test.convert(address_of_foo);
1371-
CHECK(test.object_map.at(foo).unique_id == 1);
1392+
CHECK(test.object_map.at(foo).unique_id == 2);
13721393
CHECK(
13731394
converted == smt_bit_vector_theoryt::concat(
1374-
smt_bit_vector_constant_termt{1, 16},
1395+
smt_bit_vector_constant_termt{2, 16},
13751396
smt_bit_vector_constant_termt{0, 48}));
13761397
}
13771398
}
@@ -1429,15 +1450,15 @@ TEST_CASE(
14291450
track_expression_objects(comparison, ns, test.object_map);
14301451
INFO("Expression " + comparison.pretty(1, 0));
14311452
const auto converted = test.convert(comparison);
1432-
CHECK(test.object_map.at(foo).unique_id == 2);
1433-
CHECK(test.object_map.at(bar).unique_id == 1);
1453+
CHECK(test.object_map.at(foo).unique_id == 3);
1454+
CHECK(test.object_map.at(bar).unique_id == 2);
14341455
CHECK(
14351456
converted == smt_core_theoryt::distinct(
14361457
smt_bit_vector_theoryt::concat(
1437-
smt_bit_vector_constant_termt{2, 8},
1458+
smt_bit_vector_constant_termt{3, 8},
14381459
smt_bit_vector_constant_termt{0, 56}),
14391460
smt_bit_vector_theoryt::concat(
1440-
smt_bit_vector_constant_termt{1, 8},
1461+
smt_bit_vector_constant_termt{2, 8},
14411462
smt_bit_vector_constant_termt{0, 56})));
14421463
}
14431464
}
@@ -1543,7 +1564,7 @@ TEST_CASE(
15431564
const object_size_exprt object_size{
15441565
address_of_exprt{foo}, unsignedbv_typet{64}};
15451566
track_expression_objects(object_size, ns, test.object_map);
1546-
const auto foo_id = 1;
1567+
const auto foo_id = 2;
15471568
CHECK(test.object_map.at(foo).unique_id == foo_id);
15481569
const auto object_bits = config.bv_encoding.object_bits;
15491570
const auto object = smt_bit_vector_constant_termt{foo_id, object_bits};

unit/solvers/smt2_incremental/object_tracking.cpp

Lines changed: 16 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -118,11 +118,20 @@ TEST_CASE("Tracking object base expressions", "[core][smt2_incremental]")
118118
smt_object_mapt object_map = initial_smt_object_map();
119119
SECTION("Check initial object map has null pointer")
120120
{
121-
REQUIRE(object_map.size() == 1);
121+
REQUIRE(object_map.size() == 2);
122122
const exprt null_pointer = null_pointer_exprt{::pointer_type(void_type())};
123-
CHECK(object_map.begin()->first == null_pointer);
124-
CHECK(object_map.begin()->second.unique_id == 0);
125-
CHECK(object_map.begin()->second.base_expression == null_pointer);
123+
const auto actual_null_object = object_map.find(null_pointer);
124+
CHECK(actual_null_object->first == null_pointer);
125+
CHECK(actual_null_object->second.unique_id == 0);
126+
CHECK(actual_null_object->second.base_expression == null_pointer);
127+
const exprt invalid_object_pointer = make_invalid_pointer_expr();
128+
const auto actual_invalid_object_pointer =
129+
object_map.find(invalid_object_pointer);
130+
CHECK(actual_invalid_object_pointer->first == invalid_object_pointer);
131+
CHECK(actual_invalid_object_pointer->second.unique_id == 1);
132+
CHECK(
133+
actual_invalid_object_pointer->second.base_expression ==
134+
invalid_object_pointer);
126135
}
127136
symbol_tablet symbol_table;
128137
namespacet ns{symbol_table};
@@ -133,15 +142,15 @@ TEST_CASE("Tracking object base expressions", "[core][smt2_incremental]")
133142
track_expression_objects(compound_expression, ns, object_map);
134143
SECTION("Tracking expression objects")
135144
{
136-
CHECK(object_map.size() == 4);
145+
CHECK(object_map.size() == 5);
137146
const auto foo_object = object_map.find(foo);
138147
REQUIRE(foo_object != object_map.end());
139148
CHECK(foo_object->second.base_expression == foo);
140-
CHECK(foo_object->second.unique_id == 3);
149+
CHECK(foo_object->second.unique_id == 4);
141150
const auto bar_object = object_map.find(bar);
142151
REQUIRE(bar_object != object_map.end());
143152
CHECK(bar_object->second.base_expression == bar);
144-
CHECK(bar_object->second.unique_id == 1);
153+
CHECK(bar_object->second.unique_id == 2);
145154
}
146155
SECTION("Confirming objects are tracked.")
147156
{

unit/solvers/smt2_incremental/smt2_incremental_decision_procedure.cpp

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -414,6 +414,9 @@ TEST_CASE(
414414
const auto null_object_size_definition =
415415
test.object_size_function.make_definition(
416416
0, smt_bit_vector_constant_termt{0, 32});
417+
const auto invalid_pointer_object_size_definition =
418+
test.object_size_function.make_definition(
419+
1, smt_bit_vector_constant_termt{0, 32});
417420
const symbolt foo = make_test_symbol("foo", signedbv_typet{16});
418421
const smt_identifier_termt foo_term{"foo", smt_bit_vector_sortt{16}};
419422
const exprt expr_42 = from_integer({42}, signedbv_typet{16});
@@ -425,13 +428,23 @@ TEST_CASE(
425428
test.procedure.set_to(equal_42, true);
426429
test.mock_responses.push_back(smt_check_sat_responset{smt_sat_responset{}});
427430
test.procedure();
431+
std::vector<smt_commandt> expected_commands{
432+
smt_declare_function_commandt{foo_term, {}},
433+
smt_assert_commandt{smt_core_theoryt::equal(foo_term, term_42)},
434+
invalid_pointer_object_size_definition,
435+
null_object_size_definition,
436+
smt_check_sat_commandt{}};
428437
REQUIRE(
429-
test.sent_commands ==
430-
std::vector<smt_commandt>{
431-
smt_declare_function_commandt{foo_term, {}},
432-
smt_assert_commandt{smt_core_theoryt::equal(foo_term, term_42)},
433-
null_object_size_definition,
434-
smt_check_sat_commandt{}});
438+
(test.sent_commands.size() == expected_commands.size() &&
439+
std::all_of(
440+
expected_commands.begin(),
441+
expected_commands.end(),
442+
[&](const smt_commandt &command) -> bool {
443+
return std::find(
444+
test.sent_commands.begin(),
445+
test.sent_commands.end(),
446+
command) != test.sent_commands.end();
447+
})));
435448
SECTION("Get \"foo\" value back")
436449
{
437450
test.sent_commands.clear();

0 commit comments

Comments
 (0)