@ -50,10 +50,10 @@ end
include Import
let check_addr_access ? must_be_valid_reason access_mode location ( address , history ) astate =
let check_addr_access path ? must_be_valid_reason access_mode location ( address , history ) astate =
let access_trace = Trace . Immediate { location ; history } in
let * astate =
AddressAttributes . check_valid ? must_be_valid_reason access_trace address astate
AddressAttributes . check_valid path ? must_be_valid_reason access_trace address astate
| > Result . map_error ~ f : ( fun ( invalidation , invalidation_trace ) ->
ReportableError
{ diagnostic =
@ -79,10 +79,10 @@ let check_addr_access ?must_be_valid_reason access_mode location (address, histo
Ok astate
let check_and_abduce_addr_access_isl access_mode location ( address , history ) ? ( null_noop = false )
astate =
let check_and_abduce_addr_access_isl path access_mode location ( address , history )
? ( null_noop = false ) astate =
let access_trace = Trace . Immediate { location ; history } in
AddressAttributes . check_valid_isl access_trace address ~ null_noop astate
AddressAttributes . check_valid_isl path access_trace address ~ null_noop astate
| > List . map ~ f : ( fun access_result ->
let * astate = AccessResult . of_abductive_access_result access_trace access_result in
match access_mode with
@ -137,7 +137,7 @@ module Closures = struct
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 path action lambda_addr ( astate : t ) =
match AbductiveDomain . find_post_cell_opt lambda_addr astate with
| None ->
Ok astate
@ -147,7 +147,7 @@ module Closures = struct
| Attribute . Closure _ ->
IContainer . iter_result ~ fold : Memory . Edges . fold edges ~ f : ( fun ( access , addr_trace ) ->
if is_captured_by_ref_fake_access access then
let + _ = check_addr_access Read action addr_trace astate in
let + _ = check_addr_access path Read action addr_trace astate in
()
else Ok () )
| _ ->
@ -172,50 +172,52 @@ module Closures = struct
( astate , closure_addr_hist )
end
let eval_var location hist var astate = Stack . eval location hist var astate
let eval_access ? must_be_valid_reason mode location addr_hist access astate =
let + astate = check_addr_access ? must_be_valid_reason mode location addr_hist astate in
let eval_access path ? must_be_valid_reason mode location addr_hist access astate =
let + astate = check_addr_access path ? must_be_valid_reason mode location addr_hist astate in
Memory . eval_edge addr_hist access astate
let eval_deref_access ? must_be_valid_reason mode location addr_hist access astate =
let * astate , addr_hist = eval_access Read location addr_hist access astate in
eval_access ? must_be_valid_reason mode location addr_hist Dereference astate
let eval_deref_access path ? must_be_valid_reason mode location addr_hist access astate =
let * astate , addr_hist = eval_access path Read location addr_hist access astate in
eval_access path ? must_be_valid_reason mode location addr_hist Dereference astate
let eval_access_biad_isl mode location addr_hist access astate =
let eval_access_biad_isl path mode location addr_hist access astate =
let map_ok addr_hist access results =
List . map results ~ f : ( fun result ->
let + astate = result in
Memory . eval_edge addr_hist access astate )
in
let results = check_and_abduce_addr_access_isl mode location addr_hist astate in
let results = check_and_abduce_addr_access_isl path mode location addr_hist astate in
map_ok addr_hist access results
let eval mode location exp0 astate =
let rec eval mode exp astate =
let eval path mode location exp0 astate =
let rec eval path mode exp astate =
match ( exp : Exp . t ) with
| Var id ->
Ok ( eval_var location (* error in case of missing history? *) [] ( Var . of_id id ) astate )
Ok
( Stack . eval path location (* error in case of missing history? *) [] ( Var . of_id id )
astate )
| Lvar pvar ->
Ok
( eval_var location
( Stack . eval path location
[ ValueHistory . VariableAccessed ( pvar , location ) ]
( Var . of_pvar pvar ) astate )
| Lfield ( exp' , field , _ ) ->
let * astate , addr_hist = eval Read exp' astate in
eval_access mode location addr_hist ( FieldAccess field ) astate
let * astate , addr_hist = eval path Read exp' astate in
eval_access path mode location addr_hist ( FieldAccess field ) astate
| Lindex ( exp' , exp_index ) ->
let * astate , addr_hist_index = eval Read exp_index astate in
let * astate , addr_hist = eval Read exp' astate in
eval_access mode location addr_hist ( ArrayAccess ( StdTyp . void , fst addr_hist_index ) ) astate
let * astate , addr_hist_index = eval path Read exp_index astate in
let * astate , addr_hist = eval path Read exp' astate in
eval_access path mode location addr_hist
( ArrayAccess ( StdTyp . void , fst addr_hist_index ) )
astate
| Closure { name ; captured_vars } ->
let + astate , rev_captured =
List . fold_result captured_vars ~ init : ( astate , [] )
~ f : ( fun ( astate , rev_captured ) ( capt_exp , captured_as , _ , mode ) ->
let + astate , addr_trace = eval Read capt_exp astate in
let + astate , addr_trace = eval path Read capt_exp astate in
( astate , ( captured_as , addr_trace , mode ) :: rev_captured ) )
in
Closures . record location name ( List . rev rev_captured ) astate
@ -223,7 +225,7 @@ let eval mode location exp0 astate =
(* function pointers are represented as closures with no captured variables *)
Ok ( Closures . record location proc_name [] astate )
| Cast ( _ , exp' ) ->
eval mode exp' astate
eval path mode exp' astate
| Const ( Cint i ) ->
let v = AbstractValue . Constants . get_int i in
let invalidation = Invalidation . ConstantDereference i in
@ -235,14 +237,14 @@ let eval mode location exp0 astate =
in
( astate , ( v , [ ValueHistory . Invalidated ( invalidation , location ) ] ) )
| UnOp ( unop , exp , _ typ ) ->
let * astate , ( addr , hist ) = eval Read exp astate in
let * astate , ( addr , hist ) = eval path Read exp astate in
let unop_addr = AbstractValue . mk_fresh () in
let + astate = PulseArithmetic . eval_unop unop_addr unop addr astate in
( astate , ( unop_addr , hist ) )
| BinOp ( bop , e_lhs , e_rhs ) ->
let * astate , ( addr_lhs , hist_lhs ) = eval Read e_lhs astate in
let * astate , ( addr_lhs , hist_lhs ) = eval path Read e_lhs astate in
(* NOTE: keeping track of only [hist_lhs] into the binop is not the best *)
let * astate , ( addr_rhs , _ hist_rhs ) = eval Read e_rhs astate in
let * astate , ( addr_rhs , _ hist_rhs ) = eval path Read e_rhs astate in
let binop_addr = AbstractValue . mk_fresh () in
let + astate =
PulseArithmetic . eval_binop binop_addr bop ( AbstractValueOperand addr_lhs )
@ -252,24 +254,24 @@ let eval mode location exp0 astate =
| Const _ | Sizeof _ | Exn _ ->
Ok ( astate , ( AbstractValue . mk_fresh () , (* TODO history *) [] ) )
in
eval mode exp0 astate
eval path mode exp0 astate
let eval_to_operand mode location exp astate =
let eval_to_operand path mode location exp astate =
match ( exp : Exp . t ) with
| Const ( Cint i ) ->
Ok ( astate , PulseArithmetic . LiteralOperand i )
| exp ->
let + astate , ( value , _ ) = eval mode location exp astate in
let + astate , ( value , _ ) = eval path mode location exp astate in
( astate , PulseArithmetic . AbstractValueOperand value )
let prune location ~ condition astate =
let prune path location ~ condition astate =
let rec prune_aux ~ negated exp astate =
match ( exp : Exp . t ) with
| BinOp ( bop , exp_lhs , exp_rhs ) ->
let * astate , lhs_op = eval_to_operand Read location exp_lhs astate in
let * astate , rhs_op = eval_to_operand Read location exp_rhs astate in
let * astate , lhs_op = eval_to_operand path Read location exp_lhs astate in
let * astate , rhs_op = eval_to_operand path Read location exp_rhs astate in
PulseArithmetic . prune_binop ~ negated bop lhs_op rhs_op astate
| UnOp ( LNot , exp' , _ ) ->
prune_aux ~ negated : ( not negated ) exp' astate
@ -279,53 +281,53 @@ let prune location ~condition astate =
prune_aux ~ negated : false condition astate
let eval_deref ? must_be_valid_reason location exp astate =
let * astate , addr_hist = eval Read location exp astate in
let + astate = check_addr_access ? must_be_valid_reason Read location addr_hist astate in
let eval_deref path ? must_be_valid_reason location exp astate =
let * astate , addr_hist = eval path Read location exp astate in
let + astate = check_addr_access path ? must_be_valid_reason Read location addr_hist astate in
Memory . eval_edge addr_hist Dereference astate
let eval_proc_name location call_exp astate =
let eval_proc_name path location call_exp astate =
match ( call_exp : Exp . t ) with
| Const ( Cfun proc_name ) | Closure { name = proc_name } ->
Ok ( astate , Some proc_name )
| _ ->
let + astate , ( f , _ ) = eval Read location call_exp astate in
let + astate , ( f , _ ) = eval path Read location call_exp astate in
( astate , AddressAttributes . get_closure_proc_name f astate )
let eval_structure_isl mode loc exp astate =
let eval_structure_isl path mode loc exp astate =
match ( exp : Exp . t ) with
| Lfield ( exp' , field , _ ) ->
let + astate , addr_hist = eval mode loc exp' astate in
let astates = eval_access_biad_isl mode loc addr_hist ( FieldAccess field ) astate in
let + astate , addr_hist = eval path mode loc exp' astate in
let astates = eval_access_biad_isl path mode loc addr_hist ( FieldAccess field ) astate in
( false , astates )
| Lindex ( exp' , exp_index ) ->
let * astate , addr_hist_index = eval mode loc exp_index astate in
let + astate , addr_hist = eval mode loc exp' astate in
let * astate , addr_hist_index = eval path mode loc exp_index astate in
let + astate , addr_hist = eval path mode loc exp' astate in
let astates =
eval_access_biad_isl mode loc addr_hist
eval_access_biad_isl path mode loc addr_hist
( ArrayAccess ( StdTyp . void , fst addr_hist_index ) )
astate
in
( false , astates )
| _ ->
let + astate , ( addr , history ) = eval mode loc exp astate in
let + astate , ( addr , history ) = eval path mode loc exp astate in
( true , [ Ok ( astate , ( addr , history ) ) ] )
let eval_deref_biad_isl location access addr_hist astate =
check_and_abduce_addr_access_isl Read location addr_hist astate
let eval_deref_biad_isl path location access addr_hist astate =
check_and_abduce_addr_access_isl path Read location addr_hist astate
| > List . map ~ f : ( fun result ->
let + astate = result in
Memory . eval_edge addr_hist access astate )
let eval_deref_isl location exp astate =
let < * > is_structured , ls_astate_addr_hist = eval_structure_isl Read location exp astate in
let eval_deref_isl path location exp astate =
let < * > is_structured , ls_astate_addr_hist = eval_structure_isl path Read location exp astate in
let eval_deref_function ( astate , addr_hist ) =
if is_structured then eval_deref_biad_isl location Dereference addr_hist astate
else [ eval_deref location exp astate ]
if is_structured then eval_deref_biad_isl path location Dereference addr_hist astate
else [ eval_deref path location exp astate ]
in
List . concat_map ls_astate_addr_hist ~ f : ( fun result ->
let < * > astate_addr = result in
@ -349,42 +351,44 @@ let havoc_id id loc_opt astate =
else astate
let write_access location addr_trace_ref access addr_trace_obj astate =
check_addr_access Write location addr_trace_ref astate
let write_access path location addr_trace_ref access addr_trace_obj astate =
check_addr_access path Write location addr_trace_ref astate
> > | Memory . add_edge addr_trace_ref access addr_trace_obj location
let write_access_biad_isl location addr_trace_ref access addr_trace_obj astate =
let astates = check_and_abduce_addr_access_isl Write location addr_trace_ref astate in
let write_access_biad_isl path location addr_trace_ref access addr_trace_obj astate =
let astates = check_and_abduce_addr_access_isl path Write location addr_trace_ref astate in
List . map astates ~ f : ( fun result ->
let + astate = result in
Memory . add_edge addr_trace_ref access addr_trace_obj location astate )
let write_deref location ~ ref : addr_trace_ref ~ obj : addr_trace_obj astate =
write_access location addr_trace_ref Dereference addr_trace_obj astate
let write_deref path location ~ ref : addr_trace_ref ~ obj : addr_trace_obj astate =
write_access path location addr_trace_ref Dereference addr_trace_obj astate
let write_deref_biad_isl location ~ ref : ( addr_ref , addr_ref_history ) access ~ obj : addr_trace_obj
let write_deref_biad_isl path location ~ ref : ( addr_ref , addr_ref_history ) access ~ obj : addr_trace_obj
astate =
write_access_biad_isl location ( addr_ref , addr_ref_history ) access addr_trace_obj astate
write_access_biad_isl path location ( addr_ref , addr_ref_history ) access addr_trace_obj astate
let write_field location ~ ref : addr_trace_ref field ~ obj : addr_trace_obj astate =
write_access location addr_trace_ref ( FieldAccess field ) addr_trace_obj astate
let write_field path location ~ ref : addr_trace_ref field ~ obj : addr_trace_obj astate =
write_access path location addr_trace_ref ( FieldAccess field ) addr_trace_obj astate
let write_deref_field location ~ ref : addr_trace_ref field ~ obj : addr_trace_obj astate =
let * astate , addr_hist = eval_access Read location addr_trace_ref ( FieldAccess field ) astate in
write_deref location ~ ref : addr_hist ~ obj : addr_trace_obj astate
let write_deref_field path location ~ ref : addr_trace_ref field ~ obj : addr_trace_obj astate =
let * astate , addr_hist =
eval_access path Read location addr_trace_ref ( FieldAccess field ) astate
in
write_deref path location ~ ref : addr_hist ~ obj : addr_trace_obj astate
let write_arr_index location ~ ref : addr_trace_ref ~ index ~ obj : addr_trace_obj astate =
write_access location addr_trace_ref ( ArrayAccess ( StdTyp . void , index ) ) addr_trace_obj astate
let write_arr_index path location ~ ref : addr_trace_ref ~ index ~ obj : addr_trace_obj astate =
write_access path location addr_trace_ref ( ArrayAccess ( StdTyp . void , index ) ) addr_trace_obj astate
let havoc_deref_field location addr_trace field trace_obj astate =
write_deref_field location ~ ref : addr_trace field
let havoc_deref_field path location addr_trace field trace_obj astate =
write_deref_field path location ~ ref : addr_trace field
~ obj : ( AbstractValue . mk_fresh () , trace_obj )
astate
@ -405,10 +409,10 @@ type invalidation_access =
| StackAddress of Var . t * ValueHistory . t
| UntraceableAccess
let record_invalidation access_path location cause astate =
let record_invalidation path access_path location cause astate =
match access_path with
| StackAddress ( x , hist0 ) ->
let astate , ( addr , hist ) = Stack . eval location hist0 x astate in
let astate , ( addr , hist ) = Stack . eval path location hist0 x astate in
Stack . add x ( addr , Invalidated ( cause , location ) :: hist ) astate
| MemoryAccess { pointer ; access ; hist_obj_default } ->
let addr_obj , hist_obj =
@ -425,40 +429,40 @@ let record_invalidation access_path location cause astate =
astate
let invalidate access_path location cause addr_trace astate =
check_addr_access NoAccess location addr_trace astate
let invalidate path access_path location cause addr_trace astate =
check_addr_access path NoAccess location addr_trace astate
> > | AddressAttributes . invalidate addr_trace cause location
> > | record_invalidation access_path location cause
> > | record_invalidation path access_path location cause
let invalidate_biad_isl location cause ( address , history ) astate =
check_and_abduce_addr_access_isl NoAccess location ( address , history ) ~ null_noop : true astate
let invalidate_biad_isl path location cause ( address , history ) astate =
check_and_abduce_addr_access_isl path NoAccess location ( address , history ) ~ null_noop : true astate
| > List . map ~ f : ( fun result ->
let + astate = result in
AddressAttributes . invalidate ( address , history ) cause location astate )
let invalidate_access location cause ref_addr_hist access astate =
let invalidate_access path location cause ref_addr_hist access astate =
let astate , ( addr_obj , hist_obj ) = Memory . eval_edge ref_addr_hist access astate in
invalidate
invalidate path
( MemoryAccess { pointer = ref_addr_hist ; access ; hist_obj_default = hist_obj } )
location cause
( addr_obj , snd ref_addr_hist )
astate
let invalidate_deref_access location cause ref_addr_hist access astate =
let invalidate_deref_access path location cause ref_addr_hist access astate =
let astate , addr_hist = Memory . eval_edge ref_addr_hist access astate in
let astate , ( addr_obj , hist_obj ) = Memory . eval_edge addr_hist Dereference astate in
invalidate
invalidate path
( MemoryAccess { pointer = ref_addr_hist ; access ; hist_obj_default = hist_obj } )
location cause
( addr_obj , snd ref_addr_hist )
astate
let invalidate_array_elements location cause addr_trace astate =
let + astate = check_addr_access NoAccess location addr_trace astate in
let invalidate_array_elements path location cause addr_trace astate =
let + astate = check_addr_access path NoAccess location addr_trace astate in
match Memory . find_opt ( fst addr_trace ) astate with
| None ->
astate
@ -467,15 +471,15 @@ let invalidate_array_elements location cause addr_trace astate =
match ( access : Memory . Access . t ) with
| ArrayAccess _ as access ->
AddressAttributes . invalidate dest_addr_trace cause location astate
| > record_invalidation
| > record_invalidation path
( MemoryAccess { pointer = addr_trace ; access ; hist_obj_default = snd dest_addr_trace } )
location cause
| _ ->
astate )
let shallow_copy location addr_hist astate =
let + astate = check_addr_access Read location addr_hist astate in
let shallow_copy path location addr_hist astate =
let + astate = check_addr_access path Read location addr_hist astate in
let cell =
match AbductiveDomain . find_post_cell_opt ( fst addr_hist ) astate with
| None ->
@ -668,13 +672,13 @@ let remove_vars vars location astate =
Stack . remove_vars vars astate
let get_captured_actuals location ~ captured_vars ~ actual_closure astate =
let * astate , this_value_addr = eval_access Read location actual_closure Dereference astate in
let get_captured_actuals path location ~ captured_vars ~ actual_closure astate =
let * astate , this_value_addr = eval_access path Read location actual_closure Dereference astate in
let + _ , astate , captured_vars_with_actuals =
List . fold_result captured_vars ~ init : ( 0 , astate , [] )
~ f : ( fun ( id , astate , captured ) ( var , mode , typ ) ->
let + astate , captured_actual =
eval_access Read location this_value_addr
eval_access path Read location this_value_addr
( FieldAccess ( Closures . mk_fake_field ~ id mode ) )
astate
in