@ -34,8 +34,13 @@ module TransferFunctions (CFG : ProcCfg.S) = struct
None
None
let add_access formals loc ~ is_write_access locks threads ownership
let get_first_actual actuals = List . hd actuals | > Option . bind ~ f : get_access_exp
( proc_data : extras ProcData . t ) access_domain exp =
let apply_to_first_actual ~ f astate actuals =
get_first_actual actuals | > Option . value_map ~ default : astate ~ f
let add_access formals loc ~ is_write_access locks threads ownership tenv access_domain exp =
let open Domain in
let open Domain in
let rec add_field_accesses prefix_path acc = function
let rec add_field_accesses prefix_path acc = function
| [] ->
| [] ->
@ -44,7 +49,7 @@ module TransferFunctions (CFG : ProcCfg.S) = struct
let prefix_path' = Option . value_exn ( AccessExpression . add_access prefix_path access ) in
let prefix_path' = Option . value_exn ( AccessExpression . add_access prefix_path access ) in
if
if
( not ( HilExp . Access . is_field_or_array_access access ) )
( not ( HilExp . Access . is_field_or_array_access access ) )
| | RacerDModels . is_safe_access access prefix_path proc_data. tenv
| | RacerDModels . is_safe_access access prefix_path tenv
then add_field_accesses prefix_path' acc access_list
then add_field_accesses prefix_path' acc access_list
else
else
let is_write = List . is_empty access_list && is_write_access in
let is_write = List . is_empty access_list && is_write_access in
@ -60,13 +65,14 @@ module TransferFunctions (CFG : ProcCfg.S) = struct
add_field_accesses base acc accesses )
add_field_accesses base acc accesses )
let make_container_access formals ret_base callee_pname ~ is_write receiver_ap callee_loc tenv
let make_container_access proc_data ret_base callee_pname ~ is_write receiver_ap callee_loc
( astate : Domain . t ) =
( astate : Domain . t ) =
let open Domain in
let open Domain in
let ProcData . { extras = formals ; tenv } = proc_data in
if
if
AttributeMapDomain . is_synchronized astate . attribute_map receiver_ap
AttributeMapDomain . is_synchronized astate . attribute_map receiver_ap
| | RacerDModels . is_synchronized_container callee_pname receiver_ap tenv
| | RacerDModels . is_synchronized_container callee_pname receiver_ap tenv
then Non e
then astat e
else
else
let ownership_pre = OwnershipDomain . get_owned receiver_ap astate . ownership in
let ownership_pre = OwnershipDomain . get_owned receiver_ap astate . ownership in
let callee_access =
let callee_access =
@ -77,16 +83,15 @@ module TransferFunctions (CFG : ProcCfg.S) = struct
OwnershipDomain . add ( AccessExpression . base ret_base ) ownership_pre astate . ownership
OwnershipDomain . add ( AccessExpression . base ret_base ) ownership_pre astate . ownership
in
in
let accesses = AccessDomain . add_opt callee_access astate . accesses in
let accesses = AccessDomain . add_opt callee_access astate . accesses in
Some { astate with accesses ; ownership }
{ astate with accesses ; ownership }
let add_reads formals exps loc ( { accesses ; locks ; threads ; ownership } as astate : Domain . t )
let add_reads formals exps loc ( { accesses ; locks ; threads ; ownership } as astate : Domain . t ) tenv =
proc_data =
let accesses =
let accesses' =
List . fold exps ~ init : accesses
List . fold exps ~ init : accesses
~ f : ( add_access formals loc ~ is_write_access : false locks threads ownership proc_data )
~ f : ( add_access formals loc ~ is_write_access : false locks threads ownership tenv )
in
in
{ astate with accesses = accesses' }
{ astate with accesses }
let expand_actuals formals actuals accesses pdesc =
let expand_actuals formals actuals accesses pdesc =
@ -153,28 +158,24 @@ module TransferFunctions (CFG : ProcCfg.S) = struct
let open RacerDModels in
let open RacerDModels in
let open RacerDDomain in
let open RacerDDomain in
if RacerDModels . is_synchronized_container_constructor tenv callee_pname actuals then
if RacerDModels . is_synchronized_container_constructor tenv callee_pname actuals then
List . hd actuals | > Option . bind ~ f : get_access_exp
apply_to_first_actual astate actuals ~ f : ( fun receiver ->
| > Option . value_map ~ default : astate ~ f : ( fun receiver ->
let attribute_map = AttributeMapDomain . add receiver Synchronized astate . attribute_map in
let attribute_map =
{ astate with attribute_map } )
AttributeMapDomain . add receiver Synchronized astate . attribute_map
in
{ astate with attribute_map } )
else if RacerDModels . is_converter_to_synchronized_container tenv callee_pname actuals then
else if RacerDModels . is_converter_to_synchronized_container tenv callee_pname actuals then
let attribute_map =
let attribute_map =
AttributeMapDomain . add ( AccessExpression . base ret_base ) Synchronized astate . attribute_map
AttributeMapDomain . add ( AccessExpression . base ret_base ) Synchronized astate . attribute_map
in
in
{ astate with attribute_map }
{ astate with attribute_map }
else if is_box callee_pname then
else if is_box callee_pname then
match actuals with
apply_to_first_actual astate actuals ~ f : ( fun actual_access_expr ->
| HilExp . AccessExpression actual_access_expr :: _
if AttributeMapDomain . is_functional astate . attribute_map actual_access_expr then
when AttributeMapDomain . is_functional astate . attribute_map actual_access_expr ->
(* TODO: check for constants, which are functional? *)
(* TODO: check for constants, which are functional? *)
let attribute_map =
let attribute_map =
AttributeMapDomain . add ( AccessExpression . base ret_base ) Functional
AttributeMapDomain . add ( AccessExpression . base ret_base ) Functional astate . attribute_map
astate . attribute_map
in
in
{ astate with attribute_map }
{ astate with attribute_map }
| _ ->
else astate )
astate
else
else
let ownership =
let ownership =
OwnershipDomain . add ( AccessExpression . base ret_base ) OwnershipAbstractValue . owned
OwnershipDomain . add ( AccessExpression . base ret_base ) OwnershipAbstractValue . owned
@ -183,37 +184,27 @@ module TransferFunctions (CFG : ProcCfg.S) = struct
{ astate with ownership }
{ astate with ownership }
let treat_call_acquiring_ownership ret_base procname actuals loc
let do_call_acquiring_ownership ret_base astate =
( { ProcData . tenv ; extras } as proc_data ) astate () =
let open Domain in
let open Domain in
if RacerDModels . acquires_ownership procname tenv then
let ownership =
let astate = add_reads extras actuals loc astate proc_data in
OwnershipDomain . add ( AccessExpression . base ret_base ) OwnershipAbstractValue . owned
let ownership =
astate . ownership
OwnershipDomain . add ( AccessExpression . base ret_base ) OwnershipAbstractValue . owned
in
astate . ownership
{ astate with ownership }
in
Some { astate with ownership }
else None
let treat_container_accesses ret_base callee_pname actuals loc { ProcData . tenv ; extras } astate () =
let do_container_access ~ is_write ret_base callee_pname actuals loc proc_data astate =
let open RacerDModels in
match get_first_actual actuals with
Option . bind ( get_container_access callee_pname tenv ) ~ f : ( fun container_access ->
| Some receiver_expr ->
match List . hd actuals with
make_container_access proc_data ret_base callee_pname ~ is_write receiver_expr loc astate
| Some ( HilExp . AccessExpression receiver_expr ) ->
| None ->
let is_write =
L . internal_error " Call to %a is marked as a container access, but has no receiver "
match container_access with ContainerWrite -> true | ContainerRead -> false
Procname . pp callee_pname ;
in
astate
make_container_access extras ret_base callee_pname ~ is_write receiver_expr loc tenv
astate
| _ ->
L . internal_error " Call to %a is marked as a container write, but has no receiver "
Procname . pp callee_pname ;
None )
let do_proc_call ret_base callee_pname actuals call_flags loc { ProcData . tenv ; summary ; extras }
let do_proc_call ret_base callee_pname actuals call_flags loc { ProcData . tenv ; summary ; extras }
( astate : Domain . t ) () =
( astate : Domain . t ) =
let open Domain in
let open Domain in
let open RacerDModels in
let open RacerDModels in
let open ConcurrencyModels in
let open ConcurrencyModels in
@ -317,12 +308,11 @@ module TransferFunctions (CFG : ProcCfg.S) = struct
{ astate_callee with ownership ; attribute_map }
{ astate_callee with ownership ; attribute_map }
let do_assignment lhs_access_exp rhs_exp loc ( { ProcData . tenv ; extras } as proc_data )
let do_assignment lhs_access_exp rhs_exp loc { ProcData . tenv ; extras } ( astate : Domain . t ) =
( astate : Domain . t ) =
let open Domain in
let open Domain in
let rhs_accesses =
let rhs_accesses =
add_access extras loc ~ is_write_access : false astate . locks astate . threads astate . ownership
add_access extras loc ~ is_write_access : false astate . locks astate . threads astate . ownership tenv
proc_data astate. accesses rhs_exp
astate. accesses rhs_exp
in
in
let rhs_access_exprs = HilExp . get_access_exprs rhs_exp in
let rhs_access_exprs = HilExp . get_access_exprs rhs_exp in
let is_functional =
let is_functional =
@ -345,7 +335,7 @@ module TransferFunctions (CFG : ProcCfg.S) = struct
rhs_accesses
rhs_accesses
else
else
add_access extras loc ~ is_write_access : true astate . locks astate . threads astate . ownership
add_access extras loc ~ is_write_access : true astate . locks astate . threads astate . ownership
proc_data rhs_accesses ( HilExp . AccessExpression lhs_access_exp )
tenv rhs_accesses ( HilExp . AccessExpression lhs_access_exp )
in
in
let ownership = OwnershipDomain . propagate_assignment lhs_access_exp rhs_exp astate . ownership in
let ownership = OwnershipDomain . propagate_assignment lhs_access_exp rhs_exp astate . ownership in
let attribute_map =
let attribute_map =
@ -354,7 +344,7 @@ module TransferFunctions (CFG : ProcCfg.S) = struct
{ astate with accesses ; ownership ; attribute_map }
{ astate with accesses ; ownership ; attribute_map }
let do_assume formals assume_exp loc proc_data ( astate : Domain . t ) =
let do_assume formals assume_exp loc tenv ( astate : Domain . t ) =
let open Domain in
let open Domain in
let apply_choice bool_value ( acc : Domain . t ) = function
let apply_choice bool_value ( acc : Domain . t ) = function
| Attribute . LockHeld ->
| Attribute . LockHeld ->
@ -373,7 +363,7 @@ module TransferFunctions (CFG : ProcCfg.S) = struct
in
in
let accesses =
let accesses =
add_access formals loc ~ is_write_access : false astate . locks astate . threads astate . ownership
add_access formals loc ~ is_write_access : false astate . locks astate . threads astate . ownership
proc_data astate . accesses assume_exp
tenv astate . accesses assume_exp
in
in
let astate' =
let astate' =
match HilExp . get_access_exprs assume_exp with
match HilExp . get_access_exprs assume_exp with
@ -390,16 +380,17 @@ module TransferFunctions (CFG : ProcCfg.S) = struct
{ astate' with accesses }
{ astate' with accesses }
let exec_instr ( astate : Domain . t ) ( { ProcData . summary ; extras } as proc_data ) _
let exec_instr astate ( { ProcData . summary ; extras ; tenv } as proc_data ) _ instr =
( instr : HilInstr . t ) =
match ( instr : HilInstr . t ) with
match instr with
| Call ( ret_base , Direct callee_pname , actuals , call_flags , loc ) ->
| Call ( ret_base , Direct callee_pname , actuals , call_flags , loc ) ->
let astate = add_reads extras actuals loc astate proc_data in
let astate = add_reads extras actuals loc astate tenv in
treat_call_acquiring_ownership ret_base callee_pname actuals loc proc_data astate ()
if RacerDModels . acquires_ownership callee_pname tenv then
| > IOption . if_none_evalopt
do_call_acquiring_ownership ret_base astate
~ f : ( treat_container_accesses ret_base callee_pname actuals loc proc_data astate )
else if RacerDModels . is_container_write tenv callee_pname then
| > IOption . if_none_eval
do_container_access ~ is_write : true ret_base callee_pname actuals loc proc_data astate
~ f : ( do_proc_call ret_base callee_pname actuals call_flags loc proc_data astate )
else if RacerDModels . is_container_read tenv callee_pname then
do_container_access ~ is_write : false ret_base callee_pname actuals loc proc_data astate
else do_proc_call ret_base callee_pname actuals call_flags loc proc_data astate
| Call ( _ , Indirect _ , _ , _ , _ ) ->
| Call ( _ , Indirect _ , _ , _ , _ ) ->
if Procname . is_java ( Summary . get_proc_name summary ) then
if Procname . is_java ( Summary . get_proc_name summary ) then
L . ( die InternalError ) " Unexpected indirect call instruction %a " HilInstr . pp instr
L . ( die InternalError ) " Unexpected indirect call instruction %a " HilInstr . pp instr
@ -407,7 +398,7 @@ module TransferFunctions (CFG : ProcCfg.S) = struct
| Assign ( lhs_access_expr , rhs_exp , loc ) ->
| Assign ( lhs_access_expr , rhs_exp , loc ) ->
do_assignment lhs_access_expr rhs_exp loc proc_data astate
do_assignment lhs_access_expr rhs_exp loc proc_data astate
| Assume ( assume_exp , _ , _ , loc ) ->
| Assume ( assume_exp , _ , _ , loc ) ->
do_assume extras assume_exp loc proc_data astate
do_assume extras assume_exp loc tenv astate
| Metadata _ ->
| Metadata _ ->
astate
astate