[racerd] less boiler-plate in reporting violations

Summary: The pattern "check if an access has already been reported, otherwise see if it is a violation, report it, then add it to the set of reported accesses" is too much copy pasta.  Push that into the reporting functions.

Reviewed By: ezgicicek

Differential Revision: D16859208

fbshipit-source-id: 5370efd41
master
Nikos Gorogiannis 6 years ago committed by Facebook Github Bot
parent 6bd25fd9dd
commit 1bfbdbb4e1

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

Loading…
Cancel
Save