Skip to content

Commit f73a1a0

Browse files
authored
Merge pull request #6905 from NlightNFotis/relational_operators_pointer_support
Relational operators support for pointers in new SMT backend
2 parents ae93642 + 118b5b1 commit f73a1a0

File tree

8 files changed

+169
-1
lines changed

8 files changed

+169
-1
lines changed
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
#include <stdlib.h>
2+
3+
int main()
4+
{
5+
int x;
6+
int *y = &x;
7+
int *z = &x;
8+
9+
if(x)
10+
{
11+
y++;
12+
}
13+
else
14+
{
15+
z++;
16+
}
17+
18+
__CPROVER_assume(y >= z);
19+
__CPROVER_assert(x != y, "x != y: expected successful");
20+
__CPROVER_assert(x == y, "x == y: expected failure");
21+
22+
__CPROVER_assume(z >= x);
23+
24+
__CPROVER_assert(z >= x, "z >= x: expected successful");
25+
__CPROVER_assert(z <= y, "z <= y: expected successful");
26+
__CPROVER_assert(z <= x, "z <= x: expected failure");
27+
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
CORE
2+
pointers_assume.c
3+
--trace
4+
\[main\.assertion\.1\] line \d+ x != y: expected successful: SUCCESS
5+
\[main\.assertion\.2\] line \d+ x == y: expected failure: FAILURE
6+
\[main\.assertion\.3\] line \d+ z >= x: expected successful: SUCCESS
7+
\[main\.assertion\.4\] line \d+ z <= y: expected successful: SUCCESS
8+
\[main\.assertion\.5\] line \d+ z <= x: expected failure: FAILURE
9+
^EXIT=10$
10+
^SIGNAL=0$
11+
--
12+
--
13+
This is testing basic pointer relational operator support for three objects
14+
defined in the function's stack frame.
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
#define NULL (void *)0
2+
3+
int main()
4+
{
5+
int i = 12;
6+
int *x = &i;
7+
int *y = x + 1;
8+
int *z = x - 1;
9+
10+
// Assertions on y's relation to x
11+
__CPROVER_assert(y != x, "y != x: expected successful");
12+
__CPROVER_assert(y > x, "y > x: expected successful");
13+
__CPROVER_assert(y < x, "y < x: expected failure");
14+
15+
// Assertions on z's relation to x
16+
__CPROVER_assert(z != x, "z != x: expected successful");
17+
__CPROVER_assert(z > x, "z > x: expected failure");
18+
__CPROVER_assert(z < x, "z < x: expected success");
19+
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
CORE
2+
pointers_stack_lessthan.c
3+
--trace
4+
\[main\.assertion\.1] line \d+ y != x: expected successful: SUCCESS
5+
\[main\.assertion\.2] line \d+ y > x: expected successful: SUCCESS
6+
\[main\.assertion\.3] line \d+ y < x: expected failure: FAILURE
7+
\[main\.assertion\.4] line \d+ z != x: expected successful: SUCCESS
8+
\[main\.assertion\.5] line \d+ z > x: expected failure: FAILURE
9+
\[main\.assertion\.6] line \d+ z < x: expected success: SUCCESS
10+
^EXIT=10$
11+
^SIGNAL=0$
12+
--
13+
--
14+
This is testing basic pointer relational operator support for three objects
15+
defined in the function's stack frame.
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
#include <stdlib.h>
2+
3+
int main()
4+
{
5+
int *a = malloc(sizeof(int) * 5);
6+
7+
for(int i = 0; i < 5; i++)
8+
*(a + i) = i;
9+
10+
for(int i = 0; i < 5; i++)
11+
{
12+
__CPROVER_assert(*(a + i) >= i, "*(a + i) >= i: expected successful");
13+
__CPROVER_assert(*(a + i) <= i, "*(a + i) <= i: expected successful");
14+
__CPROVER_assert(*(a + i) == i, "*(a + i) <= i: expected successful");
15+
__CPROVER_assert(*(a + i) != i, "*(a + i) <= i: expected failure");
16+
}
17+
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
CORE
2+
pointers_stack_malloc.c
3+
--trace
4+
\[main\.assertion\.1\] line \d+ \*\(a \+ i\) >= i: expected successful: SUCCESS
5+
\[main\.assertion\.2\] line \d+ \*\(a \+ i\) <= i: expected successful: SUCCESS
6+
\[main\.assertion\.3\] line \d+ \*\(a \+ i\) <= i: expected successful: SUCCESS
7+
\[main\.assertion\.4\] line \d+ \*\(a \+ i\) <= i: expected failure: FAILURE
8+
^EXIT=10$
9+
^SIGNAL=0$
10+
--
11+
--
12+
This is testing the support for relational operators as applied to pointer objects
13+
backed by a malloc and initialised to some values.

src/solvers/smt2_incremental/convert_expr_to_smt.cpp

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -530,13 +530,31 @@ static smt_termt convert_relational_to_smt(
530530
const auto &lhs = converted.at(binary_relation.lhs());
531531
const auto &rhs = converted.at(binary_relation.rhs());
532532
const typet operand_type = binary_relation.lhs().type();
533-
if(lhs.get_sort().cast<smt_bit_vector_sortt>())
533+
if(can_cast_type<pointer_typet>(operand_type))
534+
{
535+
// The code here is operating under the assumption that the comparison
536+
// operands have types for which the comparison makes sense.
537+
538+
// We already know this is the case given that we have followed
539+
// the if statement branch, but including the same check here
540+
// for consistency (it's cheap).
541+
const auto lhs_type_is_pointer =
542+
can_cast_type<pointer_typet>(binary_relation.lhs().type());
543+
const auto rhs_type_is_pointer =
544+
can_cast_type<pointer_typet>(binary_relation.rhs().type());
545+
INVARIANT(
546+
lhs_type_is_pointer && rhs_type_is_pointer,
547+
"pointer comparison requires that both operand types are pointers.");
548+
return unsigned_factory(lhs, rhs);
549+
}
550+
else if(lhs.get_sort().cast<smt_bit_vector_sortt>())
534551
{
535552
if(can_cast_type<unsignedbv_typet>(operand_type))
536553
return unsigned_factory(lhs, rhs);
537554
if(can_cast_type<signedbv_typet>(operand_type))
538555
return signed_factory(lhs, rhs);
539556
}
557+
540558
UNIMPLEMENTED_FEATURE(
541559
"Generation of SMT formula for relational expression: " +
542560
binary_relation.pretty());

unit/solvers/smt2_incremental/convert_expr_to_smt.cpp

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -327,6 +327,51 @@ TEST_CASE(
327327
}
328328
}
329329

330+
TEST_CASE(
331+
"expr to smt conversion for relational operators as applied to pointers",
332+
"[core][smt2_incremental]")
333+
{
334+
auto test = expr_to_smt_conversion_test_environmentt::make(test_archt::i386);
335+
// Pointer variables, used for comparisons
336+
const std::size_t pointer_width = 32;
337+
const auto pointer_type = pointer_typet(signedbv_typet{32}, pointer_width);
338+
const symbol_exprt pointer_a("a", pointer_type);
339+
const symbol_exprt pointer_b("b", pointer_type);
340+
// SMT terms needed for pointer comparisons
341+
const smt_termt smt_term_a =
342+
smt_identifier_termt{"a", smt_bit_vector_sortt{pointer_width}};
343+
const smt_termt smt_term_b =
344+
smt_identifier_termt{"b", smt_bit_vector_sortt{pointer_width}};
345+
346+
SECTION("Greater than on pointers")
347+
{
348+
CHECK(
349+
test.convert(greater_than_exprt{pointer_a, pointer_b}) ==
350+
smt_bit_vector_theoryt::unsigned_greater_than(smt_term_a, smt_term_b));
351+
}
352+
353+
SECTION("Greater than or equal on pointer operands")
354+
{
355+
CHECK(
356+
test.convert(greater_than_or_equal_exprt{pointer_a, pointer_b}) ==
357+
smt_bit_vector_theoryt::unsigned_greater_than_or_equal(
358+
smt_term_a, smt_term_b));
359+
}
360+
SECTION("Less than on pointer operands")
361+
{
362+
CHECK(
363+
test.convert(less_than_exprt{pointer_a, pointer_b}) ==
364+
smt_bit_vector_theoryt::unsigned_less_than(smt_term_a, smt_term_b));
365+
}
366+
SECTION("Less than or equal on pointer operands")
367+
{
368+
CHECK(
369+
test.convert(less_than_or_equal_exprt{pointer_a, pointer_b}) ==
370+
smt_bit_vector_theoryt::unsigned_less_than_or_equal(
371+
smt_term_a, smt_term_b));
372+
}
373+
}
374+
330375
TEST_CASE(
331376
"expr to smt conversion for arithmetic operators",
332377
"[core][smt2_incremental]")

0 commit comments

Comments
 (0)