From 402cacb7de06d9da6ebcb4b3dc5997cce86d7cf2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20B=C3=BChler?= <david.buhler@cea.fr> Date: Sat, 3 Dec 2022 10:00:14 +0100 Subject: [PATCH] [Eva] Bitwise domain: fixes big-endian interpretation of shifts and casts. --- src/plugins/eva/values/offsm_value.ml | 109 ++++++++++++-------------- 1 file changed, 50 insertions(+), 59 deletions(-) diff --git a/src/plugins/eva/values/offsm_value.ml b/src/plugins/eva/values/offsm_value.ml index 556c2f74059..826e1e50125 100644 --- a/src/plugins/eva/values/offsm_value.ml +++ b/src/plugins/eva/values/offsm_value.ml @@ -274,71 +274,61 @@ let bitwise_and = CacheAnd.merge bitwise_and let bitwise_xor = CacheXor.merge bitwise_xor -(** Sign extension *) - -let offsm_sign_extension sign_bit size = - let i = match sign_bit with - | `Zero -> Ival.zero - | `One -> Ival.minus_one - | `ZeroOne -> Ival.(join zero minus_one) - in - let v_extend = V_Or_Uninitialized.initialized (V.inject_ival i) in - V_Offsetmap.create ~size v_extend ~size_v:size - - (** Shifts *) -type shift = SLeft of Int.t | SRight of Int.t * bool - -(* Shift implemented as an an offsetmap copy then paste. *) -let shift size o shift = - let r = default size in - match shift with - | SLeft n -> - if Int.lt n size then - let size_copy = Int.sub size n in - let data = basic_copy ~size:size_copy o in - basic_paste ~start:n ~src:data ~size_src:size_copy r - else r (* Guaranteed undefined behavior ; we don't care about the result. *) - | SRight (n, signed) -> - if Int.lt n size then - let size_copy = Int.sub size n in - let data = basic_copy ~start:n ~size:size_copy o in - let o' = basic_paste ~src:data ~size_src:size_copy r in - if signed then - let sign_bit = read_bit o (Int.pred size) in - if sign_bit <> `Zero then - (* We need to preserve the sign. Add {-1} or {0; -1} on the leftmost - bits *) - let size_ext = Int.sub size size_copy in - let ext = offsm_sign_extension sign_bit size_ext in - basic_paste ~start:size_copy ~src:ext ~size_src:size_ext o' - else - o' - else - o' - else r (* Guaranteed undefined behavior ; we don't care about the result. *) +type shift_direction = Left | Right +(* The value of the sign bit, expressed as a cvalue. *) +let sign_bit size offsm = + let sign_bit = + if Cil.theMachine.theMachine.little_endian + then Int.pred size + else Int.zero + in + let sign_v = basic_find ~start:sign_bit ~size:Integer.one offsm in + Cvalue.V_Or_Uninitialized.get_v sign_v + +(* Creates an offsetmap of size [size] filled with the sign bit of [offsm]. *) +let signed_default ~size ~size_offsm offsm = + let default_v = sign_bit size_offsm offsm in + let v = V_Or_Uninitialized.initialized default_v in + V_Offsetmap.create ~size ~size_v:Int.one v + +let shift ~size ~signed offsm shift_direction n = + let result = + if signed && shift_direction = Right + then signed_default ~size ~size_offsm:size offsm + else default size + in + if Int.ge n size + then result (* Undefined behavior: we don't care about the result. *) + else + let size_copy = Int.sub size n in + let little_endian = Cil.theMachine.theMachine.little_endian in + let start_copy, start_paste = + if (shift_direction = Left) = little_endian + then Int.zero, n + else n, Int.zero + in + let data = basic_copy ~start:start_copy ~size:size_copy offsm in + basic_paste ~start:start_paste ~src:data ~size_src:size_copy result (** Casts *) -let cast ~old_size ~new_size ~signed o = - if Int.equal old_size new_size then o +let cast ~old_size ~new_size ~signed offsm = + let little_endian = Cil.theMachine.theMachine.little_endian in + if Int.equal old_size new_size then offsm else if Int.lt new_size old_size then (* Truncation *) - basic_copy ~size:new_size o + let start = if little_endian then Int.zero else Int.sub old_size new_size in + basic_copy ~start ~size:new_size offsm else (* Extension *) - if signed then (* need to check the sign and extend accordingly *) - (* Original bits, extended with zeros *) - let r = default new_size in - let r_o = basic_paste ~src:o ~size_src:old_size r in - (* Bits of sign extension *) - let sign_bit = read_bit o (Int.pred old_size) in - let size_ext = Int.sub new_size old_size in - let ext = offsm_sign_extension sign_bit size_ext in - basic_paste ~start:old_size ~src:ext ~size_src:size_ext r_o - else - let r = default new_size in - basic_paste ~src:o ~size_src:old_size r + let result = + if signed + then signed_default ~size:new_size ~size_offsm:old_size offsm + else default new_size + in + let start = if little_endian then Int.zero else Int.sub new_size old_size in + basic_paste ~start ~src:offsm ~size_src:old_size result (** Binary not *) @@ -539,9 +529,10 @@ module CvalueOffsm : Abstract.Value.Internal with type t = V.t * offsm_or_top try let i = V.project_ival v_r in let i = Ival.project_int i in + let size = size typ in let signed = Bit_utils.is_signed_int_enum_pointer typ in - let shiftn = if op = Shiftlt then SLeft i else SRight (i, signed) in - let o = shift (size typ) (to_offsm typ l) shiftn in + let dir = if op = Shiftlt then Left else Right in + let o = shift ~size ~signed (to_offsm typ l) dir i in Main_values.CVal.forward_binop typ op v_l v_r >>-: fun v -> v, O o with V.Not_based_on_null | Ival.Not_Singleton_Int -> -- GitLab