diff --git a/infer/src/backend/symExec.ml b/infer/src/backend/symExec.ml index 0c1e819a1..d6c69332a 100644 --- a/infer/src/backend/symExec.ml +++ b/infer/src/backend/symExec.ml @@ -659,23 +659,23 @@ let resolve_virtual_pname tenv prop actuals callee_pname call_flags : Typ.Procna (** Resolve the name of the procedure to call based on the type of the arguments *) let resolve_java_pname tenv prop args pname_java call_flags : Typ.Procname.java = let resolve_from_args resolved_pname_java args = - let parameters = Typ.Procname.java_get_parameters resolved_pname_java in - if List.length args <> List.length parameters then resolved_pname_java - else - let resolved_params = - List.fold2_exn - ~f:(fun accu (arg_exp, _) name -> - match resolve_typename prop arg_exp with - | Some class_name - -> Typ.Procname.split_classname (Typ.Name.name class_name) :: accu - | None - -> name :: accu) - ~init:[] args (Typ.Procname.java_get_parameters resolved_pname_java) - |> List.rev - in - Typ.Procname.java_replace_parameters resolved_pname_java resolved_params + let resolved_params = + List.fold2_exn + ~f:(fun accu (arg_exp, _) name -> + match resolve_typename prop arg_exp with + | Some class_name + -> Typ.Procname.split_classname (Typ.Name.name class_name) :: accu + | None + -> name :: accu) + ~init:[] args (Typ.Procname.java_get_parameters resolved_pname_java) + |> List.rev + in + Typ.Procname.java_replace_parameters resolved_pname_java resolved_params in let resolved_pname_java, other_args = + let pname = Typ.Procname.Java pname_java + and parameters = Typ.Procname.java_get_parameters pname_java in + let match_parameters args = Int.equal (List.length args) (List.length parameters) in match args with | [] -> (pname_java, []) @@ -683,7 +683,7 @@ let resolve_java_pname tenv prop args pname_java call_flags : Typ.Procname.java -> let resolved = match resolve_typename prop first_arg with | Some class_name -> ( - match resolve_method tenv class_name (Typ.Procname.Java pname_java) with + match resolve_method tenv class_name pname with | Typ.Procname.Java resolved_pname_java -> resolved_pname_java | _ @@ -692,10 +692,15 @@ let resolve_java_pname tenv prop args pname_java call_flags : Typ.Procname.java -> pname_java in (resolved, other_args) - | _ :: other_args when Typ.Procname.is_constructor (Typ.Procname.Java pname_java) + | _ :: other_args + when match_parameters other_args (* Non-virtual call, e.g. constructors or private methods *) -> (pname_java, other_args) - | args + | args when match_parameters args (* Static call *) -> (pname_java, args) + | args + -> L.(die InternalError) + "Call mismatch: method %a has %i paramters but is called with %i arguments@." + Typ.Procname.pp pname (List.length parameters) (List.length args) in resolve_from_args resolved_pname_java other_args diff --git a/infer/tests/build_systems/ant/issues.exp b/infer/tests/build_systems/ant/issues.exp index c9393381e..20df598af 100644 --- a/infer/tests/build_systems/ant/issues.exp +++ b/infer/tests/build_systems/ant/issues.exp @@ -31,6 +31,7 @@ codetoanalyze/java/infer/DynamicDispatch.java, void DynamicDispatch.dynamicDispa codetoanalyze/java/infer/DynamicDispatch.java, void DynamicDispatch.dynamicDispatchCallsWrapperWithSupertypeBad(), 3, NULL_DEREFERENCE, [start of procedure dynamicDispatchCallsWrapperWithSupertypeBad(),start of procedure DynamicDispatch$Supertype(),return from a call to DynamicDispatch$Supertype.(),start of procedure dynamicDispatchWrapperBar(...),start of procedure bar(),return from a call to Object DynamicDispatch$Supertype.bar(),return from a call to Object DynamicDispatch.dynamicDispatchWrapperBar(DynamicDispatch$Supertype)] codetoanalyze/java/infer/DynamicDispatch.java, void DynamicDispatch.dynamicDispatchShouldNotCauseFalseNegativeEasy(), 3, NULL_DEREFERENCE, [start of procedure dynamicDispatchShouldNotCauseFalseNegativeEasy(),start of procedure DynamicDispatch$Subtype(),start of procedure DynamicDispatch$Supertype(),return from a call to DynamicDispatch$Supertype.(),return from a call to DynamicDispatch$Subtype.(),start of procedure foo(),return from a call to Object DynamicDispatch$Subtype.foo()] codetoanalyze/java/infer/DynamicDispatch.java, void DynamicDispatch.dynamicDispatchShouldNotReportWhenCallingSupertype(DynamicDispatch$Subtype), 3, NULL_DEREFERENCE, [start of procedure dynamicDispatchShouldNotReportWhenCallingSupertype(...),start of procedure foo(),return from a call to Object DynamicDispatch$Subtype.foo()] +codetoanalyze/java/infer/DynamicDispatch.java, void DynamicDispatch.dynamicResolutionWithPrivateMethodBad(), 2, NULL_DEREFERENCE, [start of procedure dynamicResolutionWithPrivateMethodBad(),start of procedure DynamicDispatch$Subtype(),start of procedure DynamicDispatch$Supertype(),return from a call to DynamicDispatch$Supertype.(),return from a call to DynamicDispatch$Subtype.(),start of procedure callFoo(...),start of procedure foo(),return from a call to Object DynamicDispatch$Subtype.foo(),return from a call to Object DynamicDispatch.callFoo(DynamicDispatch$Subtype)] codetoanalyze/java/infer/DynamicDispatch.java, void DynamicDispatch.interfaceShouldNotCauseFalseNegativeEasy(), 3, NULL_DEREFERENCE, [start of procedure interfaceShouldNotCauseFalseNegativeEasy(),start of procedure DynamicDispatch$Impl(),return from a call to DynamicDispatch$Impl.(),start of procedure foo(),return from a call to Object DynamicDispatch$Impl.foo()] codetoanalyze/java/infer/DynamicDispatch.java, void DynamicDispatch.interfaceShouldNotCauseFalseNegativeHard(DynamicDispatch$Impl), 1, NULL_DEREFERENCE, [start of procedure interfaceShouldNotCauseFalseNegativeHard(...),start of procedure foo(),return from a call to Object DynamicDispatch$Impl.foo()] codetoanalyze/java/infer/FilterInputStreamLeaks.java, void FilterInputStreamLeaks.bufferedInputStreamNotClosedAfterRead(), 7, RESOURCE_LEAK, [start of procedure bufferedInputStreamNotClosedAfterRead(),Skipping BufferedInputStream(...): unknown method,exception java.io.IOException] @@ -133,8 +134,8 @@ codetoanalyze/java/infer/ResourceLeaks.java, boolean ResourceLeaks.jarFileNotClo codetoanalyze/java/infer/ResourceLeaks.java, int ResourceLeaks.fileOutputStreamTwoLeaks1(boolean), 3, RESOURCE_LEAK, [start of procedure fileOutputStreamTwoLeaks1(...),Taking true branch] codetoanalyze/java/infer/ResourceLeaks.java, int ResourceLeaks.fileOutputStreamTwoLeaks1(boolean), 6, RESOURCE_LEAK, [start of procedure fileOutputStreamTwoLeaks1(...),Taking false branch] codetoanalyze/java/infer/ResourceLeaks.java, int ResourceLeaks.readConfigNotCloseStream(String), 5, RESOURCE_LEAK, [start of procedure readConfigNotCloseStream(...)] -codetoanalyze/java/infer/ResourceLeaks.java, void ResourceLeaks.activityObtainTypedArrayAndLeak(Activity), 2, RESOURCE_LEAK, [start of procedure activityObtainTypedArrayAndLeak(...),start of procedure ignore(...),return from a call to void ResourceLeaks.ignore(Object)] -codetoanalyze/java/infer/ResourceLeaks.java, void ResourceLeaks.contextObtainTypedArrayAndLeak(Context), 2, RESOURCE_LEAK, [start of procedure contextObtainTypedArrayAndLeak(...),start of procedure ignore(...),return from a call to void ResourceLeaks.ignore(Object)] +codetoanalyze/java/infer/ResourceLeaks.java, void ResourceLeaks.activityObtainTypedArrayAndLeak(Activity), 2, RESOURCE_LEAK, [start of procedure activityObtainTypedArrayAndLeak(...),start of procedure ignore(...),return from a call to void ResourceLeaks.ignore(TypedArray)] +codetoanalyze/java/infer/ResourceLeaks.java, void ResourceLeaks.contextObtainTypedArrayAndLeak(Context), 2, RESOURCE_LEAK, [start of procedure contextObtainTypedArrayAndLeak(...),start of procedure ignore(...),return from a call to void ResourceLeaks.ignore(TypedArray)] codetoanalyze/java/infer/ResourceLeaks.java, void ResourceLeaks.copyFileLeak(File,File), 11, RESOURCE_LEAK, [start of procedure copyFileLeak(...),Skipping transferTo(...): unknown method,Taking true branch,exception java.io.IOException] codetoanalyze/java/infer/ResourceLeaks.java, void ResourceLeaks.copyFileLeak(File,File), 11, RESOURCE_LEAK, [start of procedure copyFileLeak(...),exception java.io.FileNotFoundException] codetoanalyze/java/infer/ResourceLeaks.java, void ResourceLeaks.deflaterLeak(), 1, RESOURCE_LEAK, [start of procedure deflaterLeak()] @@ -166,7 +167,7 @@ codetoanalyze/java/infer/ResourceLeaks.java, void ResourceLeaks.pipedOutputStrea codetoanalyze/java/infer/ResourceLeaks.java, void ResourceLeaks.scannerNotClosed(), 1, RESOURCE_LEAK, [start of procedure scannerNotClosed()] codetoanalyze/java/infer/ResourceLeaks.java, void ResourceLeaks.serverSocketNotClosed(), 12, RESOURCE_LEAK, [start of procedure serverSocketNotClosed(),Skipping ServerSocket(...): unknown method,exception java.io.IOException] codetoanalyze/java/infer/ResourceLeaks.java, void ResourceLeaks.socketNotClosed(), 1, RESOURCE_LEAK, [start of procedure socketNotClosed()] -codetoanalyze/java/infer/ResourceLeaks.java, void ResourceLeaks.themeObtainTypedArrayAndLeak(Resources$Theme), 2, RESOURCE_LEAK, [start of procedure themeObtainTypedArrayAndLeak(...),start of procedure ignore(...),return from a call to void ResourceLeaks.ignore(Object)] +codetoanalyze/java/infer/ResourceLeaks.java, void ResourceLeaks.themeObtainTypedArrayAndLeak(Resources$Theme), 2, RESOURCE_LEAK, [start of procedure themeObtainTypedArrayAndLeak(...),start of procedure ignore(...),return from a call to void ResourceLeaks.ignore(TypedArray)] codetoanalyze/java/infer/ResourceLeaks.java, void ResourceLeaks.twoResources(), 11, RESOURCE_LEAK, [start of procedure twoResources(),Taking true branch,exception java.io.IOException] codetoanalyze/java/infer/ResourceLeaks.java, void ResourceLeaks.twoResourcesRandomAccessFile(), 10, RESOURCE_LEAK, [start of procedure twoResourcesRandomAccessFile(),Taking true branch,exception java.io.IOException] codetoanalyze/java/infer/ResourceLeaks.java, void ResourceLeaks.zipFileLeakExceptionalBranch(), 5, RESOURCE_LEAK, [start of procedure zipFileLeakExceptionalBranch(),exception java.io.IOException,Switch condition is true. Entering switch case] diff --git a/infer/tests/codetoanalyze/java/infer/DynamicDispatch.java b/infer/tests/codetoanalyze/java/infer/DynamicDispatch.java index bcf3ae7d5..2d286a0aa 100644 --- a/infer/tests/codetoanalyze/java/infer/DynamicDispatch.java +++ b/infer/tests/codetoanalyze/java/infer/DynamicDispatch.java @@ -133,4 +133,26 @@ public class DynamicDispatch { } + private Object callFoo(Supertype o) { + return o.foo(); + } + + void dynamicResolutionWithPrivateMethodBad() { + Supertype subtype = new Subtype(); + callFoo(subtype).toString(); + } + + Object variadicMethod(Supertype... args) { + if (args.length == 0) { + return null; + } else { + return args[0].foo(); + } + } + + void dynamicResolutionWithVariadicMethodBad() { + Supertype subtype = new Subtype(); + variadicMethod(subtype, null, null).toString(); + } + } diff --git a/infer/tests/codetoanalyze/java/infer/issues.exp b/infer/tests/codetoanalyze/java/infer/issues.exp index 74f0c6977..bc152a9d6 100644 --- a/infer/tests/codetoanalyze/java/infer/issues.exp +++ b/infer/tests/codetoanalyze/java/infer/issues.exp @@ -53,6 +53,7 @@ codetoanalyze/java/infer/DynamicDispatch.java, void DynamicDispatch.dynamicDispa codetoanalyze/java/infer/DynamicDispatch.java, void DynamicDispatch.dynamicDispatchCallsWrapperWithSupertypeBad(), 3, NULL_DEREFERENCE, [start of procedure dynamicDispatchCallsWrapperWithSupertypeBad(),start of procedure DynamicDispatch$Supertype(),return from a call to DynamicDispatch$Supertype.(),start of procedure dynamicDispatchWrapperBar(...),start of procedure bar(),return from a call to Object DynamicDispatch$Supertype.bar(),return from a call to Object DynamicDispatch.dynamicDispatchWrapperBar(DynamicDispatch$Supertype)] codetoanalyze/java/infer/DynamicDispatch.java, void DynamicDispatch.dynamicDispatchShouldNotCauseFalseNegativeEasy(), 3, NULL_DEREFERENCE, [start of procedure dynamicDispatchShouldNotCauseFalseNegativeEasy(),start of procedure DynamicDispatch$Subtype(),start of procedure DynamicDispatch$Supertype(),return from a call to DynamicDispatch$Supertype.(),return from a call to DynamicDispatch$Subtype.(),start of procedure foo(),return from a call to Object DynamicDispatch$Subtype.foo()] codetoanalyze/java/infer/DynamicDispatch.java, void DynamicDispatch.dynamicDispatchShouldNotReportWhenCallingSupertype(DynamicDispatch$Subtype), 3, NULL_DEREFERENCE, [start of procedure dynamicDispatchShouldNotReportWhenCallingSupertype(...),start of procedure foo(),return from a call to Object DynamicDispatch$Subtype.foo()] +codetoanalyze/java/infer/DynamicDispatch.java, void DynamicDispatch.dynamicResolutionWithPrivateMethodBad(), 2, NULL_DEREFERENCE, [start of procedure dynamicResolutionWithPrivateMethodBad(),start of procedure DynamicDispatch$Subtype(),start of procedure DynamicDispatch$Supertype(),return from a call to DynamicDispatch$Supertype.(),return from a call to DynamicDispatch$Subtype.(),start of procedure callFoo(...),start of procedure foo(),return from a call to Object DynamicDispatch$Subtype.foo(),return from a call to Object DynamicDispatch.callFoo(DynamicDispatch$Subtype)] codetoanalyze/java/infer/DynamicDispatch.java, void DynamicDispatch.interfaceShouldNotCauseFalseNegativeEasy(), 3, NULL_DEREFERENCE, [start of procedure interfaceShouldNotCauseFalseNegativeEasy(),start of procedure DynamicDispatch$Impl(),return from a call to DynamicDispatch$Impl.(),start of procedure foo(),return from a call to Object DynamicDispatch$Impl.foo()] codetoanalyze/java/infer/DynamicDispatch.java, void DynamicDispatch.interfaceShouldNotCauseFalseNegativeHard(DynamicDispatch$Impl), 1, NULL_DEREFERENCE, [start of procedure interfaceShouldNotCauseFalseNegativeHard(...),start of procedure foo(),return from a call to Object DynamicDispatch$Impl.foo()] codetoanalyze/java/infer/FilterInputStreamLeaks.java, void FilterInputStreamLeaks.bufferedInputStreamNotClosedAfterRead(), 7, RESOURCE_LEAK, [start of procedure bufferedInputStreamNotClosedAfterRead(),Skipping BufferedInputStream(...): unknown method,exception java.io.IOException] @@ -163,13 +164,13 @@ codetoanalyze/java/infer/ResourceLeaks.java, int ResourceLeaks.readConfigCloseSt codetoanalyze/java/infer/ResourceLeaks.java, int ResourceLeaks.readConfigNotCloseStream(String), 5, RESOURCE_LEAK, [start of procedure readConfigNotCloseStream(...)] codetoanalyze/java/infer/ResourceLeaks.java, int ResourceLeaks.tryWithResource(), 3, UNINITIALIZED_VALUE, [start of procedure tryWithResource(),exception java.io.IOException,Switch condition is true. Entering switch case,exception java.io.IOException] codetoanalyze/java/infer/ResourceLeaks.java, void ResourceLeaks.NoResourceLeakWarningAfterCheckState(File,int), 2, PRECONDITION_NOT_MET, [start of procedure NoResourceLeakWarningAfterCheckState(...),Taking false branch] -codetoanalyze/java/infer/ResourceLeaks.java, void ResourceLeaks.activityObtainTypedArrayAndLeak(Activity), 2, RESOURCE_LEAK, [start of procedure activityObtainTypedArrayAndLeak(...),start of procedure ignore(...),return from a call to void ResourceLeaks.ignore(Object)] +codetoanalyze/java/infer/ResourceLeaks.java, void ResourceLeaks.activityObtainTypedArrayAndLeak(Activity), 2, RESOURCE_LEAK, [start of procedure activityObtainTypedArrayAndLeak(...),start of procedure ignore(...),return from a call to void ResourceLeaks.ignore(TypedArray)] codetoanalyze/java/infer/ResourceLeaks.java, void ResourceLeaks.closeNullQuietlyWithCloseables(), 5, UNINITIALIZED_VALUE, [start of procedure closeNullQuietlyWithCloseables(),exception java.io.FileNotFoundException] codetoanalyze/java/infer/ResourceLeaks.java, void ResourceLeaks.closeNullWithCloseables(), 5, UNINITIALIZED_VALUE, [start of procedure closeNullWithCloseables(),exception java.io.FileNotFoundException] codetoanalyze/java/infer/ResourceLeaks.java, void ResourceLeaks.closeWithCloseablesNestedAlloc(), 5, UNINITIALIZED_VALUE, [start of procedure closeWithCloseablesNestedAlloc(),exception java.io.FileNotFoundException] codetoanalyze/java/infer/ResourceLeaks.java, void ResourceLeaks.closedQuietlyWithCloseables(), 5, UNINITIALIZED_VALUE, [start of procedure closedQuietlyWithCloseables(),exception java.io.IOException] codetoanalyze/java/infer/ResourceLeaks.java, void ResourceLeaks.closedWithCloseables(), 5, UNINITIALIZED_VALUE, [start of procedure closedWithCloseables(),exception java.io.IOException] -codetoanalyze/java/infer/ResourceLeaks.java, void ResourceLeaks.contextObtainTypedArrayAndLeak(Context), 2, RESOURCE_LEAK, [start of procedure contextObtainTypedArrayAndLeak(...),start of procedure ignore(...),return from a call to void ResourceLeaks.ignore(Object)] +codetoanalyze/java/infer/ResourceLeaks.java, void ResourceLeaks.contextObtainTypedArrayAndLeak(Context), 2, RESOURCE_LEAK, [start of procedure contextObtainTypedArrayAndLeak(...),start of procedure ignore(...),return from a call to void ResourceLeaks.ignore(TypedArray)] codetoanalyze/java/infer/ResourceLeaks.java, void ResourceLeaks.copyFileLeak(File,File), 6, UNINITIALIZED_VALUE, [start of procedure copyFileLeak(...),exception java.io.IOException] codetoanalyze/java/infer/ResourceLeaks.java, void ResourceLeaks.copyFileLeak(File,File), 11, RESOURCE_LEAK, [start of procedure copyFileLeak(...),Skipping transferTo(...): unknown method,Taking true branch,exception java.io.IOException] codetoanalyze/java/infer/ResourceLeaks.java, void ResourceLeaks.copyFileLeak(File,File), 11, RESOURCE_LEAK, [start of procedure copyFileLeak(...),exception java.io.FileNotFoundException] @@ -204,7 +205,7 @@ codetoanalyze/java/infer/ResourceLeaks.java, void ResourceLeaks.scannerNotClosed codetoanalyze/java/infer/ResourceLeaks.java, void ResourceLeaks.serverSocketNotClosed(), 12, RESOURCE_LEAK, [start of procedure serverSocketNotClosed(),Skipping ServerSocket(...): unknown method,exception java.io.IOException] codetoanalyze/java/infer/ResourceLeaks.java, void ResourceLeaks.serverSocketWithSocketClosed(), 14, UNINITIALIZED_VALUE, [start of procedure serverSocketWithSocketClosed(),Skipping ServerSocket(...): unknown method,exception java.io.IOException] codetoanalyze/java/infer/ResourceLeaks.java, void ResourceLeaks.socketNotClosed(), 1, RESOURCE_LEAK, [start of procedure socketNotClosed()] -codetoanalyze/java/infer/ResourceLeaks.java, void ResourceLeaks.themeObtainTypedArrayAndLeak(Resources$Theme), 2, RESOURCE_LEAK, [start of procedure themeObtainTypedArrayAndLeak(...),start of procedure ignore(...),return from a call to void ResourceLeaks.ignore(Object)] +codetoanalyze/java/infer/ResourceLeaks.java, void ResourceLeaks.themeObtainTypedArrayAndLeak(Resources$Theme), 2, RESOURCE_LEAK, [start of procedure themeObtainTypedArrayAndLeak(...),start of procedure ignore(...),return from a call to void ResourceLeaks.ignore(TypedArray)] codetoanalyze/java/infer/ResourceLeaks.java, void ResourceLeaks.twoResources(), 8, UNINITIALIZED_VALUE, [start of procedure twoResources(),exception java.io.FileNotFoundException] codetoanalyze/java/infer/ResourceLeaks.java, void ResourceLeaks.twoResources(), 11, RESOURCE_LEAK, [start of procedure twoResources(),Taking true branch,exception java.io.IOException] codetoanalyze/java/infer/ResourceLeaks.java, void ResourceLeaks.twoResourcesCommonFix(), 8, UNINITIALIZED_VALUE, [start of procedure twoResourcesCommonFix(),exception java.io.FileNotFoundException]