Skip to content

Commit d5ff1ba

Browse files
authored
Merge pull request #6648 from NlightNFotis/smt_arithops_regression_tests
Regression tests for the SMT bitvector arithmetic operator conversion
2 parents e08c77d + b900b19 commit d5ff1ba

File tree

9 files changed

+176
-2
lines changed

9 files changed

+176
-2
lines changed
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
#include <limits.h>
2+
#include <stdlib.h>
3+
4+
int main()
5+
{
6+
int a = INT_MAX;
7+
int b = INT_MIN;
8+
9+
__CPROVER_assert(
10+
a + 1 == INT_MIN, "Wrap-around to INT_MIN when adding to INT_MAX");
11+
__CPROVER_assert(
12+
b - 1 == INT_MAX, "Wrap-around to INT_MAX when subtracting from INT_MIN");
13+
__CPROVER_assert(a - b == -1, "INT_MAX minus INT_MIN equals -1");
14+
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
CORE
2+
overflow_behaviour.c
3+
--incremental-smt2-solver 'z3 --smt2 -in' --trace
4+
\[main\.assertion\.1\] line \d+ Wrap-around to INT_MIN when adding to INT_MAX: SUCCESS
5+
\[main\.assertion\.2\] line \d+ Wrap-around to INT_MAX when subtracting from INT_MIN: SUCCESS
6+
\[main\.assertion\.3\] line \d+ INT_MAX minus INT_MIN equals -1: SUCCESS
7+
^VERIFICATION SUCCESSFUL$
8+
^EXIT=0$
9+
^SIGNAL=0$
10+
--
11+
--
12+
This test is designed to test wrap-around behaviour for boundary-values
13+
of the int domain.
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
#include <stdbool.h>
2+
3+
int main()
4+
{
5+
int x;
6+
__CPROVER_assume(x < 100);
7+
__CPROVER_assume(x > -100);
8+
bool quadratic_solved = (x + 8) * (x - 42) == 0;
9+
10+
if(x < 0)
11+
__CPROVER_assert(!quadratic_solved, "No negative solution");
12+
else
13+
__CPROVER_assert(!quadratic_solved, "No positive solution");
14+
15+
return 0;
16+
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
CORE
2+
polynomial.c
3+
--incremental-smt2-solver 'z3 --smt2 -in' --trace
4+
\[main\.assertion\.1\] line \d+ No negative solution: FAILURE
5+
\[main\.assertion\.2\] line \d+ No positive solution: FAILURE
6+
x=-8\ \(11111111 11111111 11111111 11111000\)
7+
x=42\ \(00000000 00000000 00000000 00101010\)
8+
^VERIFICATION FAILED$
9+
^EXIT=10$
10+
^SIGNAL=0$
11+
--
12+
--
13+
This is an end-to-end test making sure that CBMC has encoded
14+
the problem and sent it to the SMT solver, and we manage to
15+
get the solutions to the polynomial back through the trace.
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
#include <stdlib.h>
2+
3+
int main()
4+
{
5+
int a;
6+
__CPROVER_assume(a < 100);
7+
__CPROVER_assume(a > -100);
8+
__CPROVER_assume(a != 0);
9+
10+
// Simple algebraic identities - expected to drive the SMT backend
11+
__CPROVER_assert(a + a == a * 2, "a plus a always equals two times a");
12+
__CPROVER_assert(a - a == 0, "a minus a always equals 0");
13+
__CPROVER_assert(a + -a == 0, "a plus its additive inverse equals 0");
14+
__CPROVER_assert(
15+
a - -a == 2 * a, "a minus its additive inverse equals two times a");
16+
__CPROVER_assert((a * a) / a == a, "a squared divided by a equals a");
17+
__CPROVER_assert((2 * a) / a == 2, "two times a divided by a equals two");
18+
__CPROVER_assert(a % a == 0, "a mod itself equals 0");
19+
20+
// Same round of tests, but for a type of different size
21+
long long int b;
22+
__CPROVER_assume(b < 100ll);
23+
__CPROVER_assume(b > -100ll);
24+
__CPROVER_assume(b != 0ll);
25+
26+
__CPROVER_assert(b + b == b * 2ll, "b plus b always equals two times b");
27+
__CPROVER_assert(b - b == 0ll, "b minus b always equals 0");
28+
__CPROVER_assert(b + -b == 0ll, "b plus its additive inverse equals 0");
29+
__CPROVER_assert(
30+
b - -b == 2ll * b, "b minus its additive inverse equals two times b");
31+
__CPROVER_assert((b * b) / b == b, "b squared divided by b equals b");
32+
__CPROVER_assert((2ll * b) / b == 2ll, "two times b divided by b equals two");
33+
__CPROVER_assert(b % b == 0ll, "b mod itself equals 0");
34+
}
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
CORE
2+
simple_equation.c
3+
--incremental-smt2-solver 'z3 --smt2 -in' --trace
4+
\[main\.assertion\.1\] line \d+ a plus a always equals two times a: SUCCESS
5+
\[main\.assertion\.2\] line \d+ a minus a always equals 0: SUCCESS
6+
\[main\.assertion\.3\] line \d+ a plus its additive inverse equals 0: SUCCESS
7+
\[main\.assertion\.4\] line \d+ a minus its additive inverse equals two times a: SUCCESS
8+
\[main\.assertion\.5\] line \d+ a squared divided by a equals a: SUCCESS
9+
\[main\.assertion\.6\] line \d+ two times a divided by a equals two: SUCCESS
10+
\[main\.assertion\.7\] line \d+ a mod itself equals 0: SUCCESS
11+
\[main\.assertion\.8\] line \d+ b plus b always equals two times b: SUCCESS
12+
\[main\.assertion\.9\] line \d+ b minus b always equals 0: SUCCESS
13+
\[main\.assertion\.10\] line \d+ b plus its additive inverse equals 0: SUCCESS
14+
\[main\.assertion\.11\] line \d+ b minus its additive inverse equals two times b: SUCCESS
15+
\[main\.assertion\.12\] line \d+ b squared divided by b equals b: SUCCESS
16+
\[main\.assertion\.13\] line \d+ two times b divided by b equals two: SUCCESS
17+
\[main\.assertion\.14\] line \d+ b mod itself equals 0: SUCCESS
18+
^VERIFICATION SUCCESSFUL$
19+
^EXIT=0$
20+
^SIGNAL=0$
21+
--
22+
--
23+
This is a simple test that's trying to verify that some simple algebraic
24+
identities hold for all values insider an integral interval. This is expected
25+
to work as an end-to-end example driving the all of the conversion function
26+
for bitvector arithmetic in the new SMT backend, getting us to the point of
27+
a full verification run producing a result.
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
int main()
2+
{
3+
unsigned int a;
4+
unsigned int b = 12;
5+
__CPROVER_assume(a > 15);
6+
7+
// expected to fail by assigning a = 4294967284u in the trace
8+
// and wrapping around to 0, which results in 0 > 27.
9+
__CPROVER_assert(a + b > 27, "a plus b should be more than 27");
10+
// expected to fail by assigning a = 2147483648u in the trace
11+
// and evaluating to 2147483660 > 27, which is true.
12+
__CPROVER_assert(!(a + b > 27), "a plus b should be more than 27");
13+
14+
// Same round of tests but for unsigned long long.
15+
unsigned long long int c;
16+
unsigned long long int d = 12llu;
17+
__CPROVER_assume(c > 15llu);
18+
19+
__CPROVER_assert(c + d > 27, "c plus d should be more than 27");
20+
__CPROVER_assert(!(c + d > 27), "c plus d should be more than 27");
21+
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
CORE
2+
unsigned_behaviour.c
3+
--incremental-smt2-solver 'z3 --smt2 -in' --trace
4+
\[main\.assertion\.1\] line \d+ a plus b should be more than 27: FAILURE
5+
\[main\.assertion\.2\] line \d+ a plus b should be more than 27: FAILURE
6+
\[main\.assertion\.3\] line \d+ c plus d should be more than 27: FAILURE
7+
\[main\.assertion\.4\] line \d+ c plus d should be more than 27: FAILURE
8+
a=\d+(u|ul)?
9+
c=\d+(u|ul)?
10+
^VERIFICATION FAILED$
11+
^EXIT=10$
12+
^SIGNAL=0$
13+
--
14+
--
15+
This test checks for the correct behaviour of unsigned integers around
16+
boundary values.

src/util/piped_process.cpp

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -348,12 +348,30 @@ piped_processt::send_responset piped_processt::send(const std::string &message)
348348
#ifdef _WIN32
349349
const auto message_size = narrow<DWORD>(message.size());
350350
DWORD bytes_written = 0;
351-
if(!WriteFile(
352-
child_std_IN_Wr, message.c_str(), message_size, &bytes_written, NULL))
351+
const auto write_file = [&]() {
352+
return WriteFile(
353+
child_std_IN_Wr, message.c_str(), message_size, &bytes_written, NULL);
354+
};
355+
if(!write_file())
353356
{
354357
// Error handling with GetLastError ?
355358
return send_responset::FAILED;
356359
}
360+
// `WriteFile` can return a success status but write 0 bytes if we write
361+
// messages quickly enough. This problem has been observed when using a
362+
// release build, but resolved when using a debug build or `--verbosity 10`.
363+
// Presumably this happens if cbmc gets too far ahead of the sub process.
364+
// Flushing the buffer and retrying should then succeed to write the message
365+
// in this case.
366+
if(bytes_written == 0)
367+
{
368+
FlushFileBuffers(child_std_IN_Wr);
369+
if(!write_file())
370+
{
371+
// Error handling with GetLastError ?
372+
return send_responset::FAILED;
373+
}
374+
}
357375
INVARIANT(
358376
message_size == bytes_written,
359377
"Number of bytes written to sub process must match message size.");

0 commit comments

Comments
 (0)