[ProcnameDispatcher] Optimization and do not crash with Java

Summary:
- small optimization by starting deconstructing procnames/types in the dispatcher rather than the matchers
- as a consequence, returns fast for unhandled constructs like Java procnames or types
- Java is still not handled but at least does not crash
- re-enable Inferbo for Java

Reviewed By: jberdine

Differential Revision: D6912304

fbshipit-source-id: 76e95a8
master
Mehdi Bouaziz 7 years ago committed by Facebook Github Bot
parent 3be3ca427f
commit d61c4927c1

@ -42,6 +42,8 @@ let template_args_of_template_spec_info = function
args args
exception DoNotHandleJavaYet
let templated_name_of_class_name class_name = let templated_name_of_class_name class_name =
let open Typ in let open Typ in
match class_name with match class_name with
@ -50,7 +52,7 @@ let templated_name_of_class_name class_name =
| CppClass (qual_name, template_spec_info) -> | CppClass (qual_name, template_spec_info) ->
(qual_name, template_args_of_template_spec_info template_spec_info) (qual_name, template_args_of_template_spec_info template_spec_info)
| JavaClass _ -> | JavaClass _ ->
assert false raise DoNotHandleJavaYet
(** Little abstraction over arguments: currently actual args, we'll want formal args later *) (** 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 = 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} {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 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_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 = 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 on_args:('f_in, 'f_out, 'captured_types) on_args -> FuncArg.t list -> 'f_in * 'captured_types
-> 'f_out pre_result -> '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_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 } ; 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 = Typ.Procname.t -> FuncArg.t list -> 'f option
type 'f dispatcher = 'f matcher
type 'f typ_dispatcher = 'f typ_matcher type 'f typ_dispatcher = Typ.name -> 'f option
(* Combinators *) (* Combinators *)
@ -551,21 +544,46 @@ module Procname = struct
let make_matcher : ('f_in, 'f_out) all_args_matcher -> 'f_in -> 'f_out matcher = let make_matcher : ('f_in, 'f_out) all_args_matcher -> 'f_in -> 'f_out matcher =
fun m f -> fun m f ->
let {on_c; on_objc_cpp} : (_, _) all_args_matcher = m in 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 -> fun procname args ->
match procname with match procname with
| ObjC_Cpp objc_cpp -> | ObjC_Cpp objc_cpp ->
on_objc_cpp f objc_cpp args |> pre_to_opt procname args on_objc_cpp objc_cpp args
| C c -> | C c ->
on_c f c args |> pre_to_opt procname args on_c c args
| _ -> | _ ->
None 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 *) (* Function args *)
let no_marker_checker _markers = true let no_marker_checker _markers = true
@ -607,7 +625,7 @@ module Procname = struct
(** Matches the type matched by the given path_matcher *) (** Matches the type matched by the given path_matcher *)
let match_typ : (_, _, unit, unit, unit, non_empty) path_matcher -> (_, _) one_arg_matcher = let match_typ : (_, _, unit, unit, unit, non_empty) path_matcher -> (_, _) one_arg_matcher =
fun m -> 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 = let rec match_typ typ =
match typ with match typ with
| {Typ.desc= Tstruct name} -> | {Typ.desc= Tstruct name} ->
@ -729,17 +747,24 @@ module Procname = struct
(** Retries matching with another matcher *) (** 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 (** Retries matching with another matcher if the function does not have the
exact number/types of args *) exact number/types of args *)
let exact_args_or_retry : 'f -> (_, _, _) func_args_end = let exact_args_or_retry : 'f matcher -> (_, _, _) func_args_end =
fun f -> alternative_args_end no_args_left (args_end_retry f) fun m -> alternative_args_end no_args_left (args_end_retry m)
let wrong_args_internal_error procname _args = let wrong_args_internal_error : _ matcher =
Logging.(die InternalError) let on_procname procname =
"Unexpected number/types of arguments for %a" Typ.Procname.pp 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 let ( $! ) path_matcher () = args_begin path_matcher
@ -794,13 +819,21 @@ module TypName = struct
let make_matcher let make_matcher
: ('f_in, 'f_out, _, _, _, non_empty) path_matcher -> 'f_in -> 'f_out typ_matcher = : ('f_in, 'f_out, _, _, _, non_empty) path_matcher -> 'f_in -> 'f_out typ_matcher =
fun m f -> fun m f ->
let {on_templated_name} = m in let {on_templated_name} : ('f_in, 'f_out, _, _, _, non_empty) path_matcher = m in
function let on_templated_name templated_name =
| name -> name |> templated_name_of_class_name |> on_templated_name f |> Option.map ~f:fst templated_name |> on_templated_name f |> Option.map ~f:fst
in
{on_templated_name}
let make_dispatcher : 'f typ_matcher list -> 'f typ_dispatcher = 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 let ( &-->! ) path_matcher f = make_matcher path_matcher f

@ -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 ('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]: (* A matcher is a rule associating a function [f] to a [C/C++ function/method]:
- [C/C++ function/method] --> [f] - [C/C++ function/method] --> [f]

@ -44,7 +44,9 @@ let all_checkers =
; (DynamicDispatch Interproc.analyze_procedure, Language.Java) ] } ; (DynamicDispatch Interproc.analyze_procedure, Language.Java) ] }
; { name= "buffer overrun" ; { name= "buffer overrun"
; active= Config.bufferoverrun ; active= Config.bufferoverrun
; callbacks= [(Procedure BufferOverrunChecker.checker, Language.Clang)] } ; callbacks=
[ (Procedure BufferOverrunChecker.checker, Language.Clang)
; (Procedure BufferOverrunChecker.checker, Language.Java) ] }
; { name= "crashcontext" ; { name= "crashcontext"
; active= Config.crashcontext ; active= Config.crashcontext
; callbacks= [(Procedure BoundedCallTree.checker, Language.Java)] } ; callbacks= [(Procedure BoundedCallTree.checker, Language.Java)] }

Loading…
Cancel
Save