Skip to content

Commit 06c2cfd

Browse files
authored
Merge pull request #6201 from diffblue/bvXdiv_by_zero
SMT-LIB2 parser now models bit-vector division by zero correctly
2 parents 953871e + 43b2ccd commit 06c2cfd

File tree

3 files changed

+82
-27
lines changed

3 files changed

+82
-27
lines changed

regression/smt2_solver/basic-bv1/basic-bv1.smt2

Lines changed: 15 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -8,19 +8,24 @@
88
(define-fun b03 () Bool (= (bvneg #x07) #xf9)) ; unary minus
99
(define-fun b04 () Bool (= (bvmul #x07 #x03) #x15)) ; multiplication
1010
(define-fun b05 () Bool (= (bvurem #x07 #x03) #x01)) ; unsigned remainder
11-
(define-fun b06 () Bool (= (bvsrem #x07 #x03) #x01)) ; signed remainder
12-
(define-fun b07 () Bool (= (bvsmod #x07 #x03) #x01)) ; signed modulo
13-
(define-fun b08 () Bool (= (bvshl #x07 #x03) #x38)) ; shift left
14-
(define-fun b09 () Bool (= (bvlshr #xf0 #x03) #x1e)) ; unsigned (logical) shift right
15-
(define-fun b10 () Bool (= (bvashr #xf0 #x03) #xfe)) ; signed (arithmetical) shift right#x0a
11+
(define-fun b06 () Bool (= (bvurem #x07 #x00) #x07)) ; unsigned remainder (div. by zero)
12+
(define-fun b07 () Bool (= (bvudiv #x01 #x00) #xff)) ; unsigned division (div. by zero)
13+
(define-fun b08 () Bool (= (bvsrem #x07 #x03) #x01)) ; signed remainder
14+
(define-fun b09 () Bool (= (bvsrem #x07 #x00) #x07)) ; signed remainder (div. by zero)
15+
(define-fun b10 () Bool (= (bvsmod #x07 #x03) #x01)) ; signed modulo
16+
(define-fun b11 () Bool (= (bvsmod #x07 #x00) #x07)) ; signed modulo (div. by zero)
17+
(define-fun b12 () Bool (= (bvsdiv #x01 #x00) #xff)) ; signed division (div. by zero)
18+
(define-fun b13 () Bool (= (bvshl #x07 #x03) #x38)) ; shift left
19+
(define-fun b14 () Bool (= (bvlshr #xf0 #x03) #x1e)) ; unsigned (logical) shift right
20+
(define-fun b15 () Bool (= (bvashr #xf0 #x03) #xfe)) ; signed (arithmetical) shift right#x0a
1621

1722
; Multi-ary variants, where applicable
18-
(define-fun b11 () Bool (= (bvadd #x07 #x03 #x01) #x0b)) ; addition
19-
(define-fun b12 () Bool (= (bvmul #x07 #x03 #x01) #x15)) ; multiplication
23+
(define-fun b16 () Bool (= (bvadd #x07 #x03 #x01) #x0b)) ; addition
24+
(define-fun b17 () Bool (= (bvmul #x07 #x03 #x01) #x15)) ; multiplication
2025

2126
; rotation
22-
(define-fun b13 () Bool (= ((_ rotate_left 2) #xf7) #xdf)) ; rotation left
23-
(define-fun b14 () Bool (= ((_ rotate_right 2) #x07) #xc1)) ; rotation right
27+
(define-fun b18 () Bool (= ((_ rotate_left 2) #xf7) #xdf)) ; rotation left
28+
(define-fun b19 () Bool (= ((_ rotate_right 2) #x07) #xc1)) ; rotation right
2429

2530
; Bitwise Operations
2631

@@ -67,7 +72,7 @@
6772
; all must be true
6873

6974
(assert (not (and
70-
b01 b02 b03 b04 b05 b06 b07 b08 b09 b10 b11 b12 b13 b14
75+
b01 b02 b03 b04 b05 b06 b07 b08 b09 b10 b11 b12 b13 b14 b15 b16 b17 b18 b19
7176
d01
7277
power-test
7378
p1 p2 p3 p4 p5 p6 p7 p8)))

src/solvers/smt2/smt2_parser.cpp

Lines changed: 65 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -879,6 +879,64 @@ exprt smt2_parsert::function_application()
879879
UNREACHABLE;
880880
}
881881

882+
exprt smt2_parsert::bv_division(
883+
const exprt::operandst &operands,
884+
bool is_signed)
885+
{
886+
if(operands.size() != 2)
887+
throw error() << "bitvector division expects two operands";
888+
889+
// SMT-LIB2 defines the result of division by 0 to be 1....1
890+
auto divisor = symbol_exprt("divisor", operands[1].type());
891+
auto divisor_is_zero = equal_exprt(divisor, from_integer(0, divisor.type()));
892+
auto all_ones = to_unsignedbv_type(operands[0].type()).largest_expr();
893+
894+
exprt division_result;
895+
896+
if(is_signed)
897+
{
898+
auto signed_operands = cast_bv_to_signed({operands[0], divisor});
899+
division_result =
900+
cast_bv_to_unsigned(div_exprt(signed_operands[0], signed_operands[1]));
901+
}
902+
else
903+
division_result = div_exprt(operands[0], divisor);
904+
905+
return let_exprt(
906+
{divisor},
907+
{operands[1]},
908+
if_exprt(divisor_is_zero, all_ones, division_result));
909+
}
910+
911+
exprt smt2_parsert::bv_mod(const exprt::operandst &operands, bool is_signed)
912+
{
913+
if(operands.size() != 2)
914+
throw error() << "bitvector modulo expects two operands";
915+
916+
// SMT-LIB2 defines the result of "lhs modulo 0" to be "lhs"
917+
auto dividend = symbol_exprt("dividend", operands[0].type());
918+
auto divisor = symbol_exprt("divisor", operands[1].type());
919+
auto divisor_is_zero = equal_exprt(divisor, from_integer(0, divisor.type()));
920+
921+
exprt mod_result;
922+
923+
// bvurem and bvsrem match our mod_exprt.
924+
// bvsmod doesn't.
925+
if(is_signed)
926+
{
927+
auto signed_operands = cast_bv_to_signed({dividend, divisor});
928+
mod_result =
929+
cast_bv_to_unsigned(mod_exprt(signed_operands[0], signed_operands[1]));
930+
}
931+
else
932+
mod_result = mod_exprt(dividend, divisor);
933+
934+
return let_exprt(
935+
{dividend, divisor},
936+
{operands[0], operands[1]},
937+
if_exprt(divisor_is_zero, dividend, mod_result));
938+
}
939+
882940
exprt smt2_parsert::expression()
883941
{
884942
switch(next_token())
@@ -1053,27 +1111,17 @@ void smt2_parsert::setup_expressions()
10531111
return binary(ID_minus, op);
10541112
};
10551113

1056-
expressions["bvsdiv"] = [this] {
1057-
return cast_bv_to_unsigned(binary(ID_div, cast_bv_to_signed(operands())));
1058-
};
1059-
1060-
expressions["bvudiv"] = [this] { return binary(ID_div, operands()); };
1114+
expressions["bvsdiv"] = [this] { return bv_division(operands(), true); };
1115+
expressions["bvudiv"] = [this] { return bv_division(operands(), false); };
10611116
expressions["/"] = [this] { return binary(ID_div, operands()); };
10621117
expressions["div"] = [this] { return binary(ID_div, operands()); };
10631118

1064-
expressions["bvsrem"] = [this] {
1065-
// 2's complement signed remainder (sign follows dividend)
1066-
// This matches our ID_mod, and what C does since C99.
1067-
return cast_bv_to_unsigned(binary(ID_mod, cast_bv_to_signed(operands())));
1068-
};
1069-
1070-
expressions["bvsmod"] = [this] {
1071-
// 2's complement signed remainder (sign follows divisor)
1072-
// We don't have that.
1073-
return cast_bv_to_unsigned(binary(ID_mod, cast_bv_to_signed(operands())));
1074-
};
1119+
expressions["bvsrem"] = [this] { return bv_mod(operands(), true); };
1120+
expressions["bvurem"] = [this] { return bv_mod(operands(), false); };
10751121

1076-
expressions["bvurem"] = [this] { return binary(ID_mod, operands()); };
1122+
// 2's complement signed remainder (sign follows divisor)
1123+
// We don't have that.
1124+
expressions["bvsmod"] = [this] { return bv_mod(operands(), true); };
10771125

10781126
expressions["%"] = [this] { return binary(ID_mod, operands()); };
10791127

src/solvers/smt2/smt2_parser.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -162,6 +162,8 @@ class smt2_parsert
162162
exprt binary_predicate(irep_idt, const exprt::operandst &);
163163
exprt binary(irep_idt, const exprt::operandst &);
164164
exprt unary(irep_idt, const exprt::operandst &);
165+
exprt bv_division(const exprt::operandst &, bool is_signed);
166+
exprt bv_mod(const exprt::operandst &, bool is_signed);
165167

166168
std::pair<binding_exprt::variablest, exprt> binding(irep_idt);
167169
exprt lambda_expression();

0 commit comments

Comments
 (0)