diff --git a/.buckconfig b/.buckconfig index cea37ddba..0702f2773 100644 --- a/.buckconfig +++ b/.buckconfig @@ -1,3 +1,7 @@ [project] ignore = .git, .ml, .mli + +[java] + source_level = 8 + target_level = 8 \ No newline at end of file diff --git a/configure.ac b/configure.ac index 3e47ea8d3..e0a2ebe79 100644 --- a/configure.ac +++ b/configure.ac @@ -199,8 +199,8 @@ if test "x$enable_java_analyzers" = "xyes"; then AC_CHECK_TOOL([JAVAC], [javac], [no]) AC_ASSERT_PROG([javac], [$JAVAC]) AC_ASSERT_PROG([java], [$JAVA]) - AC_ASSERT_OCAML_PKG([javalib], [], [2.3.1]) - AC_ASSERT_OCAML_PKG([sawja], [], [1.5.1]) + AC_ASSERT_OCAML_PKG([javalib], [], [2.3.3]) + AC_ASSERT_OCAML_PKG([sawja], [], [1.5.2]) AC_ASSERT_OCAML_PKG([ptrees]) AC_MSG_CHECKING([for JAVA_HOME]) diff --git a/infer/annotations/Makefile b/infer/annotations/Makefile index 7c7ea9d60..dd506e6c4 100644 --- a/infer/annotations/Makefile +++ b/infer/annotations/Makefile @@ -14,7 +14,7 @@ ANNOT_SOURCES = $(shell find com/facebook/infer/annotation -name "*.java") PROCESSOR_SOURCES = $(shell find com/facebook/infer/annotprocess -name "*.java") ANNOT_CLASSES = 'annot_classes' PROCESSOR_CLASSES = 'processor_classes' -TARGET_JDK_VERSION = '1.7' +TARGET_JDK_VERSION = '1.8' ANNOTATIONS_JAR = $(CWD)/annotations.jar PROCESSOR_JAR = $(JAVA_LIB_DIR)/processor.jar diff --git a/infer/src/java/jTrans.ml b/infer/src/java/jTrans.ml index 2f9d349ba..b95201fd6 100644 --- a/infer/src/java/jTrans.ml +++ b/infer/src/java/jTrans.ml @@ -217,7 +217,21 @@ let get_implementation cm = let cn, ms = JBasics.cms_split cms in failwithf "native method %s found in %s@." (JBasics.ms_name ms) (JBasics.cn_name cn) | Javalib.Java t -> - JBir.transform ~bcv: false ~ch_link: false ~formula: false ~formula_cmd:[] cm (Lazy.force t) + (* Sawja doesn't handle invokedynamic, and it will crash with a Match_failure if we give it + bytecode with this instruction. hack around this problem by converting all invokedynamic's + to invokestatic's that call a method with the same signature as the lambda on + java.lang.Object. this isn't great, but it's a lot better than crashing *) + let code = Lazy.force t in + let c_code = + Array.map + (function + | (JCode.OpInvoke (`Dynamic _, ms)) -> + JCode.OpInvoke (`Static JBasics.java_lang_object, ms) + | opcode -> + opcode) + code.JCode.c_code in + let code' = { code with JCode.c_code; } in + JBir.transform ~bcv: false ~ch_link: false ~formula: false ~formula_cmd:[] cm code' let update_constr_loc cn ms loc_start = if (JBasics.ms_name ms) = JConfig.constructor_name then diff --git a/infer/tests/build_systems/ant/build.xml b/infer/tests/build_systems/ant/build.xml index 2a3f9c1f6..b50bb1ea1 100644 --- a/infer/tests/build_systems/ant/build.xml +++ b/infer/tests/build_systems/ant/build.xml @@ -7,10 +7,8 @@ - - - + diff --git a/infer/tests/build_systems/ant/issues.exp b/infer/tests/build_systems/ant/issues.exp index a6f047287..a394a3738 100644 --- a/infer/tests/build_systems/ant/issues.exp +++ b/infer/tests/build_systems/ant/issues.exp @@ -64,6 +64,8 @@ src/infer/GuardedByExample.java, void GuardedByExample.writeFBad(), 1, UNSAFE_GU src/infer/GuardedByExample.java, void GuardedByExample.writeFBadWrongLock(), 2, UNSAFE_GUARDED_BY_ACCESS src/infer/HashMapExample.java, int HashMapExample.getOneIntegerWithoutCheck(), 6, NULL_DEREFERENCE src/infer/HashMapExample.java, void HashMapExample.getTwoIntegersWithOneCheck(Integer,Integer), 11, NULL_DEREFERENCE +src/infer/InvokeDynamic.java, int InvokeDynamic.lambda$npeInLambdaBad$1(String,String), 1, NULL_DEREFERENCE +src/infer/InvokeDynamic.java, void InvokeDynamic.invokeDynamicThenNpeBad(List), 5, NULL_DEREFERENCE src/infer/NullPointerExceptions.java, String NullPointerExceptions.hashmapNPE(HashMap,Object), 1, NULL_DEREFERENCE src/infer/NullPointerExceptions.java, String NullPointerExceptions.nullTryLock(FileChannel), 2, NULL_DEREFERENCE src/infer/NullPointerExceptions.java, String NullPointerExceptions.testSystemGetPropertyArgument(), 1, NULL_DEREFERENCE diff --git a/infer/tests/build_systems/expected_outputs/buck_report.json b/infer/tests/build_systems/expected_outputs/buck_report.json index a3762206c..3bda2b043 100644 --- a/infer/tests/build_systems/expected_outputs/buck_report.json +++ b/infer/tests/build_systems/expected_outputs/buck_report.json @@ -474,6 +474,11 @@ "file": "infer/tests/codetoanalyze/java/infer/DynamicDispatch.java", "procedure": "void DynamicDispatch.interfaceShouldNotCauseFalseNegativeHard(DynamicDispatch$Interface)" }, + { + "bug_type": "NULL_DEREFERENCE", + "file": "infer/tests/codetoanalyze/java/infer/InvokeDynamic.java", + "procedure": "void InvokeDynamic.invokeDynamicThenNpeBad(List)" + }, { "bug_type": "RESOURCE_LEAK", "file": "infer/tests/codetoanalyze/java/infer/ResourceLeaks.java", @@ -489,6 +494,11 @@ "file": "infer/tests/codetoanalyze/java/infer/ResourceLeaks.java", "procedure": "void ResourceLeaks.jarOutputStreamLeak()" }, + { + "bug_type": "NULL_DEREFERENCE", + "file": "infer/tests/codetoanalyze/java/infer/InvokeDynamic.java", + "procedure": "int InvokeDynamic.lambda$npeInLambdaBad$1(String,String)" + }, { "bug_type": "RESOURCE_LEAK", "file": "infer/tests/codetoanalyze/java/infer/CloseableAsResourceExample.java", diff --git a/infer/tests/codetoanalyze/java/infer/InvokeDynamic.java b/infer/tests/codetoanalyze/java/infer/InvokeDynamic.java new file mode 100644 index 000000000..142067158 --- /dev/null +++ b/infer/tests/codetoanalyze/java/infer/InvokeDynamic.java @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2016 - present Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + */ + +package codetoanalyze.java.infer; + +import java.util.Collections; +import java.util.List; + +public class InvokeDynamic { + + void invokeDynamicThenNpeBad(List list) { + Object o = null; + Collections.sort(list, (String a, String b) -> { + return b.compareTo(a); + }); + o.toString(); + } + + void npeInLambdaBad(List list) { + Collections.sort(list, (String a, String b) -> { + Object o = null; + o.toString(); + return b.compareTo(a); + }); + } + + // we won't get this one because we don't actually translate the invocation of the lambda + void FN_npeViaCaptureBad(List list) { + String s = null; + Collections.sort(list, (String a, String b) -> { + return s.compareTo(a); + }); + } + +} diff --git a/infer/tests/codetoanalyze/java/infer/issues.exp b/infer/tests/codetoanalyze/java/infer/issues.exp index c6799cfff..7723ef7bb 100644 --- a/infer/tests/codetoanalyze/java/infer/issues.exp +++ b/infer/tests/codetoanalyze/java/infer/issues.exp @@ -153,6 +153,10 @@ HashMapExample.java, void HashMapExample.putIntegerTwiceThenGetTwice(HashMap), 1 HashMapExample.java, void HashMapExample.putIntegerTwiceThenGetTwice(HashMap), 13, RETURN_VALUE_IGNORED HashMapExample.java, void HashMapExample.putIntegerTwiceThenGetTwice(HashMap), 6, RETURN_VALUE_IGNORED HashMapExample.java, void HashMapExample.putIntegerTwiceThenGetTwice(HashMap), 7, RETURN_VALUE_IGNORED +InvokeDynamic.java, int InvokeDynamic.lambda$npeInLambdaBad$1(String,String), 1, ANALYSIS_STOPS +InvokeDynamic.java, int InvokeDynamic.lambda$npeInLambdaBad$1(String,String), 1, NULL_DEREFERENCE +InvokeDynamic.java, void InvokeDynamic.invokeDynamicThenNpeBad(List), 5, ANALYSIS_STOPS +InvokeDynamic.java, void InvokeDynamic.invokeDynamicThenNpeBad(List), 5, NULL_DEREFERENCE JunitAssertion.java, void JunitAssertion.consistentAssertion(JunitAssertion$A), 1, PRECONDITION_NOT_MET JunitAssertion.java, void JunitAssertion.inconsistentAssertion(JunitAssertion$A), 2, ANALYSIS_STOPS JunitAssertion.java, void JunitAssertion.inconsistentAssertion(JunitAssertion$A), 2, NULL_DEREFERENCE diff --git a/opam b/opam index 76dfdaa2d..6c71b22f5 100644 --- a/opam +++ b/opam @@ -30,7 +30,7 @@ depends: [ "core_extended" {>="113.33.03"} "conf-autoconf" "extlib-compat" {>="1.5.4"} - "javalib" {>="2.3.2"} + "javalib" {>="2.3.3"} "ocamlfind" {build} "ounit" {="2.0.0"} "reason" {>="1.4.0"} diff --git a/package.json b/package.json index a98c68c21..d8373c237 100644 --- a/package.json +++ b/package.json @@ -16,7 +16,7 @@ "@opam-alpha/ocaml": "4.2.3", "@opam-alpha/sawja": "^ 1.5.2", "@opam-alpha/atdgen": "^ 1.10.0", - "@opam-alpha/javalib": "^ 2.3.2", + "@opam-alpha/javalib": "^ 2.3.3", "@opam-alpha/extlib-compat": "1.7.0", "@opam-alpha/ounit": "2.0.0", "@opam-alpha/ocp-indent": "1.5.3", diff --git a/yarn.lock b/yarn.lock index 39c78b1c6..302878b22 100644 --- a/yarn.lock +++ b/yarn.lock @@ -132,11 +132,11 @@ dependencies: fieldslib-actual "git://github.com/npm-opam/fieldslib.git#113.33.03" -"@opam-alpha/javalib@^ 2.3.2", "@opam-alpha/javalib@>= 2.3.2": - version "2.3.2" - resolved javalib-2.3.2.tgz#be3b8e6f402256dad773e015430d8c129739899c +"@opam-alpha/javalib@^ 2.3.3", "@opam-alpha/javalib@>= 2.3.2": + version "2.3.3" + resolved javalib-2.3.3.tgz#1cb16fe3bbc6998a13d3ae6725c1189989555a18 dependencies: - javalib-actual "git://github.com/npm-opam/javalib.git#2.3.2" + javalib-actual "git://github.com/npm-opam/javalib.git#2.3.3" "@opam-alpha/js-build-tools@>= 113.33.04 < 113.34.00": version "113.33.4" @@ -680,12 +680,18 @@ opam-installer-bin "https://github.com/yunxing/opam-installer-bin.git" substs "https://github.com/yunxing/substs.git" -"dependency-env@git+https://github.com/reasonml/dependency-env.git", "dependency-env@https://github.com/npm-ml/dependency-env.git", "dependencyEnv@git+https://github.com/reasonml/dependency-env.git": +"dependency-env@https://github.com/npm-ml/dependency-env.git", "dependency-env@https://github.com/reasonml/dependency-env.git": version "0.0.0" resolved dependency-env.git-b6710d7ccc0ea940ce55c4149675dd4ad6a9b94b#1dfad199e8cd9fba48513f85c1383874c7e83e5e dependencies: resolve "^1.1.7" +"dependencyEnv@https://github.com/reasonml/dependency-env": + version "0.0.0" + resolved dependency-env-b6710d7ccc0ea940ce55c4149675dd4ad6a9b94b#1dfad199e8cd9fba48513f85c1383874c7e83e5e + dependencies: + resolve "^1.1.7" + "easy-format-actual@git://github.com/npm-opam/easy-format.git#1.2.0": version "1.2.0" resolved easy-format.git-955d4b4cd1748832aa7fb756c4ba1092759355de#43c15ccebcdf3fdc1412219b080226a3c8b62a54 @@ -719,9 +725,9 @@ opam-installer-bin "https://github.com/yunxing/opam-installer-bin.git" substs "https://github.com/yunxing/substs.git" -"javalib-actual@git://github.com/npm-opam/javalib.git#2.3.2": - version "2.3.2" - resolved javalib.git-b767b73e51bbfb7fc3a420fbe8bb861036d39984#a763fba354b2de5bb9a7a7fd2928674aff45d4ad +"javalib-actual@git://github.com/npm-opam/javalib.git#2.3.3": + version "2.3.3" + resolved javalib.git-e6ef415e81155658efac8ccc98c43963b611b8ec#c7b814034b9f08a77c9feaa40d6fc5fa4de29d68 dependencies: "@opam-alpha/camlp4" "*" "@opam-alpha/camlzip" ">= 1.05.0" @@ -807,7 +813,7 @@ opam-installer-bin "https://github.com/yunxing/opam-installer-bin.git" substs "https://github.com/yunxing/substs.git" -"nopam@git+https://github.com/reasonml/nopam.git", "nopam@https://github.com/yunxing/nopam.git": +"nopam@https://github.com/reasonml/nopam.git", "nopam@https://github.com/yunxing/nopam.git": version "0.0.1" resolved nopam.git-8584695c8e2615857d4f58a0dec7bae3a9059a54#49cd1b4ccc32d588cdd3a671d4cc6d773803396b @@ -845,7 +851,7 @@ opam-installer-bin "https://github.com/yunxing/opam-installer-bin.git" substs "https://github.com/yunxing/substs.git" -"opam-installer-bin@git+https://github.com/yunxing/opam-installer-bin.git", "opam-installer-bin@https://github.com/yunxing/opam-installer-bin.git": +"opam-installer-bin@https://github.com/yunxing/opam-installer-bin.git": version "0.0.0" resolved opam-installer-bin.git-689ede681217f76fb2f82a9f4528e192a5b543ba#b7704eda021a9fe18a9a37454868e1bbf102e0a0 dependencies: @@ -1383,7 +1389,7 @@ resolve@^1.1.7: opam-installer-bin "https://github.com/yunxing/opam-installer-bin.git" substs "https://github.com/yunxing/substs.git" -"substs@git+https://github.com/yunxing/substs.git", "substs@https://github.com/yunxing/substs.git": +"substs@https://github.com/yunxing/substs.git": version "0.0.1" resolved substs.git-fd480dcdb4aed3fa9128fd819a546e3a7770040f#3a935dc6de26a5dfae899eca93a510bae55e57a4 @@ -1411,7 +1417,7 @@ resolve@^1.1.7: opam-installer-bin "https://github.com/yunxing/opam-installer-bin.git" substs "https://github.com/yunxing/substs.git" -"tuareg@github:yunxing/tuareg": +tuareg@yunxing/tuareg: version "1.0.0" resolved a90c0a2f202529a641d369c3b18b0c785a4a7e99#aa3a72a7726b1dd4fd1c809f893cc7ed6d2d420d