diff --git a/infer/src/checkers/Sink.ml b/infer/src/checkers/Sink.ml index cd09f8fdb..dac648f32 100644 --- a/infer/src/checkers/Sink.ml +++ b/infer/src/checkers/Sink.ml @@ -11,13 +11,13 @@ module F = Format module type Kind = sig include TraceElem.Kind - val get : Typ.Procname.t -> HilExp.t list -> CallFlags.t -> Tenv.t -> (t * IntSet.t) option + val get : Typ.Procname.t -> HilExp.t list -> CallFlags.t -> Tenv.t -> (t * IntSet.t) list end module type S = sig include TraceElem.S - val get : CallSite.t -> HilExp.t list -> CallFlags.t -> Tenv.t -> t option + val get : CallSite.t -> HilExp.t list -> CallFlags.t -> Tenv.t -> t list val indexes : t -> IntSet.t @@ -38,11 +38,8 @@ module Make (Kind : Kind) = struct let make ?(indexes = IntSet.empty) kind site = {kind; site; indexes} let get site actuals call_flags tenv = - match Kind.get (CallSite.pname site) actuals call_flags tenv with - | Some (kind, indexes) -> - Some {kind; site; indexes} - | None -> - None + Kind.get (CallSite.pname site) actuals call_flags tenv + |> List.rev_map ~f:(fun (kind, indexes) -> {kind; site; indexes}) let with_callsite t callee_site = {t with site= callee_site} diff --git a/infer/src/checkers/Sink.mli b/infer/src/checkers/Sink.mli index f6a9d5fa9..bbc3197f1 100644 --- a/infer/src/checkers/Sink.mli +++ b/infer/src/checkers/Sink.mli @@ -10,14 +10,14 @@ open! IStd module type Kind = sig include TraceElem.Kind - val get : Typ.Procname.t -> HilExp.t list -> CallFlags.t -> Tenv.t -> (t * IntSet.t) option + val get : Typ.Procname.t -> HilExp.t list -> CallFlags.t -> Tenv.t -> (t * IntSet.t) list (** return Some kind if the given procname/actuals are a sink, None otherwise *) end module type S = sig include TraceElem.S - val get : CallSite.t -> HilExp.t list -> CallFlags.t -> Tenv.t -> t option + val get : CallSite.t -> HilExp.t list -> CallFlags.t -> Tenv.t -> t list (** return Some sink if the given call site/actuals are a sink, None otherwise *) val indexes : t -> IntSet.t diff --git a/infer/src/checkers/SinkTrace.ml b/infer/src/checkers/SinkTrace.ml index 8cc4e1dfd..7effb7074 100644 --- a/infer/src/checkers/SinkTrace.ml +++ b/infer/src/checkers/SinkTrace.ml @@ -32,7 +32,7 @@ end module MakeSink (TraceElem : TraceElem.S) = struct include TraceElem - let get _ _ _ _ = None + let get _ _ _ _ = [] let indexes _ = IntSet.empty diff --git a/infer/src/quandary/ClangTrace.ml b/infer/src/quandary/ClangTrace.ml index 9ec14a8fa..a68da2fab 100644 --- a/infer/src/quandary/ClangTrace.ml +++ b/infer/src/quandary/ClangTrace.ml @@ -239,7 +239,7 @@ module SinkKind = struct (* taint the nth parameter (0-indexed) *) let taint_nth n kind actuals = - if n < List.length actuals then Some (kind, IntSet.singleton n) else None + if n < List.length actuals then [(kind, IntSet.singleton n)] else [] (* taint all parameters after the nth (exclusive) *) @@ -248,13 +248,13 @@ module SinkKind = struct List.filter_mapi ~f:(fun actual_num _ -> Option.some_if (actual_num > n) actual_num) actuals with | [] -> - None + [] | to_taint -> - Some (kind, IntSet.of_list to_taint) + [(kind, IntSet.of_list to_taint)] let taint_all kind actuals = - Some (kind, IntSet.of_list (List.mapi ~f:(fun actual_num _ -> actual_num) actuals)) + [(kind, IntSet.of_list (List.mapi ~f:(fun actual_num _ -> actual_num) actuals))] (* return Some(sink kind) if [procedure_name] is in the list of externally specified sinks *) @@ -266,12 +266,14 @@ module SinkKind = struct let kind = of_string kind in try let n = int_of_string index in - taint_nth n kind actuals + let taint = taint_nth n kind actuals in + Option.some_if (not (List.is_empty taint)) taint with Failure _ -> (* couldn't parse the index, just taint everything *) - taint_all kind actuals + Some (taint_all kind actuals) else None ) external_sinks + |> Option.value ~default:[] let get pname actuals _ _ = @@ -326,13 +328,13 @@ module SinkKind = struct | Some (Const.Cint i) -> (* check if the data kind might be CURLOPT_URL *) IntLit.to_int i - |> Option.bind ~f:(fun n -> - if controls_request n then taint_after_nth 1 URL actuals else None ) + |> Option.value_map ~default:[] ~f:(fun n -> + if controls_request n then taint_after_nth 1 URL actuals else [] ) | _ -> (* can't statically resolve data kind; taint it just in case *) taint_after_nth 1 URL actuals ) | None -> - None ) + [] ) | "execl" | "execlp" | "execle" | "execv" | "execve" | "execvp" | "system" -> taint_all ShellExec actuals | "openat" -> @@ -353,7 +355,7 @@ module SinkKind = struct | _ -> get_external_sink pname actuals ) | Typ.Procname.Block _ -> - None + [] | pname -> L.(die InternalError) "Non-C++ procname %a in C++ analysis" Typ.Procname.pp pname diff --git a/infer/src/quandary/JavaTrace.ml b/infer/src/quandary/JavaTrace.ml index 3bd09e5a5..210e9683d 100644 --- a/infer/src/quandary/JavaTrace.ml +++ b/infer/src/quandary/JavaTrace.ml @@ -331,12 +331,12 @@ module SinkKind = struct let indexes = IntSet.of_list (List.mapi ~f:(fun param_num _ -> param_num + offset) actuals_to_taint) in - Some (kind, indexes) + Some [(kind, indexes)] in (* taint the nth non-"this" parameter (0-indexed) *) let taint_nth n kind = let first_index = if Typ.Procname.Java.is_static java_pname then n else n + 1 in - if first_index < List.length actuals then Some (kind, IntSet.singleton first_index) + if first_index < List.length actuals then Some [(kind, IntSet.singleton first_index)] else None in let get_external_sink class_name method_name = @@ -444,8 +444,9 @@ module SinkKind = struct in PatternMatch.supertype_find_map_opt tenv taint_matching_supertype (Typ.Name.Java.from_string (Typ.Procname.Java.get_class_name java_pname)) + |> Option.value ~default:[] | pname when BuiltinDecl.is_declared pname -> - None + [] | pname -> L.(die InternalError) "Non-Java procname %a in Java analysis" Typ.Procname.pp pname diff --git a/infer/src/quandary/TaintAnalysis.ml b/infer/src/quandary/TaintAnalysis.ml index 8a32a77d5..245b8626f 100644 --- a/infer/src/quandary/TaintAnalysis.ml +++ b/infer/src/quandary/TaintAnalysis.ml @@ -468,11 +468,8 @@ module Make (TaintSpecification : TaintSpec.S) = struct proc_data.ProcData.tenv in let astate_acc_result = - match sinks with - | None -> - astate_acc - | Some sink -> - add_sink sink dummy_actuals astate proc_data dummy_call_site + List.fold sinks ~init:astate_acc ~f:(fun astate sink -> + add_sink sink dummy_actuals astate proc_data dummy_call_site ) in add_sinks_for_access astate_acc_result ae in @@ -671,13 +668,11 @@ module Make (TaintSpecification : TaintSpec.S) = struct let astate_with_sink = if List.is_empty actuals then astate else - match + let sinks = TraceDomain.Sink.get call_site actuals call_flags proc_data.ProcData.tenv - with - | Some sink -> - add_sink sink actuals astate proc_data call_site - | None -> - astate + in + List.fold sinks ~init:astate ~f:(fun astate sink -> + add_sink sink actuals astate proc_data call_site ) in let astate_with_summary = let sources = TraceDomain.Source.get call_site actuals proc_data.tenv in diff --git a/infer/src/unit/TaintTests.ml b/infer/src/unit/TaintTests.ml index 228a34a23..118c970e3 100644 --- a/infer/src/unit/TaintTests.ml +++ b/infer/src/unit/TaintTests.ml @@ -32,8 +32,8 @@ module MockTrace = Trace.Make (struct let get pname _ _ _ = if String.is_prefix ~prefix:"SINK" (Typ.Procname.to_string pname) then - Some (CallSite.make pname Location.dummy, IntSet.singleton 0) - else None + [(CallSite.make pname Location.dummy, IntSet.singleton 0)] + else [] end) module Sanitizer = Sanitizer.Dummy