let get_bitwise_lshift_unsigned_assertion
~simplify_constants:simplify_constants
~warning:warning
exp loperand roperand =
(* result should be representable in result type *)
let t = Cil.typeOf exp in
let size = bitsSizeOf t in
let () =
if not (size <= 32)
(* 64 bits size "requires" representing a constant
which does not hold in a Cil constant
(as long as it remains an int64 and not a big integer) *)
then rte_warn "problem with bitsSize of %a: not treated" d_exp exp ;
in let maxValResult = (* compute greatest reprensentable "size bits" unsigned integer *)
get_unsigned_max size
in let ov_assertion () =
let term = translate_C_expr_to_term ~cast:false exp
in (* unsigned result is representable in result type if loperand times 2^roperand
(where loperand and roperand are nonnegative),
which should be equal to term (obtained with a shift),
is less than the maximal value for the result type *)
(* no cast to int since we check "true result" which is an integer*)
Logic_const.prel (Rle, term, Cil.lconstant maxValResult)
in let problem_with_ov_assertion () =
if simplify_constants then (
match get_expr_val loperand, get_expr_val roperand with
| None,_
| _, None -> (false,false)
| Some lval64, Some rval64 ->
(* both operands are constant:
check result is representable in result type *)
let result_true_val =
Int.shift_left (Int.of_int64 lval64) (Int.of_int64 rval64)
in
if Int.compare result_true_val (Int.of_int64 maxValResult) > 0
then (true,false) (* constant operators and assertion does not hold *)
else (true,true) (* constant operators and assertion holds *)
) else (false,false)
in
match problem_with_ov_assertion () with
| (true,false) ->
let assertion = ov_assertion () in
if warning then (
rte_warn
"shift assert broken (unsigned overflow): %a" d_predicate_named assertion
)
;
[ (assertion, Some (make_check_false())) ]
| (true,true) -> [ ]
| (false,_) -> [ (ov_assertion (), None) ]