diff --git a/src/kernel_services/plugin_entry_points/db.ml b/src/kernel_services/plugin_entry_points/db.ml index 2453bded6360dc01a4109b3724d32b37fb135586..9d0a42e6ebda2f54c326da5882d51ae0154901ce 100644 --- a/src/kernel_services/plugin_entry_points/db.ml +++ b/src/kernel_services/plugin_entry_points/db.ml @@ -1021,6 +1021,7 @@ module RteGen = struct let get_pointer_downcast_status = mk_fun "RteGen.get_pointer_downcast_status" let get_float_to_int_status = mk_fun "RteGen.get_float_to_int_status" let get_finite_float_status = mk_fun "RteGen.get_finite_float_status" + let get_pointer_value_status = mk_fun "RteGen.get_pointer_value_status" let get_bool_value_status = mk_fun "RteGen.get_bool_value_status" end diff --git a/src/kernel_services/plugin_entry_points/db.mli b/src/kernel_services/plugin_entry_points/db.mli index a54ae74932d0942ba3df7aa1508675e0dda9c5a8..43b89f26ecf759389eb744dbe06b00e7a871b97f 100644 --- a/src/kernel_services/plugin_entry_points/db.mli +++ b/src/kernel_services/plugin_entry_points/db.mli @@ -903,6 +903,7 @@ module RteGen : sig val get_pointer_downcast_status : (unit -> status_accessor) ref val get_float_to_int_status : (unit -> status_accessor) ref val get_finite_float_status : (unit -> status_accessor) ref + val get_pointer_value_status : (unit -> status_accessor) ref val get_bool_value_status : (unit -> status_accessor) ref end diff --git a/src/plugins/rte/flags.ml b/src/plugins/rte/flags.ml index 7d17b15a3a9577579b409c2396f89060023f48a8..fea846e8b1989abd969c2b70363767b2379fd136 100644 --- a/src/plugins/rte/flags.ml +++ b/src/plugins/rte/flags.ml @@ -40,6 +40,7 @@ type t = { float_to_int: bool; finite_float: bool; pointer_call: bool; + pointer_value: bool; bool_value: bool; } @@ -59,6 +60,7 @@ let all = { float_to_int = true; finite_float = true; pointer_call = true; + pointer_value = true; bool_value = true; } @@ -78,6 +80,7 @@ let none = { float_to_int = false; finite_float = false; pointer_call = false; + pointer_value = false; bool_value = false; } @@ -102,6 +105,7 @@ let default ?float_to_int ?finite_float ?pointer_call + ?pointer_value ?bool_value () = { @@ -120,6 +124,7 @@ let default float_to_int = option Options.DoFloatToInt.get float_to_int ; finite_float = option (fun () -> Kernel.SpecialFloat.get () <> "none") finite_float ; pointer_call = option Options.DoPointerCall.get pointer_call ; + pointer_value = option Kernel.InvalidPointer.get pointer_value; bool_value = option Kernel.InvalidBool.get bool_value ; } diff --git a/src/plugins/rte/flags.mli b/src/plugins/rte/flags.mli index 3ea19d53f367e367c1a0e414871403d5bef54d1b..fc1a7b6f4d7cf274a86954c51a4cf4c900b0e7e5 100644 --- a/src/plugins/rte/flags.mli +++ b/src/plugins/rte/flags.mli @@ -42,6 +42,7 @@ type t = { float_to_int: bool; finite_float: bool; pointer_call: bool; + pointer_value: bool; bool_value: bool; } @@ -62,6 +63,7 @@ val default : ?float_to_int:bool -> ?finite_float:bool -> ?pointer_call:bool -> + ?pointer_value:bool -> ?bool_value:bool -> unit -> t diff --git a/src/plugins/rte/generator.ml b/src/plugins/rte/generator.ml index 8c8e697d4dcf846db06cb7c6062fc9b5fd9847a1..4c84ce9c126543da6535ca91d6b455e1624eb830 100644 --- a/src/plugins/rte/generator.ml +++ b/src/plugins/rte/generator.ml @@ -83,6 +83,14 @@ module Mem_access = let additional_parameters = [ Kernel.SafeArrays.parameter ] end) +module Pointer_value = + Make + (struct + let name = "pointer_value" + let parameter = Kernel.InvalidPointer.parameter + let additional_parameters = [] + end) + module Pointer_call = Make (struct diff --git a/src/plugins/rte/generator.mli b/src/plugins/rte/generator.mli index 1518a0acc67f22908320d834bb54b1f99c22eec4..0116b9d7698346c6a8811defdb08ceb55039adb7 100644 --- a/src/plugins/rte/generator.mli +++ b/src/plugins/rte/generator.mli @@ -30,6 +30,7 @@ end module Initialized: S module Mem_access: S +module Pointer_value: S module Pointer_call: S module Div_mod: S module Shift: S diff --git a/src/plugins/rte/register.ml b/src/plugins/rte/register.ml index 8b5afe27c054f83e273da685237efc10d5899d2d..a3f3df56f048d270e2bdb4ede38ae8cac65c1646 100644 --- a/src/plugins/rte/register.ml +++ b/src/plugins/rte/register.ml @@ -96,6 +96,7 @@ let () = nojournal_register get_pointer_downcast_status Pointer_downcast.accessor; nojournal_register get_float_to_int_status Float_to_int.accessor; nojournal_register get_finite_float_status Finite_float.accessor; + nojournal_register get_pointer_value_status Pointer_value.accessor; nojournal_register get_bool_value_status Bool_value.accessor ; nojournal_register get_all_status all_statuses; ;; diff --git a/src/plugins/rte/rte.ml b/src/plugins/rte/rte.ml index 467d65f1ffd919d19c5ef4f4784c8cef98e9b490..16845eed8d574889527464bbff6a589dcd4c9b0b 100644 --- a/src/plugins/rte/rte.ml +++ b/src/plugins/rte/rte.ml @@ -451,6 +451,24 @@ let finite_float_assertion ~remove_trivial:_ ~on_alarm (fkind, exp) = let pointer_call ~remove_trivial:_ ~on_alarm (e, args) = on_alarm ~invalid:false (Alarms.Function_pointer (e, Some args)) +let is_safe_pointer_value = function + | Lval (Var vi, offset) -> + (* Reading a pointer variable must emit an alarm if an invalid pointer value + could have been written without previous alarm, through: + - an union type, in which case [offset] is not NoOffset; + - an untyped write, in which case the address of [vi] is taken. *) + not vi.vaddrof && offset = NoOffset + | AddrOf (_, NoOffset) | StartOf (_, NoOffset) -> true + | CastE (_typ, e) -> + (* 0 can always be converted into a NULL pointer. *) + let v = get_expr_val e in + Extlib.may_map ~dft:false Integer.(equal zero) v + | _ -> false + +let pointer_value ~remove_trivial ~on_alarm expr = + if not (remove_trivial && is_safe_pointer_value expr.enode) + then on_alarm ~invalid:false (Alarms.Invalid_pointer expr) + let bool_value ~remove_trivial ~on_alarm lv = match remove_trivial, lv with | true, (Var vi, NoOffset) diff --git a/src/plugins/rte/rte.mli b/src/plugins/rte/rte.mli index 7c787c279a81d18e1eae71b1683d411036e8874d..c7a292c92cad6f05ceb1b015448c85c4ccbf9e26 100644 --- a/src/plugins/rte/rte.mli +++ b/src/plugins/rte/rte.mli @@ -44,6 +44,7 @@ val downcast_assertion: (typ * exp) alarm_gen val float_to_int_assertion: (typ * exp) alarm_gen val finite_float_assertion: (fkind * exp) alarm_gen val pointer_call: (exp * exp list) alarm_gen +val pointer_value: exp alarm_gen val bool_value: lval alarm_gen (* diff --git a/src/plugins/rte/visit.ml b/src/plugins/rte/visit.ml index 61dafe98471f4ed4f86338f62319019ef54b5c44..36c092b8a7ca1adc1f69f5179f552820a8e5644d 100644 --- a/src/plugins/rte/visit.ml +++ b/src/plugins/rte/visit.ml @@ -99,6 +99,9 @@ class annot_visitor kf flags on_alarm = object (self) method private do_pointer_call () = flags.Flags.pointer_call && not (Generator.Pointer_call.is_computed kf) + method private do_pointer_value () = + flags.Flags.pointer_value && not (Generator.Pointer_value.is_computed kf) + method private do_bool_value () = flags.Flags.bool_value && not (Generator.Bool_value.is_computed kf) @@ -275,6 +278,9 @@ class annot_visitor kf flags on_alarm = object (self) self#generate_assertion Rte.finite_float_assertion (fkind,exp) | _ -> ()) + | BinOp((PlusPI | MinusPI), _, _, _) when self#do_pointer_value () -> + self#generate_assertion Rte.pointer_value exp + | UnOp(Neg, exp, ty) -> (* Note: if unary minus on unsigned integer is to be understood as "subtracting the promoted value from the largest value @@ -290,6 +296,8 @@ class annot_visitor kf flags on_alarm = object (self) | Lval lval -> (match Cil.(unrollType (typeOfLval lval)) with + | TPtr _ when self#do_pointer_value () -> + self#generate_assertion Rte.pointer_value exp | TInt (IBool,_) when self#do_bool_value () -> self#generate_assertion Rte.bool_value lval | _ -> ()); @@ -313,6 +321,8 @@ class annot_visitor kf flags on_alarm = object (self) (* to , from *) | TInt _, TPtr _ when self#do_pointer_downcast () -> self#generate_assertion Rte.downcast_assertion (ty, e) + | TPtr _, TInt _ when self#do_pointer_value () -> + self#generate_assertion Rte.pointer_value exp | TInt(kind,_), TInt (_, _) -> let signed = Cil.isSigned kind in @@ -339,8 +349,9 @@ class annot_visitor kf flags on_alarm = object (self) | FP_nan -> self#generate_assertion Rte.finite_float_assertion (fkind,exp) end - | StartOf _ - | AddrOf _ + | StartOf _ | AddrOf _ -> + if self#do_pointer_value () + then self#generate_assertion Rte.pointer_value exp | Info _ | UnOp _ | Const _ @@ -451,6 +462,7 @@ let annotate ?flags kf = let open Flags in if comp Initialized.accessor flags.initialized ||| comp Mem_access.accessor flags.mem_access ||| + comp Pointer_value.accessor flags.pointer_value ||| comp Pointer_call.accessor flags.pointer_call ||| comp Div_mod.accessor flags.div_mod ||| comp Shift.accessor flags.shift ||| diff --git a/tests/rte/oracle/twofunc.res.oracle b/tests/rte/oracle/twofunc.res.oracle index 5d0a80d5f3847f4511ec8b4104f59014643e42ae..834e89b4e6941e3bb468d33795f53da68909b733 100644 --- a/tests/rte/oracle/twofunc.res.oracle +++ b/tests/rte/oracle/twofunc.res.oracle @@ -143,6 +143,7 @@ int main(void) [kernel] - shift_value_out_of_bounds = true [kernel] - division_by_zero = true [kernel] - pointer_call = true +[kernel] - pointer_value = false [kernel] - mem_access = true [kernel] - initialized = false [kernel] kf = main @@ -159,6 +160,7 @@ int main(void) [kernel] - shift_value_out_of_bounds = true [kernel] - division_by_zero = true [kernel] - pointer_call = true +[kernel] - pointer_value = false [kernel] - mem_access = true [kernel] - initialized = false [kernel] ================================ @@ -237,6 +239,7 @@ int main(void) [kernel] - shift_value_out_of_bounds = true [kernel] - division_by_zero = true [kernel] - pointer_call = true +[kernel] - pointer_value = false [kernel] - mem_access = true [kernel] - initialized = false [kernel] kf = main @@ -253,6 +256,7 @@ int main(void) [kernel] - shift_value_out_of_bounds = true [kernel] - division_by_zero = true [kernel] - pointer_call = true +[kernel] - pointer_value = false [kernel] - mem_access = true [kernel] - initialized = false [kernel] ================================