From 5686d67072f325ed144f42a78baac5b624abca92 Mon Sep 17 00:00:00 2001 From: Nikos Gorogiannis Date: Tue, 22 Jan 2019 05:15:24 -0800 Subject: [PATCH] [classloads] fix treatment of static initializers Reviewed By: jvillard Differential Revision: D13751141 fbshipit-source-id: f64af292b --- infer/src/IR/Typ.ml | 10 ++++++++ infer/src/IR/Typ.mli | 3 +++ infer/src/concurrency/classLoads.ml | 15 ++++++++--- infer/src/concurrency/classLoadsDomain.ml | 3 +++ .../codetoanalyze/java/classloads/Makefile | 2 +- .../codetoanalyze/java/classloads/Static.java | 25 +++++++++++++++++++ 6 files changed, 53 insertions(+), 5 deletions(-) create mode 100644 infer/tests/codetoanalyze/java/classloads/Static.java diff --git a/infer/src/IR/Typ.ml b/infer/src/IR/Typ.ml index 182f72af2..be40f0883 100644 --- a/infer/src/IR/Typ.ml +++ b/infer/src/IR/Typ.ml @@ -603,6 +603,8 @@ module Procname = struct type java_type = Name.Java.Split.t = {package: string option; type_name: string} [@@deriving compare] + let java_void = {package= None; type_name= "void"} + (** Type of java procedure names. *) type t = { method_name: string @@ -741,6 +743,14 @@ module Procname = struct let is_class_initializer {method_name} = String.equal method_name class_initializer_method_name + let get_class_initializer class_name = + { method_name= class_initializer_method_name + ; parameters= [] + ; class_name + ; return_type= Some java_void + ; kind= Static } + + let is_anonymous_inner_class_constructor {class_name} = Name.Java.is_anonymous_inner_class_name class_name diff --git a/infer/src/IR/Typ.mli b/infer/src/IR/Typ.mli index 37ead3360..a64080449 100644 --- a/infer/src/IR/Typ.mli +++ b/infer/src/IR/Typ.mli @@ -391,6 +391,9 @@ module Procname : sig val is_class_initializer : t -> bool (** Check if this is a class initializer. *) + val get_class_initializer : Name.t -> t + (** Given a java class, generate the procname of its static initializer. *) + val is_external : t -> bool (** Check if the method belongs to one of the specified external packages *) end diff --git a/infer/src/concurrency/classLoads.ml b/infer/src/concurrency/classLoads.ml index 560d88f0f..2a11f9dab 100644 --- a/infer/src/concurrency/classLoads.ml +++ b/infer/src/concurrency/classLoads.ml @@ -5,6 +5,8 @@ * LICENSE file in the root directory of this source tree. *) open! IStd +module L = Logging +module F = Format module Payload = SummaryPayload.Make (struct type t = ClassLoadsDomain.summary @@ -53,18 +55,21 @@ let class_initializer_of_method pdesc = | Java java_pname when Java.is_class_initializer java_pname -> None | Java java_pname -> - Some (Java Java.(replace_method_name class_initializer_method_name java_pname)) + let class_name = Java.get_class_type_name java_pname in + Some (Java (Java.get_class_initializer class_name)) | _ -> assert false let analyze_procedure {Callbacks.proc_desc; summary} = let proc_name = Procdesc.get_proc_name proc_desc in + L.debug Analysis Verbose "CL: ANALYZING %a@." Typ.Procname.pp proc_name ; let loc = Procdesc.get_loc proc_desc in (* add a load for the method's class *) let init = - get_java_class proc_name - |> Option.fold ~init:ClassLoadsDomain.empty ~f:(ClassLoadsDomain.add_load loc) + let class_opt = get_java_class proc_name in + L.debug Analysis Verbose "CL: CLASS = %a@." (Pp.option F.pp_print_string) class_opt ; + Option.fold class_opt ~init:ClassLoadsDomain.empty ~f:(ClassLoadsDomain.add_load loc) in (* add loads done by the static initialization of this method's class *) let after_class_init = @@ -75,4 +80,6 @@ let analyze_procedure {Callbacks.proc_desc; summary} = in let post = Procdesc.fold_instrs proc_desc ~init:after_class_init ~f:(exec_instr proc_desc) in report_loads proc_desc summary post ; - Payload.update_summary post summary + let result = Payload.update_summary post summary in + L.debug Analysis Verbose "CL: FINISHED ANALYZING %a@." Typ.Procname.pp proc_name ; + result diff --git a/infer/src/concurrency/classLoadsDomain.ml b/infer/src/concurrency/classLoadsDomain.ml index b920c4265..85ec2ce83 100644 --- a/infer/src/concurrency/classLoadsDomain.ml +++ b/infer/src/concurrency/classLoadsDomain.ml @@ -6,6 +6,7 @@ *) open! IStd module F = Format +module L = Logging module ClassLoad = struct include String @@ -28,11 +29,13 @@ let add ({Event.trace} as x) astate = let union xs ys = fold add xs ys let add_load loc astate clazz = + L.debug Analysis Verbose "CL: LOADING class %s@." clazz ; let new_event = Event.make clazz loc in add new_event astate let integrate_summary callee_pname loc astate callee_summary = + L.debug Analysis Verbose "CL: ADDING SUMMARY OF %a@." Typ.Procname.pp callee_pname ; let callsite = CallSite.make callee_pname loc in let summary = with_callsite callee_summary callsite in union astate summary diff --git a/infer/tests/codetoanalyze/java/classloads/Makefile b/infer/tests/codetoanalyze/java/classloads/Makefile index bdd0d538b..c819103b5 100644 --- a/infer/tests/codetoanalyze/java/classloads/Makefile +++ b/infer/tests/codetoanalyze/java/classloads/Makefile @@ -15,7 +15,7 @@ SOURCES = $(wildcard *.java) LOADS = $(patsubst %.java,%.loads,$(SOURCES)) OBJECTS = $(patsubst %.java,%.class,$(SOURCES)) CLASS_LOADS_OPT = $(patsubst %.java,--class-loads-roots %.main,$(SOURCES)) -INFER_OPTIONS = -j 1 --class-loads-only $(CLASS_LOADS_OPT) --debug-exceptions +INFER_OPTIONS = --class-loads-only $(CLASS_LOADS_OPT) --debug-exceptions CLEAN_EXTRA = *.class *.loads loads.exp loads.exp.test include $(TESTS_DIR)/java.make diff --git a/infer/tests/codetoanalyze/java/classloads/Static.java b/infer/tests/codetoanalyze/java/classloads/Static.java new file mode 100644 index 000000000..6a4f90f24 --- /dev/null +++ b/infer/tests/codetoanalyze/java/classloads/Static.java @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2018-present, Facebook, Inc. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +class Static { + // this loads StaticA + static StaticA s = new StaticA(); + + public static void main(String args[]) {} +} + +class StaticA { + // this loads StaticB + static StaticB b = new StaticB(); +} + +class StaticB { + // no load here + static StaticC c = null; +} + +class StaticC {}