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 divison)
*)
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 "bitsSize of %a > 64: not treated" d_exp divisor_expr ;
[]
)
else
let badValDividend =
(* compute smallest representable "size bits" (signed) integer *)
get_signed_min 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 = Int64.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 Int64.compare c64 badValDivisor = 0
then (true,true)
else (true,false)
and problem_with_dividend () =
match get_expr_val dividend_expr with
| None -> (false,false)
| Some c64 ->
if Int64.compare c64 badValDividend = 0
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
"signed overflow assert broken: %a" d_predicate_named assertion
;
[ (assertion, Some (make_check_false ())) ]
| (true,false), _
| _ , (true,false) ->
(* one of divisor or dividend is constant and has a good value *)
(* Printf.eprintf
"one of divisor or dividend is constant and has a good value\n";
flush stderr; *)
[]
| (true,true), (false,_) ->
(* divisor is constant and has bad value, dividend is not constant *)
(* Printf.eprintf
"divisor is constant and has bad value, dividend is not constant\n";
flush stderr; *)
[ (Logic_const.pnot (assert_for_dividend ()), None) ]
| (false,_), (true,true) ->
(* divisor is not constant, dividend is constant and has bad value *)
(* Printf.eprintf
"divisor is not constant, dividend is constant and has bad value\n";
flush stderr; *)
[ (Logic_const.pnot (assert_for_divisor ()), None) ]
) else [ (assert_not_both (), None) ]