@@ -998,6 +998,32 @@ void SplitDBM::apply(arith_binop_t op, variable_t x, variable_t y, variable_t z,
998
998
normalize ();
999
999
}
1000
1000
1001
+ // As defined in the BPF ISA specification, the immediate value of an unsigned modulo and division is treated
1002
+ // differently depending on the width:
1003
+ // * for 32 bit, as a 32-bit unsigned integer
1004
+ // * for 64 bit, as a 32-bit (not 64 bit) signed integer
1005
+ number_t read_imm_for_udiv_or_umod (const number_t & imm, int width) {
1006
+ assert (width == 32 || width == 64 );
1007
+ if (width == 32 ) {
1008
+ return number_t {imm.cast_to <uint32_t >()};
1009
+ } else {
1010
+ return number_t {imm.cast_to <int32_t >()};
1011
+ }
1012
+ }
1013
+
1014
+ // As defined in the BPF ISA specification, the immediate value of a signed modulo and division is treated
1015
+ // differently depending on the width:
1016
+ // * for 32 bit, as a 32-bit signed integer
1017
+ // * for 64 bit, as a 64-bit signed integer
1018
+ number_t read_imm_for_sdiv_or_smod (const number_t & imm, int width) {
1019
+ assert (width == 32 || width == 64 );
1020
+ if (width == 32 ) {
1021
+ return number_t {imm.cast_to <int32_t >()};
1022
+ } else {
1023
+ return number_t {imm.cast_to <int64_t >()};
1024
+ }
1025
+ }
1026
+
1001
1027
void SplitDBM::apply (arith_binop_t op, variable_t x, variable_t y, const number_t & k, int finite_width) {
1002
1028
CrabStats::count (" SplitDBM.count.apply" );
1003
1029
ScopedCrabStats __st__ (" SplitDBM.apply" );
@@ -1007,31 +1033,10 @@ void SplitDBM::apply(arith_binop_t op, variable_t x, variable_t y, const number_
1007
1033
case arith_binop_t ::SUB: assign (x, linear_expression_t (y).subtract (k)); break ;
1008
1034
case arith_binop_t ::MUL: assign (x, linear_expression_t (k, y)); break ;
1009
1035
// For the rest of operations, we fall back on intervals.
1010
- case arith_binop_t ::SDIV: set (x, get_interval (y, finite_width).SDiv (interval_t (k))); break ;
1011
- case arith_binop_t ::UDIV: {
1012
- if (finite_width == 32 ) {
1013
- // As defined in the BPF ISA specification, for 32 bit unsigned division the immediate value is
1014
- // treated as a 32-bit unsigned integer, so we need to cast it to uint32_t.
1015
- set (x, get_interval (y, finite_width).UDiv (interval_t (k.cast_to <uint32_t >())));
1016
- } else {
1017
- // As defined in the BPF ISA specification, for 64 bit unsigned division the immediate value is
1018
- // treated as a 32-bit signed integer, so we need to cast it to int32_t.
1019
- set (x, get_interval (y, finite_width).UDiv (interval_t (k.cast_to <int32_t >())));
1020
- }
1021
- break ;
1022
- }
1023
- case arith_binop_t ::SREM: set (x, get_interval (y, finite_width).SRem (interval_t (k))); break ;
1024
- case arith_binop_t ::UREM:
1025
- if (finite_width == 32 ) {
1026
- // As defined in the BPF ISA specification, for 32 bit unsigned modulo the immediate value is
1027
- // treated as a 32-bit unsigned integer, so we need to cast it to uint32_t.
1028
- set (x, get_interval (y, finite_width).URem (interval_t (k.cast_to <uint32_t >())));
1029
- } else {
1030
- // As defined in the BPF ISA specification, for 64 bit unsigned modulo the immediate value is
1031
- // treated as a 32-bit signed integer, so we need to cast it to int32_t.
1032
- set (x, get_interval (y, finite_width).URem (interval_t (k.cast_to <int32_t >())));
1033
- }
1034
- break ;
1036
+ case arith_binop_t ::SDIV: set (x, get_interval (y, finite_width).SDiv (interval_t (read_imm_for_sdiv_or_smod (k, finite_width)))); break ;
1037
+ case arith_binop_t ::UDIV: set (x, get_interval (y, finite_width).UDiv (interval_t (read_imm_for_udiv_or_umod (k, finite_width)))); break ;
1038
+ case arith_binop_t ::SREM: set (x, get_interval (y, finite_width).SRem (interval_t (read_imm_for_sdiv_or_smod (k, finite_width)))); break ;
1039
+ case arith_binop_t ::UREM: set (x, get_interval (y, finite_width).URem (interval_t (read_imm_for_udiv_or_umod (k, finite_width)))); break ;
1035
1040
default : CRAB_ERROR (" DBM: unreachable" );
1036
1041
}
1037
1042
normalize ();
0 commit comments