diff --git a/infer/src/IR/ProcnameDispatcher.ml b/infer/src/IR/ProcnameDispatcher.ml index 63fc627ae..0422079e5 100644 --- a/infer/src/IR/ProcnameDispatcher.ml +++ b/infer/src/IR/ProcnameDispatcher.ml @@ -42,6 +42,8 @@ let template_args_of_template_spec_info = function args +exception DoNotHandleJavaYet + let templated_name_of_class_name class_name = let open Typ in match class_name with @@ -50,7 +52,7 @@ let templated_name_of_class_name class_name = | CppClass (qual_name, template_spec_info) -> (qual_name, template_args_of_template_spec_info template_spec_info) | JavaClass _ -> - assert false + raise DoNotHandleJavaYet (** Little abstraction over arguments: currently actual args, we'll want formal args later *) @@ -127,7 +129,8 @@ type ('arg_in, 'arg_out, 'f_in, 'f_out) arg_preparer = type ('f_in, 'f_out, 'captured_types, 'markers) func_arg = {eat_func_arg: ('f_in, 'f_out, 'captured_types) on_args; marker_static_checker: 'markers -> bool} -type 'f matcher = Typ.Procname.t -> FuncArg.t list -> 'f option +type 'f matcher = + {on_objc_cpp: objc_cpp -> FuncArg.t list -> 'f option; on_c: c -> FuncArg.t list -> 'f option} type 'f pre_result = DoesNotMatch | Matches of 'f | RetryWith of 'f matcher @@ -135,15 +138,6 @@ let pre_bind_opt opt ~f = match opt with None -> DoesNotMatch | Some x -> f x let pre_map_opt opt ~f = match opt with None -> DoesNotMatch | Some x -> Matches (f x) -let pre_to_opt procname args = function - | DoesNotMatch -> - None - | Matches x -> - Some x - | RetryWith f -> - f procname args - - type ('f_in, 'f_out, 'captured_types) func_args_end = on_args:('f_in, 'f_out, 'captured_types) on_args -> FuncArg.t list -> 'f_in * 'captured_types -> 'f_out pre_result @@ -152,12 +146,11 @@ type ('f_in, 'f_out) all_args_matcher = { on_objc_cpp: 'f_in -> objc_cpp -> FuncArg.t list -> 'f_out pre_result ; on_c: 'f_in -> c -> FuncArg.t list -> 'f_out pre_result } -type 'f typ_matcher = Typ.name -> 'f option +type 'f typ_matcher = {on_templated_name: templated_name -> 'f option} -(* they are actually just the same thing *) -type 'f dispatcher = 'f matcher +type 'f dispatcher = Typ.Procname.t -> FuncArg.t list -> 'f option -type 'f typ_dispatcher = 'f typ_matcher +type 'f typ_dispatcher = Typ.name -> 'f option (* Combinators *) @@ -551,21 +544,46 @@ module Procname = struct let make_matcher : ('f_in, 'f_out) all_args_matcher -> 'f_in -> 'f_out matcher = fun m f -> let {on_c; on_objc_cpp} : (_, _) all_args_matcher = m in + let on_objc_cpp objc_cpp args = + match on_objc_cpp f objc_cpp args with + | DoesNotMatch -> + None + | Matches res -> + Some res + | RetryWith {on_objc_cpp} -> + on_objc_cpp objc_cpp args + in + let on_c c args = + match on_c f c args with + | DoesNotMatch -> + None + | Matches res -> + Some res + | RetryWith {on_c} -> + on_c c args + in + {on_objc_cpp; on_c} + + + (** Simple implementation of a dispatcher, could be optimized later *) + let make_dispatcher : 'f matcher list -> 'f dispatcher = + fun matchers -> + let on_objc_cpp objc_cpp args = + List.find_map matchers ~f:(fun (matcher: _ matcher) -> matcher.on_objc_cpp objc_cpp args) + in + let on_c c args = + List.find_map matchers ~f:(fun (matcher: _ matcher) -> matcher.on_c c args) + in fun procname args -> match procname with | ObjC_Cpp objc_cpp -> - on_objc_cpp f objc_cpp args |> pre_to_opt procname args + on_objc_cpp objc_cpp args | C c -> - on_c f c args |> pre_to_opt procname args + on_c c args | _ -> None - (** Simple implementation of a dispatcher, could be optimized later *) - let make_dispatcher : 'f matcher list -> 'f dispatcher = - fun matchers procname args -> List.find_map matchers ~f:(fun matcher -> matcher procname args) - - (* Function args *) let no_marker_checker _markers = true @@ -607,7 +625,7 @@ module Procname = struct (** Matches the type matched by the given path_matcher *) let match_typ : (_, _, unit, unit, unit, non_empty) path_matcher -> (_, _) one_arg_matcher = fun m -> - let {on_templated_name} = m in + let {on_templated_name} : (_, _, unit, unit, unit, non_empty) path_matcher = m in let rec match_typ typ = match typ with | {Typ.desc= Tstruct name} -> @@ -729,17 +747,24 @@ module Procname = struct (** Retries matching with another matcher *) - let args_end_retry : _ -> (_, _, _) func_args_end = fun f ~on_args:_ _args _f_capt -> RetryWith f + let args_end_retry : _ matcher -> (_, _, _) func_args_end = + fun m ~on_args:_ _args _f_capt -> RetryWith m + (** Retries matching with another matcher if the function does not have the exact number/types of args *) - let exact_args_or_retry : 'f -> (_, _, _) func_args_end = - fun f -> alternative_args_end no_args_left (args_end_retry f) + let exact_args_or_retry : 'f matcher -> (_, _, _) func_args_end = + fun m -> alternative_args_end no_args_left (args_end_retry m) - let wrong_args_internal_error procname _args = - Logging.(die InternalError) - "Unexpected number/types of arguments for %a" Typ.Procname.pp procname + let wrong_args_internal_error : _ matcher = + let on_procname procname = + Logging.(die InternalError) + "Unexpected number/types of arguments for %a" Typ.Procname.pp procname + in + let on_c c _args = on_procname (C c) in + let on_objc_cpp objc_cpp _args = on_procname (ObjC_Cpp objc_cpp) in + {on_c; on_objc_cpp} let ( $! ) path_matcher () = args_begin path_matcher @@ -794,13 +819,21 @@ module TypName = struct let make_matcher : ('f_in, 'f_out, _, _, _, non_empty) path_matcher -> 'f_in -> 'f_out typ_matcher = fun m f -> - let {on_templated_name} = m in - function - | name -> name |> templated_name_of_class_name |> on_templated_name f |> Option.map ~f:fst + let {on_templated_name} : ('f_in, 'f_out, _, _, _, non_empty) path_matcher = m in + let on_templated_name templated_name = + templated_name |> on_templated_name f |> Option.map ~f:fst + in + {on_templated_name} let make_dispatcher : 'f typ_matcher list -> 'f typ_dispatcher = - fun matchers typname -> List.find_map matchers ~f:(fun matcher -> matcher typname) + fun matchers typname -> + match templated_name_of_class_name typname with + | exception DoNotHandleJavaYet -> + None + | templated_name -> + List.find_map matchers ~f:(fun (matcher: _ typ_matcher) -> + matcher.on_templated_name templated_name ) let ( &-->! ) path_matcher f = make_matcher path_matcher f diff --git a/infer/src/IR/ProcnameDispatcher.mli b/infer/src/IR/ProcnameDispatcher.mli index a152ebc32..5af17714f 100644 --- a/infer/src/IR/ProcnameDispatcher.mli +++ b/infer/src/IR/ProcnameDispatcher.mli @@ -46,13 +46,13 @@ type ('f_in, 'f_proc_out, 'f_out, 'captured_types, 'markers) args_matcher type ('arg_in, 'arg_out, 'f_in, 'f_out, 'captured_types, 'markers) one_arg -type 'f matcher = Typ.Procname.t -> FuncArg.t list -> 'f option +type 'f matcher -type 'f dispatcher = 'f matcher +type 'f dispatcher = Typ.Procname.t -> FuncArg.t list -> 'f option -type 'f typ_matcher = Typ.name -> 'f option +type 'f typ_matcher -type 'f typ_dispatcher = 'f typ_matcher +type 'f typ_dispatcher = Typ.name -> 'f option (* A matcher is a rule associating a function [f] to a [C/C++ function/method]: - [C/C++ function/method] --> [f] diff --git a/infer/src/checkers/registerCheckers.ml b/infer/src/checkers/registerCheckers.ml index 766c5e96e..8c37f8df6 100644 --- a/infer/src/checkers/registerCheckers.ml +++ b/infer/src/checkers/registerCheckers.ml @@ -44,7 +44,9 @@ let all_checkers = ; (DynamicDispatch Interproc.analyze_procedure, Language.Java) ] } ; { name= "buffer overrun" ; active= Config.bufferoverrun - ; callbacks= [(Procedure BufferOverrunChecker.checker, Language.Clang)] } + ; callbacks= + [ (Procedure BufferOverrunChecker.checker, Language.Clang) + ; (Procedure BufferOverrunChecker.checker, Language.Java) ] } ; { name= "crashcontext" ; active= Config.crashcontext ; callbacks= [(Procedure BoundedCallTree.checker, Language.Java)] }