let get_signed_div_assertion
~simplify_constants:simplify_constants
~warning:warning
dividend_expr divisor_expr =
(* Signed division: overflow occurs when dividend is equal to the
the minimum (negative) value for the signed integer type,
and divisor is equal to -1. Under the hypothesis (cf value analysis) that integers are
represented in two's completement.
Nothing done for modulo (the result of TYPE_MIN % -1 is 0, which does not overflow)
Still it may be dangerous on a number of compilers / architectures
(modulo may be performed in parallel with division)
*)
let t = Cil.typeOf divisor_expr in
let size = bitsSizeOf t
in
(* check dividend_expr / divisor_expr : if constants ... *)
if (size > 64) then (
(* should never happen *)
rte_warn fmt_warn_bitsize_over_64 d_exp divisor_expr ;
[]
)
else
let badValDividend =
(* compute smallest representable "size bits" (signed) integer *)
min_signed_number size
(*
let min64 = Int64.min_int
and shiftright_value = 64 - size
in if shiftright_value > 0 then Int64.shift_right min64 shiftright_value else min64
*)
and badValDivisor = My_bigint.minus_one
in let assert_for_divisor () =
Logic_const.prel
(Req, translate_C_expr_to_term divisor_expr, Cil.lconstant badValDivisor)
and assert_for_dividend () =
Logic_const.prel
(Req,
translate_C_expr_to_term dividend_expr, Cil.lconstant badValDividend)
in let assert_not_both () =
Logic_const.pnot
(Logic_const.pand (assert_for_divisor (), assert_for_dividend ()))
in
if simplify_constants then (
let problem_with_divisor () =
match get_expr_val divisor_expr with
| None -> (false,false)
| Some c64 ->
if My_bigint.equal c64 badValDivisor then (true,true)
else (true,false)
and problem_with_dividend () =
match get_expr_val dividend_expr with
| None -> (false,false)
| Some c64 ->
if My_bigint.equal c64 badValDividend then (true,true)
else (true,false)
in
match problem_with_divisor (), problem_with_dividend () with
| (false,_), (false,_) ->
(* neither divisor nor dividend is constant *)
(* Printf.eprintf "neither divisor nor dividend is constant\n";
flush stderr; *)
[ assert_not_both (), None ]
| (true,true), (true,true) ->
(* divisor and dividend are constant and have both bad values *)
(* Printf.eprintf
"divisor and dividend are constant and have both bad values\n";
flush stderr ; *)
let assertion = assert_not_both ()
in
if warning then
rte_warn
fmt_signed_overflow_assert
d_predicate_named assertion ;
[ assertion, Some Property_status.False_if_reachable ]
| (true,false), _
| _ , (true,false) ->
(* one of divisor or dividend is constant and has a good value *)
[]
| (true,true), (false,_) ->
(* divisor is constant and has bad value, dividend is not
constant *)
[ Logic_const.pnot (assert_for_dividend ()),
None ]
| (false,_), (true,true) ->
(* divisor is not constant, dividend is constant and has bad
value *)
[ Logic_const.pnot (assert_for_divisor ()),
None ])
else
[ assert_not_both (), None ]