@ -992,7 +992,7 @@ let report_unsafe_accesses ~issue_log classname (aggregated_access_map : ReportM
let open RacerDDomain in
let open RacerDDomain in
let open RacerDModels in
let open RacerDModels in
let is_duplicate_report ( { snapshot ; procdesc } : reported_access )
let is_duplicate_report ( { snapshot ; procdesc } : reported_access )
{reported_sites ; reported_writes ; reported_reads ; reported_unannotated_calls } =
( {reported_sites ; reported_writes ; reported_reads ; reported_unannotated_calls } , _ ) =
let pname = Procdesc . get_proc_name procdesc in
let pname = Procdesc . get_proc_name procdesc in
let call_site = CallSite . make pname ( TraceElem . get_loc snapshot . access ) in
let call_site = CallSite . make pname ( TraceElem . get_loc snapshot . access ) in
if Config . filtering then
if Config . filtering then
@ -1026,95 +1026,97 @@ let report_unsafe_accesses ~issue_log classname (aggregated_access_map : ReportM
{ reported with reported_unannotated_calls ; reported_sites }
{ reported with reported_unannotated_calls ; reported_sites }
else reported
else reported
in
in
let report_unsafe_access accesses ( reported_acc , issue_log )
let report_thread_safety_violation ~ acc ~ make_description ~ report_kind reported_access =
( { snapshot ; threads ; tenv ; procdesc } as reported_access ) =
if is_duplicate_report reported_access acc then acc
let pname = Procdesc . get_proc_name procdesc in
if is_duplicate_report reported_access reported_acc then ( reported_acc , issue_log )
else
else
match snapshot . access . elem with
let reported_acc , issue_log = acc in
| Access . InterfaceCall reported_pname
let issue_log =
when AccessSnapshot . is_unprotected snapshot
report_thread_safety_violation ~ issue_log ~ make_description ~ report_kind reported_access
&& ThreadsDomain . is_any threads
in
&& is_marked_thread_safe procdesc tenv ->
( update_reported reported_access reported_acc , issue_log )
(* un-annotated interface call + no lock in method marked thread-safe. warn *)
in
let issue_log =
let report_unannotated_interface_violation ~ acc reported_pname reported_access =
report_unannotated_interface_violation ~ issue_log reported_pname reported_access
if is_duplicate_report reported_access acc then acc
in
else
( update_reported reported_access reported_acc , issue_log )
let reported_acc , issue_log = acc in
| Access . InterfaceCall _ ->
let issue_log =
( reported_acc , issue_log )
report_unannotated_interface_violation ~ issue_log reported_pname reported_access
| ( Access . Write _ | ContainerWrite _ ) when Typ . Procname . is_java pname ->
in
let conflict =
( update_reported reported_access reported_acc , issue_log )
if ThreadsDomain . is_any threads then
in
(* unprotected write in method that may run in parallel with itself. warn *)
let report_unsafe_access accesses acc ( { snapshot ; threads ; tenv ; procdesc } as reported_access ) =
None
let pname = Procdesc . get_proc_name procdesc in
else
match snapshot . access . elem with
(* unprotected write, but not on a method that may run in parallel with itself
| Access . InterfaceCall reported_pname
when AccessSnapshot . is_unprotected snapshot
&& ThreadsDomain . is_any threads
&& is_marked_thread_safe procdesc tenv ->
(* un-annotated interface call + no lock in method marked thread-safe. warn *)
report_unannotated_interface_violation ~ acc reported_pname reported_access
| Access . InterfaceCall _ ->
acc
| ( Access . Write _ | ContainerWrite _ ) when Typ . Procname . is_java pname ->
let conflict =
if ThreadsDomain . is_any threads then
(* unprotected write in method that may run in parallel with itself. warn *)
None
else
(* unprotected write, but not on a method that may run in parallel with itself
( i . e . , not a self race ) . find accesses on a background thread this access might
( i . e . , not a self race ) . find accesses on a background thread this access might
conflict with and report them * )
conflict with and report them * )
List . find_map accesses ~ f : ( fun { snapshot = other_snapshot ; threads = other_threads } ->
List . find_map accesses ~ f : ( fun { snapshot = other_snapshot ; threads = other_threads } ->
if TraceElem . is_write other_snapshot . access && ThreadsDomain . is_any other_threads
if TraceElem . is_write other_snapshot . access && ThreadsDomain . is_any other_threads
then Some other_snapshot . access
then Some other_snapshot . access
else None )
else None )
in
in
if
if
AccessSnapshot . is_unprotected snapshot
AccessSnapshot . is_unprotected snapshot
&& ( Option . is_some conflict | | ThreadsDomain . is_any threads )
&& ( Option . is_some conflict | | ThreadsDomain . is_any threads )
then
then
let issue_log =
report_thread_safety_violation ~ acc ~ make_description : make_unprotected_write_description
report_thread_safety_violation ~ issue_log
~ report_kind : ( WriteWriteRace conflict ) reported_access
~ make_description : make_unprotected_write_description
else acc
~ report_kind : ( WriteWriteRace conflict ) reported_access
| Access . Write _ | ContainerWrite _ ->
in
(* Do not report unprotected writes for ObjC_Cpp *)
( update_reported reported_access reported_acc , issue_log )
acc
else ( reported_acc , issue_log )
| ( Access . Read _ | ContainerRead _ ) when AccessSnapshot . is_unprotected snapshot ->
| Access . Write _ | ContainerWrite _ ->
(* unprotected read. report all writes as conflicts for java. for c++ filter out
(* Do not report unprotected writes for ObjC_Cpp *)
( reported_acc , issue_log )
| ( Access . Read _ | ContainerRead _ ) when AccessSnapshot . is_unprotected snapshot ->
(* unprotected read. report all writes as conflicts for java. for c++ filter out
unprotected writes * )
unprotected writes * )
let is_conflict { snapshot ; threads = other_threads } =
let is_conflict { snapshot ; threads = other_threads } =
TraceElem . is_write snapshot . access
TraceElem . is_write snapshot . access
&&
&&
if Typ . Procname . is_java pname then
if Typ . Procname . is_java pname then
ThreadsDomain . is_any threads | | ThreadsDomain . is_any other_threads
ThreadsDomain . is_any threads | | ThreadsDomain . is_any other_threads
else not ( AccessSnapshot . is_unprotected snapshot )
else not ( AccessSnapshot . is_unprotected snapshot )
in
in
List . find ~ f : is_conflict accesses
List . find ~ f : is_conflict accesses
| > Option . value_map ~ default : ( reported_acc , issue_log ) ~ f : ( fun conflict ->
| > Option . value_map ~ default : acc ~ f : ( fun conflict ->
let make_description =
let make_description =
make_read_write_race_description ~ read_is_sync : false conflict
make_read_write_race_description ~ read_is_sync : false conflict
in
in
let report_kind = ReadWriteRace conflict . snapshot . access in
let report_kind = ReadWriteRace conflict . snapshot . access in
let issue_log =
report_thread_safety_violation ~ acc ~ make_description ~ report_kind reported_access
report_thread_safety_violation ~ issue_log ~ make_description ~ report_kind
)
reported_access
| Access . Read _ | ContainerRead _ ->
in
(* protected read. report unprotected writes and opposite protected writes as conflicts *)
( update_reported reported_access reported_acc , issue_log ) )
let can_conflict ( snapshot1 : AccessSnapshot . t ) ( snapshot2 : AccessSnapshot . t ) =
| Access . Read _ | ContainerRead _ ->
if snapshot1 . lock && snapshot2 . lock then false
(* protected read. report unprotected writes and opposite protected writes as conflicts *)
else ThreadsDomain . can_conflict snapshot1 . thread snapshot2 . thread
let can_conflict ( snapshot1 : AccessSnapshot . t ) ( snapshot2 : AccessSnapshot . t ) =
in
if snapshot1 . lock && snapshot2 . lock then false
let is_conflict { snapshot = other_snapshot ; threads = other_threads } =
else ThreadsDomain . can_conflict snapshot1 . thread snapshot2 . thread
if AccessSnapshot . is_unprotected other_snapshot then
in
TraceElem . is_write other_snapshot . access && ThreadsDomain . is_any other_threads
let is_conflict { snapshot = other_snapshot ; threads = other_threads } =
else TraceElem . is_write other_snapshot . access && can_conflict snapshot other_snapshot
if AccessSnapshot . is_unprotected other_snapshot then
in
TraceElem . is_write other_snapshot . access && ThreadsDomain . is_any other_threads
List . find accesses ~ f : is_conflict
else TraceElem . is_write other_snapshot . access && can_conflict snapshot other_snapshot
| > Option . value_map ~ default : acc ~ f : ( fun conflict ->
in
(* protected read with conflicting unprotected write ( s ) . warn. *)
List . find accesses ~ f : is_conflict
let make_description =
| > Option . value_map ~ default : ( reported_acc , issue_log ) ~ f : ( fun conflict ->
make_read_write_race_description ~ read_is_sync : true conflict
(* protected read with conflicting unprotected write ( s ) . warn. *)
in
let make_description =
let report_kind = ReadWriteRace conflict . snapshot . access in
make_read_write_race_description ~ read_is_sync : true conflict
report_thread_safety_violation ~ acc ~ make_description ~ report_kind reported_access
in
)
let report_kind = ReadWriteRace conflict . snapshot . access in
let issue_log =
report_thread_safety_violation ~ issue_log ~ make_description ~ report_kind
reported_access
in
( update_reported reported_access reported_acc , issue_log ) )
in
in
let report_accesses_on_location reportable_accesses init =
let report_accesses_on_location reportable_accesses init =
(* Don't report on location if all accesses are on non-concurrent contexts *)
(* Don't report on location if all accesses are on non-concurrent contexts *)
@ -1126,14 +1128,11 @@ let report_unsafe_accesses ~issue_log classname (aggregated_access_map : ReportM
in
in
let report_guardedby_violations_on_location grouped_accesses init =
let report_guardedby_violations_on_location grouped_accesses init =
if Config . racerd_guardedby then
if Config . racerd_guardedby then
List . fold grouped_accesses ~ init ~ f : ( fun ( acc , issue_log ) r ->
List . fold grouped_accesses ~ init ~ f : ( fun acc r ->
if should_report_guardedby_violation classname r && not ( is_duplicate_report r acc ) then
if should_report_guardedby_violation classname r then
let issue_log =
report_thread_safety_violation ~ acc ~ report_kind : GuardedByViolation
report_thread_safety_violation ~ issue_log ~ report_kind : GuardedByViolation
~ make_description : make_guardedby_violation_description r
~ make_description : make_guardedby_violation_description r
else acc )
in
( update_reported r acc , issue_log )
else ( acc , issue_log ) )
else init
else init
in
in
let report grouped_accesses ( reported , issue_log ) =
let report grouped_accesses ( reported , issue_log ) =