From 87b3907628782d61df0cf0d27bcc2b5714540783 Mon Sep 17 00:00:00 2001 From: Mehdi Bouaziz Date: Thu, 13 Dec 2018 07:51:42 -0800 Subject: [PATCH] [quandary] Allow several kinds for external sources/sinks Reviewed By: ngorogiannis Differential Revision: D13417113 fbshipit-source-id: 0838c5704 --- infer/src/quandary/ClangTrace.ml | 79 ++++++++-------- infer/src/quandary/JavaTrace.ml | 91 ++++++++++--------- infer/src/quandary/QuandaryConfig.ml | 21 +++-- infer/src/quandary/QuandaryConfig.mli | 4 +- .../codetoanalyze/java/quandary/.inferconfig | 2 +- .../codetoanalyze/java/quandary/issues.exp | 5 + 6 files changed, 114 insertions(+), 88 deletions(-) diff --git a/infer/src/quandary/ClangTrace.ml b/infer/src/quandary/ClangTrace.ml index d08e600a3..7f8fbd8c7 100644 --- a/infer/src/quandary/ClangTrace.ml +++ b/infer/src/quandary/ClangTrace.ml @@ -9,8 +9,8 @@ open! IStd module F = Format module L = Logging -let parse_clang_procedure procedure kind index = - try Some (QualifiedCppName.Match.of_fuzzy_qual_names [procedure], kind, index) +let parse_clang_procedure procedure kinds index = + try Some (QualifiedCppName.Match.of_fuzzy_qual_names [procedure], kinds, index) with QualifiedCppName.ParseError _ -> (* Java and Clang sources/sinks live in the same inferconfig entry. If we try to parse a Java procedure that happens to be an invalid Clang qualified name (e.g., MyClass.), @@ -49,21 +49,21 @@ module SourceKind = struct let external_sources = List.filter_map - ~f:(fun {QuandaryConfig.Source.procedure; kind; index} -> - parse_clang_procedure procedure kind index ) + ~f:(fun {QuandaryConfig.Source.procedure; kinds; index} -> + parse_clang_procedure procedure kinds index ) (QuandaryConfig.Source.of_json Config.quandary_sources) let endpoints = String.Set.of_list (QuandaryConfig.Endpoint.of_json Config.quandary_endpoints) - (* return Some(source kind) if [procedure_name] is in the list of externally specified sources *) + (* return a list of source kinds if [procedure_name] is in the list of externally specified sources *) let get_external_source qualified_pname = let return = None in - List.filter_map external_sources ~f:(fun (qualifiers, kind, index) -> + List.concat_map external_sources ~f:(fun (qualifiers, kinds, index) -> if QualifiedCppName.Match.match_qualifiers qualifiers qualified_pname then let source_index = try Some (int_of_string index) with Failure _ -> return in - Some (of_string kind, source_index) - else None ) + List.rev_map kinds ~f:(fun kind -> (of_string kind, source_index)) + else [] ) let get pname actuals tenv = @@ -235,45 +235,50 @@ module SinkKind = struct let external_sinks = List.filter_map - ~f:(fun {QuandaryConfig.Sink.procedure; kind; index} -> - parse_clang_procedure procedure kind index ) + ~f:(fun {QuandaryConfig.Sink.procedure; kinds; index} -> + parse_clang_procedure procedure kinds index ) (QuandaryConfig.Sink.of_json Config.quandary_sinks) (* taint the nth parameter (0-indexed) *) - let taint_nth n kind actuals = - if n < List.length actuals then [(kind, IntSet.singleton n)] else [] + let taint_nth n kinds actuals = + if n < List.length actuals then + let indexes = IntSet.singleton n in + List.rev_map kinds ~f:(fun kind -> (kind, indexes)) + else [] (* taint all parameters after the nth (exclusive) *) - let taint_after_nth n kind actuals = + let taint_after_nth n kinds actuals = match List.filter_mapi ~f:(fun actual_num _ -> Option.some_if (actual_num > n) actual_num) actuals with | [] -> [] | to_taint -> - [(kind, IntSet.of_list to_taint)] + let indexes = IntSet.of_list to_taint in + List.rev_map kinds ~f:(fun kind -> (kind, indexes)) - let taint_all kind actuals = - [(kind, IntSet.of_list (List.mapi ~f:(fun actual_num _ -> actual_num) actuals))] + let taint_all kinds actuals = + let indexes = IntSet.of_list (List.mapi ~f:(fun actual_num _ -> actual_num) actuals) in + List.rev_map kinds ~f:(fun kind -> (kind, indexes)) - (* return Some(sink kind) if [procedure_name] is in the list of externally specified sinks *) + (* return Some(sink kinds) if [procedure_name] is in the list of externally specified sinks *) let get_external_sink pname actuals = let qualified_pname = Typ.Procname.get_qualifiers pname in List.find_map - ~f:(fun (qualifiers, kind, index) -> + ~f:(fun (qualifiers, kinds, index) -> if QualifiedCppName.Match.match_qualifiers qualifiers qualified_pname then - let kind = of_string kind in + let kinds = List.rev_map ~f:of_string kinds in try let n = int_of_string index in - let taint = taint_nth n kind actuals in + let taint = taint_nth n kinds actuals in Option.some_if (not (List.is_empty taint)) taint with Failure _ -> (* couldn't parse the index, just taint everything *) - Some (taint_all kind actuals) + Some (taint_all kinds actuals) else None ) external_sinks |> Option.value ~default:[] @@ -301,24 +306,24 @@ module SinkKind = struct with | ( ["std"; ("basic_fstream" | "basic_ifstream" | "basic_ofstream")] , ("basic_fstream" | "basic_ifstream" | "basic_ofstream" | "open") ) -> - taint_nth 1 CreateFile actuals + taint_nth 1 [CreateFile] actuals | _, "operator[]" when Config.developer_mode && is_buffer_like pname -> - taint_nth 1 BufferAccess actuals + taint_nth 1 [BufferAccess] actuals | _ -> get_external_sink pname actuals ) | Typ.Procname.C _ when String.is_substring ~substring:"SetCommandLineOption" (Typ.Procname.to_string pname) -> - taint_nth 1 EnvironmentChange actuals + taint_nth 1 [EnvironmentChange] actuals | Typ.Procname.C _ when Config.developer_mode && Typ.Procname.equal pname BuiltinDecl.__array_access -> - taint_all BufferAccess actuals + taint_all [BufferAccess] actuals | Typ.Procname.C _ when Typ.Procname.equal pname BuiltinDecl.__set_array_length -> (* called when creating a stack-allocated array *) - taint_nth 1 StackAllocation actuals + taint_nth 1 [StackAllocation] actuals | Typ.Procname.C _ -> ( match Typ.Procname.to_string pname with | "creat" | "fopen" | "freopen" | "open" -> - taint_nth 0 CreateFile actuals + taint_nth 0 [CreateFile] actuals | "curl_easy_setopt" -> ( (* magic constant for setting request URL *) let controls_request = function @@ -335,31 +340,31 @@ module SinkKind = struct (* check if the data kind might be CURLOPT_URL *) IntLit.to_int i |> Option.value_map ~default:[] ~f:(fun n -> - if controls_request n then taint_after_nth 1 URL actuals else [] ) + 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 ) + taint_after_nth 1 [URL] actuals ) | None -> [] ) | "execl" | "execlp" | "execle" | "execv" | "execve" | "execvp" | "system" -> - taint_all ShellExec actuals + taint_all [ShellExec] actuals | "openat" -> - taint_nth 1 CreateFile actuals + taint_nth 1 [CreateFile] actuals | "popen" -> - taint_nth 0 ShellExec actuals + taint_nth 0 [ShellExec] actuals | "putenv" -> - taint_nth 0 EnvironmentChange actuals + taint_nth 0 [EnvironmentChange] actuals | ("brk" | "calloc" | "malloc" | "realloc" | "sbrk") when Config.developer_mode -> - taint_all HeapAllocation actuals + taint_all [HeapAllocation] actuals | "rename" -> - taint_all CreateFile actuals + taint_all [CreateFile] actuals | "strcpy" when Config.developer_mode -> (* warn if source array is tainted *) - taint_nth 1 BufferAccess actuals + taint_nth 1 [BufferAccess] actuals | ("memcpy" | "memmove" | "memset" | "strncpy" | "wmemcpy" | "wmemmove") when Config.developer_mode -> (* warn if count argument is tainted *) - taint_nth 2 BufferAccess actuals + taint_nth 2 [BufferAccess] actuals | _ -> get_external_sink pname actuals ) | Typ.Procname.Block _ -> diff --git a/infer/src/quandary/JavaTrace.ml b/infer/src/quandary/JavaTrace.ml index a9e2c0425..a6e55a448 100644 --- a/infer/src/quandary/JavaTrace.ml +++ b/infer/src/quandary/JavaTrace.ml @@ -42,7 +42,7 @@ module SourceKind = struct let external_sources = List.map - ~f:(fun {QuandaryConfig.Source.procedure; kind} -> (Str.regexp procedure, kind)) + ~f:(fun {QuandaryConfig.Source.procedure; kinds} -> (Str.regexp procedure, kinds)) (QuandaryConfig.Source.of_json Config.quandary_sources) @@ -65,9 +65,10 @@ module SourceKind = struct (* check the list of externally specified sources *) let procedure = class_name ^ "." ^ method_name in let sources = - List.filter_map external_sources ~f:(fun (procedure_regex, kind) -> - if Str.string_match procedure_regex procedure 0 then Some (of_string kind, return) - else None ) + List.concat_map external_sources ~f:(fun (procedure_regex, kinds) -> + if Str.string_match procedure_regex procedure 0 then + List.rev_map kinds ~f:(fun kind -> (of_string kind, return)) + else [] ) in Option.some_if (not (List.is_empty sources)) sources in @@ -314,7 +315,7 @@ module SinkKind = struct let external_sinks = List.map - ~f:(fun {QuandaryConfig.Sink.procedure; kind; index} -> (Str.regexp procedure, kind, index)) + ~f:(fun {QuandaryConfig.Sink.procedure; kinds; index} -> (Str.regexp procedure, kinds, index)) (QuandaryConfig.Sink.of_json Config.quandary_sinks) @@ -323,7 +324,7 @@ module SinkKind = struct | Typ.Procname.Java java_pname -> (* taint all the inputs of [pname]. for non-static procedures, taints the "this" parameter only if [taint_this] is true. *) - let taint_all ?(taint_this = false) kind = + let taint_all ?(taint_this = false) kinds = let actuals_to_taint, offset = if Typ.Procname.Java.is_static java_pname || taint_this then (actuals, 0) else (List.tl_exn actuals, 1) @@ -331,42 +332,48 @@ 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 (List.rev_map kinds ~f:(fun kind -> (kind, indexes))) in (* taint the nth non-"this" parameter (0-indexed) *) - let taint_nth n kind = + let taint_nth n kinds = 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 + let first_index = IntSet.singleton first_index in + Some (List.rev_map kinds ~f:(fun kind -> (kind, first_index))) else None in let get_external_sink class_name method_name = (* check the list of externally specified sinks *) let procedure = class_name ^ "." ^ method_name in - List.find_map - ~f:(fun (procedure_regex, kind, index) -> - if Str.string_match procedure_regex procedure 0 then - let kind = of_string kind in - try - let n = int_of_string index in - taint_nth n kind - with Failure _ -> - (* couldn't parse the index, just taint everything *) - taint_all kind - else None ) - external_sinks + let sinks = + List.concat_map external_sinks ~f:(fun (procedure_regex, kinds, index) -> + if Str.string_match procedure_regex procedure 0 then + let kinds = List.rev_map ~f:of_string kinds in + let taints = + try + let n = int_of_string index in + taint_nth n kinds + with Failure _ -> + (* couldn't parse the index, just taint everything *) + taint_all kinds + in + Option.value taints ~default:[] + else [] ) + in + Option.some_if (not (List.is_empty sinks)) sinks in let method_name = Typ.Procname.Java.get_method java_pname in let taint_matching_supertype typename = match (Typ.Name.name typename, method_name) with | "android.app.Activity", ("startActivityFromChild" | "startActivityFromFragment") -> - taint_nth 1 StartComponent + taint_nth 1 [StartComponent] | ( ( "android.app.Activity" | "android.content.Context" | "android.support.v4.app.Fragment" ) , "startIntentSenderForResult" ) -> - taint_nth 2 StartComponent + taint_nth 2 [StartComponent] | "android.app.Activity", "startIntentSenderFromChild" -> - taint_nth 3 StartComponent + taint_nth 3 [StartComponent] | ( ( "android.app.Fragment" | "android.content.Context" | "android.support.v4.app.Fragment" ) @@ -386,9 +393,9 @@ module SinkKind = struct | "startNextMatchingActivity" | "startService" | "stopService" ) ) -> - taint_nth 0 StartComponent + taint_nth 0 [StartComponent] | "android.content.Context", "startIntentSender" -> - taint_nth 1 StartComponent + taint_nth 1 [StartComponent] | ( "android.content.Intent" , ( "parseUri" | "getIntent" @@ -399,13 +406,13 @@ module SinkKind = struct | "setDataAndType" | "setDataAndTypeAndNormalize" | "setPackage" ) ) -> - taint_nth 0 CreateIntent + taint_nth 0 [CreateIntent] | "android.content.Intent", "setClassName" -> - taint_all CreateIntent + taint_all [CreateIntent] | "android.text.Html", "fromHtml" -> - taint_nth 0 HTML + taint_nth 0 [HTML] | "android.util.Log", ("e" | "println" | "w" | "wtf") -> - taint_all Logging + taint_all [Logging] | ( "android.webkit.WebView" , ( "evaluateJavascript" | "loadData" @@ -413,32 +420,32 @@ module SinkKind = struct | "loadUrl" | "postUrl" | "postWebMessage" ) ) -> - taint_all JavaScript + taint_all [JavaScript] | "com.facebook.infer.builtins.InferTaint", "inferSensitiveSink" -> - taint_nth 0 Other + taint_nth 0 [Other] | "java.io.File", "" | "java.nio.file.FileSystem", "getPath" | "java.nio.file.Paths", "get" -> - taint_all CreateFile + taint_all [CreateFile] | "java.io.ObjectInputStream", "" -> - taint_all Deserialization + taint_all [Deserialization] | "java.lang.Class", "forName" | "java.lang.ClassLoader", "loadClass" -> - taint_nth 0 ClassLoading + taint_nth 0 [ClassLoading] | "java.lang.ClassLoader", "defineClass" -> - taint_nth 1 ClassLoading + taint_nth 1 [ClassLoading] | "java.lang.ProcessBuilder", "" -> - taint_all ShellExec + taint_all [ShellExec] | "java.lang.ProcessBuilder", "command" -> - taint_all ShellExec + taint_all [ShellExec] | "java.lang.Runtime", "exec" -> - taint_nth 0 ShellExec + taint_nth 0 [ShellExec] (* TODO: separate non-injection sinks for PreparedStatement's *) | "java.sql.Statement", ("addBatch" | "execute") -> - taint_nth 0 SQLInjection + taint_nth 0 [SQLInjection] | "java.sql.Statement", "executeQuery" -> - taint_nth 0 SQLRead + taint_nth 0 [SQLRead] | "java.sql.Statement", ("executeUpdate" | "executeLargeUpdate") -> - taint_nth 0 SQLWrite + taint_nth 0 [SQLWrite] | class_name, method_name -> get_external_sink class_name method_name in diff --git a/infer/src/quandary/QuandaryConfig.ml b/infer/src/quandary/QuandaryConfig.ml index 093eb0c6b..648b55112 100644 --- a/infer/src/quandary/QuandaryConfig.ml +++ b/infer/src/quandary/QuandaryConfig.ml @@ -9,19 +9,28 @@ open! IStd (** utilities for importing JSON specifications of sources/sinks into Quandary *) +let get_kinds json = + let open Yojson.Basic in + match (Util.member "kinds" json, Util.member "kind" json) with + | `Null, kind -> + [Util.to_string kind] + | kinds, kind -> + (Util.to_string_option kind |> Option.to_list) @ Util.convert_each Util.to_string kinds + + module Source = struct - type t = {procedure: string; kind: string; index: string} + type t = {procedure: string; kinds: string list; index: string} let of_json = function | `List sources -> let parse_source json = let open Yojson.Basic in let procedure = Util.member "procedure" json |> Util.to_string in - let kind = Util.member "kind" json |> Util.to_string in + let kinds = get_kinds json in let index = Util.member "index" json |> Util.to_string_option |> Option.value ~default:"return" in - {procedure; kind; index} + {procedure; kinds; index} in List.map ~f:parse_source sources | _ -> @@ -29,18 +38,18 @@ module Source = struct end module Sink = struct - type t = {procedure: string; kind: string; index: string} + type t = {procedure: string; kinds: string list; index: string} let of_json = function | `List sinks -> let parse_sink json = let open Yojson.Basic in let procedure = Util.member "procedure" json |> Util.to_string in - let kind = Util.member "kind" json |> Util.to_string in + let kinds = get_kinds json in let index = Util.member "index" json |> Util.to_string_option |> Option.value ~default:"all" in - {procedure; kind; index} + {procedure; kinds; index} in List.map ~f:parse_sink sinks | _ -> diff --git a/infer/src/quandary/QuandaryConfig.mli b/infer/src/quandary/QuandaryConfig.mli index 66201d185..35a638afb 100644 --- a/infer/src/quandary/QuandaryConfig.mli +++ b/infer/src/quandary/QuandaryConfig.mli @@ -10,13 +10,13 @@ open! IStd (** utilities for importing JSON specifications of sources/sinks into Quandary*) module Source : sig - type t = {procedure: string; kind: string; index: string} + type t = {procedure: string; kinds: string list; index: string} val of_json : [> `List of Yojson.Basic.json list] -> t list end module Sink : sig - type t = {procedure: string; kind: string; index: string} + type t = {procedure: string; kinds: string list; index: string} val of_json : [> `List of Yojson.Basic.json list] -> t list end diff --git a/infer/tests/codetoanalyze/java/quandary/.inferconfig b/infer/tests/codetoanalyze/java/quandary/.inferconfig index 055db6a95..fc022b86a 100644 --- a/infer/tests/codetoanalyze/java/quandary/.inferconfig +++ b/infer/tests/codetoanalyze/java/quandary/.inferconfig @@ -7,7 +7,7 @@ }, { "procedure": "codetoanalyze.java.quandary.InterfaceSpec.source", - "kind": "PrivateData" + "kinds": ["PrivateData", "Other"] } ], "quandary-sinks": [ diff --git a/infer/tests/codetoanalyze/java/quandary/issues.exp b/infer/tests/codetoanalyze/java/quandary/issues.exp index 7f8df0761..5255d53c2 100644 --- a/infer/tests/codetoanalyze/java/quandary/issues.exp +++ b/infer/tests/codetoanalyze/java/quandary/issues.exp @@ -47,11 +47,16 @@ codetoanalyze/java/quandary/Exceptions.java, codetoanalyze.java.quandary.Excepti codetoanalyze/java/quandary/Exceptions.java, codetoanalyze.java.quandary.Exceptions.sinkInFinallyBad3():void, 7, QUANDARY_TAINT_ERROR, no_bucket, ERROR, [Return from Object InferTaint.inferSecretSource(),Call to void InferTaint.inferSensitiveSink(Object) with tainted index 0] codetoanalyze/java/quandary/ExternalSpecs.java, codetoanalyze.java.quandary.ConstructorSink.constructorSinkBad():codetoanalyze.java.quandary.ConstructorSink, 2, QUANDARY_TAINT_ERROR, no_bucket, ERROR, [Return from Object InferTaint.inferSecretSource(),Call to ConstructorSink.(Object) with tainted index 1] codetoanalyze/java/quandary/ExternalSpecs.java, codetoanalyze.java.quandary.ExternalSpecs.callExternalSink2Bad1():void, 1, LOGGING_PRIVATE_DATA, no_bucket, ERROR, [Return from Object ExternalSpecs.privateDataSource(),Call to void ExternalSpecs.loggingSink2(Object,Object) with tainted index 0] +codetoanalyze/java/quandary/ExternalSpecs.java, codetoanalyze.java.quandary.ExternalSpecs.callExternalSink2Bad1():void, 1, QUANDARY_TAINT_ERROR, no_bucket, ERROR, [Return from Object ExternalSpecs.privateDataSource(),Call to void ExternalSpecs.loggingSink2(Object,Object) with tainted index 0] codetoanalyze/java/quandary/ExternalSpecs.java, codetoanalyze.java.quandary.ExternalSpecs.callExternalSink2Bad2():void, 1, LOGGING_PRIVATE_DATA, no_bucket, ERROR, [Return from Object ExternalSpecs.privateDataSource(),Call to void ExternalSpecs.loggingSink2(Object,Object) with tainted index 1] +codetoanalyze/java/quandary/ExternalSpecs.java, codetoanalyze.java.quandary.ExternalSpecs.callExternalSink2Bad2():void, 1, QUANDARY_TAINT_ERROR, no_bucket, ERROR, [Return from Object ExternalSpecs.privateDataSource(),Call to void ExternalSpecs.loggingSink2(Object,Object) with tainted index 1] codetoanalyze/java/quandary/ExternalSpecs.java, codetoanalyze.java.quandary.ExternalSpecs.callExternalSinkBad():void, 1, LOGGING_PRIVATE_DATA, no_bucket, ERROR, [Return from Object ExternalSpecs.privateDataSource(),Call to void ExternalSpecs.loggingSink1(Object,Object) with tainted index 1] +codetoanalyze/java/quandary/ExternalSpecs.java, codetoanalyze.java.quandary.ExternalSpecs.callExternalSinkBad():void, 1, QUANDARY_TAINT_ERROR, no_bucket, ERROR, [Return from Object ExternalSpecs.privateDataSource(),Call to void ExternalSpecs.loggingSink1(Object,Object) with tainted index 1] codetoanalyze/java/quandary/ExternalSpecs.java, codetoanalyze.java.quandary.ExternalSpecs.callSinkThatPropagatesBad():void, 2, QUANDARY_TAINT_ERROR, no_bucket, ERROR, [Return from Object InferTaint.inferSecretSource(),Call to Object ExternalSpecs.sinkThatPropagates(Object) with tainted index 0] codetoanalyze/java/quandary/ExternalSpecs.java, codetoanalyze.java.quandary.ExternalSpecs.callSinkThatPropagatesBad():void, 3, QUANDARY_TAINT_ERROR, no_bucket, ERROR, [Return from Object InferTaint.inferSecretSource(),Call to void ExternalSpecs.loggingSink1(Object,Object) with tainted index 1] +codetoanalyze/java/quandary/ExternalSpecs.java, codetoanalyze.java.quandary.ExternalSpecs.externalSourceAsIntentOk(android.app.Activity):void, 1, QUANDARY_TAINT_ERROR, no_bucket, ERROR, [Return from Object ExternalSpecs.privateDataSource(),Call to void Activity.startActivity(Intent) with tainted index 1] codetoanalyze/java/quandary/ExternalSpecs.java, codetoanalyze.java.quandary.ExternalSpecs.logExternalSourceBad():void, 1, LOGGING_PRIVATE_DATA, no_bucket, ERROR, [Return from Object ExternalSpecs.privateDataSource(),Call to int Log.e(String,String) with tainted index 1] +codetoanalyze/java/quandary/ExternalSpecs.java, codetoanalyze.java.quandary.ExternalSpecs.logExternalSourceBad():void, 1, QUANDARY_TAINT_ERROR, no_bucket, ERROR, [Return from Object ExternalSpecs.privateDataSource(),Call to int Log.e(String,String) with tainted index 1] codetoanalyze/java/quandary/ExternalSpecs.java, codetoanalyze.java.quandary.ExternalSpecs.missedSanitizerBad():java.lang.Object, 3, QUANDARY_TAINT_ERROR, no_bucket, ERROR, [Return from Object InferTaint.inferSecretSource(),Call to void InferTaint.inferSensitiveSink(Object) with tainted index 0] codetoanalyze/java/quandary/ExternalSpecs.java, codetoanalyze.java.quandary.InterfaceSpecImpl.externalSpecBad():void, 1, LOGGING_PRIVATE_DATA, no_bucket, ERROR, [Return from Object InterfaceSpecImpl.source(),Call to void InterfaceSpecImpl.sink(Object) with tainted index 1] codetoanalyze/java/quandary/Fields.java, codetoanalyze.java.quandary.Fields.instanceFieldBad():void, 2, QUANDARY_TAINT_ERROR, no_bucket, ERROR, [Return from Object InferTaint.inferSecretSource(),Call to void InferTaint.inferSensitiveSink(Object) with tainted index 0]