[Uninit][10/13] Other non-functional changes

Reviewed By: ddino

Differential Revision: D10250252

fbshipit-source-id: d0574daf1
master
Mehdi Bouaziz 6 years ago committed by Facebook Github Bot
parent 8360465284
commit 5e2d5c6f6b

@ -102,8 +102,7 @@ module TransferFunctions (CFG : ProcCfg.S) = struct
let report_on_function_params pdesc tenv maybe_uninit_vars actuals loc summary callee_formals_opt let report_on_function_params pdesc tenv maybe_uninit_vars actuals loc summary callee_formals_opt
= =
List.iteri List.iteri actuals ~f:(fun idx e ->
~f:(fun idx e ->
match e with match e with
| HilExp.AccessExpression access_expr -> | HilExp.AccessExpression access_expr ->
let _, t = AccessExpression.get_base access_expr in let _, t = AccessExpression.get_base access_expr in
@ -114,10 +113,8 @@ module TransferFunctions (CFG : ProcCfg.S) = struct
(Option.exists callee_formals_opt ~f:(fun callee_formals -> (Option.exists callee_formals_opt ~f:(fun callee_formals ->
is_struct_field_passed_by_ref callee_formals t access_expr idx )) is_struct_field_passed_by_ref callee_formals t access_expr idx ))
then report_intra access_expr loc summary then report_intra access_expr loc summary
else ()
| _ -> | _ ->
() ) () )
actuals
let is_dummy_constructor_of_a_struct call = let is_dummy_constructor_of_a_struct call =
@ -157,20 +154,20 @@ module TransferFunctions (CFG : ProcCfg.S) = struct
else None else None
let remove_initialized_params pdesc call acc idx access_expr remove_fields = let remove_initialized_params pdesc call maybe_uninit_vars idx access_expr remove_fields =
match Payload.read pdesc call with match Payload.read pdesc call with
| Some {pre= initialized_formal_params; post= _} -> ( | Some {pre= init_formals; post= _} -> (
match init_nth_actual_param call idx initialized_formal_params with match init_nth_actual_param call idx init_formals with
| Some nth_formal -> | Some var_formal ->
let acc' = MaybeUninitVars.remove access_expr acc in let maybe_uninit_vars = MaybeUninitVars.remove access_expr maybe_uninit_vars in
let base = AccessExpression.get_base access_expr in
if remove_fields then if remove_fields then
MaybeUninitVars.remove_init_fields base nth_formal acc' initialized_formal_params let base = AccessExpression.get_base access_expr in
else acc' MaybeUninitVars.remove_init_fields base var_formal maybe_uninit_vars init_formals
else maybe_uninit_vars
| _ -> | _ ->
acc ) maybe_uninit_vars )
| _ -> | _ ->
acc maybe_uninit_vars
(* true if a function initializes at least a param or a field of a struct param *) (* true if a function initializes at least a param or a field of a struct param *)
@ -214,14 +211,14 @@ module TransferFunctions (CFG : ProcCfg.S) = struct
check_hil_expr ~loc rhs_expr check_hil_expr ~loc rhs_expr
| _ -> | _ ->
() ) ; () ) ;
let maybe_uninit_vars' = MaybeUninitVars.remove lhs_access_expr astate.maybe_uninit_vars in let maybe_uninit_vars = MaybeUninitVars.remove lhs_access_expr astate.maybe_uninit_vars in
let maybe_uninit_vars = let maybe_uninit_vars =
if AccessExpression.is_base lhs_access_expr then if AccessExpression.is_base lhs_access_expr then
(* if we assign to the root of a struct then we need to remove all the fields *) (* if we assign to the root of a struct then we need to remove all the fields *)
let lhs_base = AccessExpression.get_base lhs_access_expr in let lhs_base = AccessExpression.get_base lhs_access_expr in
MaybeUninitVars.remove_all_fields tenv lhs_base maybe_uninit_vars' MaybeUninitVars.remove_all_fields tenv lhs_base maybe_uninit_vars
|> MaybeUninitVars.remove_dereference_access lhs_base |> MaybeUninitVars.remove_dereference_access lhs_base
else maybe_uninit_vars' else maybe_uninit_vars
in in
let prepost = update_prepost lhs_access_expr rhs_expr in let prepost = update_prepost lhs_access_expr rhs_expr in
{astate with maybe_uninit_vars; prepost} {astate with maybe_uninit_vars; prepost}
@ -234,17 +231,24 @@ module TransferFunctions (CFG : ProcCfg.S) = struct
correctly all fields when there is an implementation of the constructor that initilizes at least one correctly all fields when there is an implementation of the constructor that initilizes at least one
field. If there is no explicit implementation we cannot assume fields are initialized *) field. If there is no explicit implementation we cannot assume fields are initialized *)
if function_initializes_some_formal_params pdesc call then if function_initializes_some_formal_params pdesc call then
let maybe_uninit_vars' = let maybe_uninit_vars =
(* in HIL/SIL the default constructor has only one param: the struct *) (* in HIL/SIL the default constructor has only one param: the struct *)
MaybeUninitVars.remove_all_fields tenv base astate.maybe_uninit_vars MaybeUninitVars.remove_all_fields tenv base astate.maybe_uninit_vars
in in
{astate with maybe_uninit_vars= maybe_uninit_vars'} {astate with maybe_uninit_vars}
else astate else astate
| Call (_, call, actuals, _, loc) -> | Call (_, call, actuals, _, loc) ->
(* in case of intraprocedural only analysis we assume that parameters passed by reference (* in case of intraprocedural only analysis we assume that parameters passed by reference
to a function will be initialized inside that function *) to a function will be initialized inside that function *)
let pname_opt = match call with Direct pname -> Some pname | Indirect _ -> None in let pname_opt = match call with Direct pname -> Some pname | Indirect _ -> None in
let callee_formals_opt = Option.bind pname_opt ~f:get_formals in let callee_formals_opt = Option.bind pname_opt ~f:get_formals in
let is_initializing_all_args =
match call with
| Direct pname ->
Models.is_initializing_all_args pname
| Indirect _ ->
false
in
let maybe_uninit_vars = let maybe_uninit_vars =
List.foldi ~init:astate.maybe_uninit_vars actuals ~f:(fun idx acc actual_exp -> List.foldi ~init:astate.maybe_uninit_vars actuals ~f:(fun idx acc actual_exp ->
match actual_exp with match actual_exp with
@ -253,41 +257,32 @@ module TransferFunctions (CFG : ProcCfg.S) = struct
match access_expr with AddressOf ae -> ae | _ -> access_expr match access_expr with AddressOf ae -> ae | _ -> access_expr
in in
match AccessExpression.get_base access_expr with match AccessExpression.get_base access_expr with
| _, {Typ.desc= Tarray _} | _, {Typ.desc= Tarray _} when is_initializing_all_args ->
when Option.exists pname_opt ~f:Models.is_initializing_all_args ->
MaybeUninitVars.remove access_expr acc MaybeUninitVars.remove access_expr acc
| _, t | _, t
(* Access to a field of a struct or an element of an array by reference *) (* Access to a field of a struct or an element of an array by reference *)
when Option.exists when Option.exists callee_formals_opt
~f:(is_fld_or_array_elem_passed_by_ref t access_expr idx) ~f:(is_fld_or_array_elem_passed_by_ref t access_expr idx) -> (
callee_formals_opt -> (
match pname_opt with match pname_opt with
| Some pname when Config.uninit_interproc -> | Some pname when Config.uninit_interproc ->
remove_initialized_params pdesc pname acc idx access_expr_to_remove false remove_initialized_params pdesc pname acc idx access_expr_to_remove false
| _ -> | _ ->
MaybeUninitVars.remove access_expr_to_remove acc ) MaybeUninitVars.remove access_expr_to_remove acc )
| base | base when Option.exists pname_opt ~f:Typ.Procname.is_constructor ->
when Option.value_map ~default:false ~f:Typ.Procname.is_constructor pname_opt
->
MaybeUninitVars.remove_all_fields tenv base MaybeUninitVars.remove_all_fields tenv base
(MaybeUninitVars.remove access_expr_to_remove acc) (MaybeUninitVars.remove access_expr_to_remove acc)
| (_, {Typ.desc= Tptr _}) as base -> ( | _, {Typ.desc= Tptr _} -> (
match pname_opt with match pname_opt with
| Some pname when Config.uninit_interproc -> | Some pname when Config.uninit_interproc ->
remove_initialized_params pdesc pname acc idx access_expr_to_remove true remove_initialized_params pdesc pname acc idx access_expr_to_remove true
| _ -> | _ ->
MaybeUninitVars.remove access_expr_to_remove acc MaybeUninitVars.remove_everything_under tenv access_expr_to_remove acc )
|> MaybeUninitVars.remove_all_fields tenv base
|> MaybeUninitVars.remove_all_array_elements base
|> MaybeUninitVars.remove_dereference_access base )
| _ -> | _ ->
acc ) acc )
| HilExp.Closure (_, apl) -> | HilExp.Closure (_, apl) ->
(* remove the captured variables of a block/lambda *) (* remove the captured variables of a block/lambda *)
List.fold List.fold apl ~init:acc ~f:(fun acc (base, _) ->
~f:(fun acc' (base, _) -> MaybeUninitVars.remove (AccessExpression.Base base) acc )
MaybeUninitVars.remove (AccessExpression.Base base) acc' )
~init:acc apl
| _ -> | _ ->
acc ) acc )
in in

@ -12,29 +12,33 @@ module Domain = AbstractDomain.InvertedSet (AccessExpression)
module MaybeUninitVars = struct module MaybeUninitVars = struct
include AbstractDomain.FiniteSet (AccessExpression) include AbstractDomain.FiniteSet (AccessExpression)
let remove_init_fields base formal_var maybe_uninit_vars init_fields = let subst_formal_actual_fields formal_var actual_base_var init_formals =
let subst_formal_actual_fields actual_base_var initialized_fields = map
map (fun access_expr ->
(fun access_expr -> let v, t = AccessExpression.get_base access_expr in
let v, t = AccessExpression.get_base access_expr in let v' = if Var.equal v formal_var then actual_base_var else v in
let v' = if Var.equal v formal_var then actual_base_var else v in let t' =
let t' = match t.desc with
match t.desc with | Typ.Tptr ({Typ.desc= Tstruct _ as desc}, _) ->
| Typ.Tptr ({Typ.desc= Tstruct _ as desc}, _) -> (* a pointer to struct needs to be changed into struct
(* a pointer to struct needs to be changed into struct
as the actual is just type struct and it would make it as the actual is just type struct and it would make it
equality fail. Not sure why the actual are type struct when equality fail. Not sure why the actual are type struct when
passed by reference *) passed by reference *)
{t with Typ.desc} {t with Typ.desc}
| _ -> | _ ->
t t
in in
AccessExpression.replace_base ~remove_deref_after_base:true (v', t') access_expr ) AccessExpression.replace_base ~remove_deref_after_base:true (v', t') access_expr )
initialized_fields init_formals
in
match base with
let remove_init_fields actual_base formal_var maybe_uninit_vars init_formals =
match actual_base with
| actual_base_var, {Typ.desc= Tptr ({Typ.desc= Tstruct _}, _) | Tstruct _} -> | actual_base_var, {Typ.desc= Tptr ({Typ.desc= Tstruct _}, _) | Tstruct _} ->
diff maybe_uninit_vars (subst_formal_actual_fields actual_base_var init_fields) let actuals_to_remove =
subst_formal_actual_fields formal_var actual_base_var init_formals
in
diff maybe_uninit_vars actuals_to_remove
| _ -> | _ ->
maybe_uninit_vars maybe_uninit_vars
@ -67,6 +71,12 @@ module MaybeUninitVars = struct
remove (AccessExpression.ArrayOffset (Base base, elt, [])) maybe_uninit_vars remove (AccessExpression.ArrayOffset (Base base, elt, [])) maybe_uninit_vars
| _ -> | _ ->
maybe_uninit_vars maybe_uninit_vars
let remove_everything_under tenv access_expr maybe_uninit_vars =
let base = AccessExpression.get_base access_expr in
maybe_uninit_vars |> remove access_expr |> remove_all_fields tenv base
|> remove_all_array_elements base |> remove_dereference_access base
end end
type 'a prepost = {pre: 'a; post: 'a} type 'a prepost = {pre: 'a; post: 'a}

Loading…
Cancel
Save