[racerd] cleanups in reporting function

Summary:
There were several lists constructed unnecessarily -- replaced them with find_maps
and hopefully simplified the logic.

Reviewed By: mbouaziz, jvillard

Differential Revision: D12823559

fbshipit-source-id: 1f06b20f3
master
Nikos Gorogiannis 6 years ago committed by Facebook Github Bot
parent 5653dfac32
commit 77f7e70417

@ -1169,51 +1169,42 @@ let report_unsafe_accesses (aggregated_access_map : ReportMap.t) =
if is_duplicate_report snapshot.access pname reported_acc then reported_acc
else
match TraceElem.kind snapshot.access with
| Access.InterfaceCall unannoted_call_pname ->
| Access.InterfaceCall unannoted_call_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 tenv procdesc snapshot.access threads
unannoted_call_pname ;
update_reported snapshot.access pname reported_acc
| Access.InterfaceCall _ ->
reported_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
conflict with and report them *)
List.find_map accesses ~f:(fun {snapshot= other_snapshot; threads= other_threads} ->
if TraceElem.is_write other_snapshot.access && ThreadsDomain.is_any other_threads
then Some other_snapshot.access
else None )
in
if
AccessSnapshot.is_unprotected snapshot
&& ThreadsDomain.is_any threads
&& is_marked_thread_safe procdesc tenv
&& (Option.is_some conflict || ThreadsDomain.is_any threads)
then (
(* un-annotated interface call + no lock in method marked thread-safe. warn *)
report_unannotated_interface_violation tenv procdesc snapshot.access threads
unannoted_call_pname ;
report_thread_safety_violation tenv procdesc
~make_description:make_unprotected_write_description
~report_kind:(WriteWriteRace conflict) snapshot.access threads wobbly_paths ;
update_reported snapshot.access pname reported_acc )
else reported_acc
| Access.Write _ | ContainerWrite _ -> (
match Procdesc.get_proc_name procdesc with
| Java _ ->
let writes_on_background_thread =
if ThreadsDomain.is_any threads then
(* unprotected write in method that may run in parallel with itself. warn *)
[]
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
conflict with and report them *)
List.filter_map
~f:(fun {snapshot= other_snapshot; threads= other_threads} ->
if
TraceElem.is_write other_snapshot.access
&& ThreadsDomain.is_any other_threads
then Some other_snapshot.access
else None )
accesses
in
if
AccessSnapshot.is_unprotected snapshot
&& ((not (List.is_empty writes_on_background_thread)) || ThreadsDomain.is_any threads)
then (
let conflict = List.hd writes_on_background_thread in
report_thread_safety_violation tenv procdesc
~make_description:make_unprotected_write_description
~report_kind:(WriteWriteRace conflict) snapshot.access threads wobbly_paths ;
update_reported snapshot.access pname reported_acc )
else reported_acc
| _ ->
(* Do not report unprotected writes when an access can't run in parallel with itself, or
for ObjC_Cpp *)
reported_acc )
| Access.Write _ | ContainerWrite _ ->
(* Do not report unprotected writes for ObjC_Cpp *)
reported_acc
| (Access.Read _ | ContainerRead _) when AccessSnapshot.is_unprotected snapshot ->
(* unprotected read. report all writes as conflicts for java. for c++ filter out
unprotected writes *)
@ -1239,25 +1230,21 @@ let report_unsafe_accesses (aggregated_access_map : ReportMap.t) =
if snapshot1.lock && snapshot2.lock then false
else ThreadsDomain.can_conflict snapshot1.thread snapshot2.thread
in
let conflicting_writes =
List.filter
~f:(fun {snapshot= other_snapshot; threads= other_threads} ->
if AccessSnapshot.is_unprotected other_snapshot then
TraceElem.is_write other_snapshot.access && ThreadsDomain.is_any other_threads
else
TraceElem.is_write other_snapshot.access && can_conflict snapshot other_snapshot
)
accesses
let is_conflict {snapshot= other_snapshot; threads= other_threads} =
if AccessSnapshot.is_unprotected other_snapshot then
TraceElem.is_write other_snapshot.access && ThreadsDomain.is_any other_threads
else TraceElem.is_write other_snapshot.access && can_conflict snapshot other_snapshot
in
if not (List.is_empty conflicting_writes) then (
let conflict = List.hd_exn conflicting_writes in
(* protected read with conflicting unprotected write(s). warn. *)
report_thread_safety_violation tenv procdesc
~make_description:(make_read_write_race_description ~read_is_sync:true conflict)
~report_kind:(ReadWriteRace conflict.snapshot.access) snapshot.access threads
wobbly_paths ;
update_reported snapshot.access pname reported_acc )
else reported_acc
List.find accesses ~f:is_conflict
|> Option.value_map ~default:reported_acc ~f:(fun conflict ->
(* protected read with conflicting unprotected write(s). warn. *)
let make_description =
make_read_write_race_description ~read_is_sync:true conflict
in
let report_kind = ReadWriteRace conflict.snapshot.access in
report_thread_safety_violation tenv procdesc ~make_description ~report_kind
snapshot.access threads wobbly_paths ;
update_reported snapshot.access pname reported_acc )
in
let report_accesses_on_location (grouped_accesses : reported_access list) reported_acc =
(* reset the reported reads and writes for each memory location *)

Loading…
Cancel
Save