[pulse] Check the validity of the addresses captured by lambda only for captures by reference

Summary: To look for captured variable address escape we should only check the validity of the addresses captured by reference. Checking the validity of the address captured by value can cause nullptr dereference false positives.

Reviewed By: jvillard

Differential Revision: D25219347

fbshipit-source-id: faf6f2b00
master
Daiva Naudziuniene 4 years ago committed by Facebook GitHub Bot
parent e00dbe46b1
commit 4e658903ae

@ -28,24 +28,36 @@ module Closures = struct
let fake_capture_field_prefix = "__capture_" let fake_capture_field_prefix = "__capture_"
let mk_fake_field ~id = let string_of_capture_mode = function
| Pvar.ByReference ->
"by_ref_"
| Pvar.ByValue ->
"by_value_"
let fake_captured_by_ref_field_prefix =
Printf.sprintf "%s%s" fake_capture_field_prefix (string_of_capture_mode Pvar.ByReference)
let mk_fake_field ~id mode =
Fieldname.make Fieldname.make
(Typ.CStruct (QualifiedCppName.of_list ["std"; "function"])) (Typ.CStruct (QualifiedCppName.of_list ["std"; "function"]))
(Printf.sprintf "%s%d" fake_capture_field_prefix id) (Printf.sprintf "%s%s%d" fake_capture_field_prefix (string_of_capture_mode mode) id)
let is_captured_fake_access (access : _ HilExp.Access.t) = let is_captured_by_ref_fake_access (access : _ HilExp.Access.t) =
match access with match access with
| FieldAccess fieldname | FieldAccess fieldname
when String.is_prefix ~prefix:fake_capture_field_prefix (Fieldname.to_string fieldname) -> when String.is_prefix ~prefix:fake_captured_by_ref_field_prefix
(Fieldname.to_string fieldname) ->
true true
| _ -> | _ ->
false false
let mk_capture_edges captured = let mk_capture_edges captured =
List.foldi captured ~init:Memory.Edges.empty ~f:(fun id edges captured_addr_trace -> List.foldi captured ~init:Memory.Edges.empty ~f:(fun id edges (mode, addr, trace) ->
Memory.Edges.add (HilExp.Access.FieldAccess (mk_fake_field ~id)) captured_addr_trace edges ) Memory.Edges.add (HilExp.Access.FieldAccess (mk_fake_field ~id mode)) (addr, trace) edges )
let check_captured_addresses action lambda_addr (astate : t) = let check_captured_addresses action lambda_addr (astate : t) =
@ -57,7 +69,7 @@ module Closures = struct
IContainer.iter_result ~fold:Attributes.fold attributes ~f:(function IContainer.iter_result ~fold:Attributes.fold attributes ~f:(function
| Attribute.Closure _ -> | Attribute.Closure _ ->
IContainer.iter_result ~fold:Memory.Edges.fold edges ~f:(fun (access, addr_trace) -> IContainer.iter_result ~fold:Memory.Edges.fold edges ~f:(fun (access, addr_trace) ->
if is_captured_fake_access access then if is_captured_by_ref_fake_access access then
let+ _ = check_addr_access action addr_trace astate in let+ _ = check_addr_access action addr_trace astate in
() ()
else Ok () ) else Ok () )
@ -71,7 +83,7 @@ module Closures = struct
let captured_addresses = let captured_addresses =
List.filter_map captured ~f:(fun (captured_as, (address_captured, trace_captured), mode) -> List.filter_map captured ~f:(fun (captured_as, (address_captured, trace_captured), mode) ->
let new_trace = ValueHistory.Capture {captured_as; mode; location} :: trace_captured in let new_trace = ValueHistory.Capture {captured_as; mode; location} :: trace_captured in
Some (address_captured, new_trace) ) Some (mode, address_captured, new_trace) )
in in
let closure_addr_hist = (AbstractValue.mk_fresh (), [ValueHistory.Assignment location]) in let closure_addr_hist = (AbstractValue.mk_fresh (), [ValueHistory.Assignment location]) in
let fake_capture_edges = mk_capture_edges captured_addresses in let fake_capture_edges = mk_capture_edges captured_addresses in
@ -487,9 +499,12 @@ let apply_callee ~caller_proc_desc callee_pname call_loc callee_exec_state ~ret
let get_captured_actuals location ~captured_vars ~actual_closure astate = let get_captured_actuals location ~captured_vars ~actual_closure astate =
let* astate, this_value_addr = eval_access location actual_closure Dereference astate in let* astate, this_value_addr = eval_access location actual_closure Dereference astate in
let+ _, astate, captured_vars_with_actuals = let+ _, astate, captured_vars_with_actuals =
List.fold_result captured_vars ~init:(0, astate, []) ~f:(fun (id, astate, captured) var -> List.fold_result captured_vars ~init:(0, astate, [])
~f:(fun (id, astate, captured) (var, mode) ->
let+ astate, captured_actual = let+ astate, captured_actual =
eval_access location this_value_addr (FieldAccess (Closures.mk_fake_field ~id)) astate eval_access location this_value_addr
(FieldAccess (Closures.mk_fake_field ~id mode))
astate
in in
(id + 1, astate, (var, captured_actual) :: captured) ) (id + 1, astate, (var, captured_actual) :: captured) )
in in
@ -506,9 +521,9 @@ let call ~caller_proc_desc err_log ~(callee_data : (Procdesc.t * PulseSummary.t)
in in
let captured_vars = let captured_vars =
Procdesc.get_captured callee_proc_desc Procdesc.get_captured callee_proc_desc
|> List.map ~f:(fun (mangled, _, _) -> |> List.map ~f:(fun (mangled, _, mode) ->
let pvar = Pvar.mk mangled callee_pname in let pvar = Pvar.mk mangled callee_pname in
Var.of_pvar pvar ) (Var.of_pvar pvar, mode) )
in in
let+ astate, captured_vars_with_actuals = let+ astate, captured_vars_with_actuals =
match actuals with match actuals with

@ -405,3 +405,12 @@ S* update_inside_lambda_as_argument(S* s) {
int update_inside_lambda_as_argument_ok_FP(S* param_s) { int update_inside_lambda_as_argument_ok_FP(S* param_s) {
return update_inside_lambda_as_argument(param_s)->f; return update_inside_lambda_as_argument(param_s)->f;
} }
std::function<void()> get_lambda(bool b) {
return [b]() -> void { return; };
}
void capture_false_by_value_ok() {
const auto& f = get_lambda(false);
f();
}

Loading…
Cancel
Save