@ -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