Skip to content

Commit 64289cd

Browse files
davidpichardiefacebook-github-bot
authored andcommitted
[Java frontend]Javalib's lambda rewritting is making his way through Infer
Reviewed By: ngorogiannis Differential Revision: D19970219 fbshipit-source-id: b14bb36a4
1 parent 865691b commit 64289cd

File tree

5 files changed

+37
-9
lines changed

5 files changed

+37
-9
lines changed

infer/src/IR/Cfg.ml

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -128,7 +128,13 @@ let proc_inline_synthetic_methods cfg pdesc : unit =
128128
let attributes = Procdesc.get_attributes pd in
129129
let is_synthetic = attributes.is_synthetic_method in
130130
let is_bridge = attributes.is_bridge_method in
131-
if is_access || is_bridge || is_synthetic then
131+
let is_generated_for_lambda =
132+
String.is_substring ~substring:"$Lambda$" (Procname.get_method pn)
133+
in
134+
(* this is a temporary hack in order to stop synthetic inlining on
135+
methods that are generated for lambda rewritting *)
136+
if is_generated_for_lambda then instr
137+
else if is_access || is_bridge || is_synthetic then
132138
inline_synthetic_method ret_id_typ etl pd loc |> Option.value ~default:instr
133139
else instr
134140
| exception (Caml.Not_found | Not_found_s _) ->

infer/src/java/jClasspath.ml

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -255,17 +255,22 @@ let get_classpath_channel program = program.classpath.channel
255255

256256
let get_models program = program.models
257257

258+
(* this string should characterize the methods we generate for lambda rewriting *)
259+
let lambda_str = "$Lambda$"
260+
258261
let add_class cn jclass program =
259262
(* [prefix] must be a fresh class name *)
260-
let prefix = JBasics.cn_name cn ^ "$Lambda$" in
263+
let prefix = JBasics.cn_name cn ^ lambda_str in
261264
(* we rewrite each class to replace invokedynamic (closure construction)
262265
with equivalent old-style Java code that implements a suitable Java interface *)
263266
let rewritten_jclass, new_classes = Javalib.remove_invokedynamics jclass ~prefix in
264267
program.classmap <- JBasics.ClassMap.add cn rewritten_jclass program.classmap ;
265268
(* the rewrite will generate new classes and we add them to the program *)
266269
JBasics.ClassMap.iter
267270
(fun cn jcl -> program.classmap <- JBasics.ClassMap.add cn jcl program.classmap)
268-
new_classes
271+
new_classes ;
272+
rewritten_jclass
273+
269274

270275
let set_callee_translated program pname = Procname.Hash.replace program.callees pname Translated
271276

@@ -286,7 +291,7 @@ let lookup_node cn program =
286291
with Caml.Not_found -> (
287292
try
288293
let jclass = javalib_get_class (get_classpath_channel program) cn in
289-
add_class cn jclass program ; Some jclass
294+
Some (add_class cn jclass program)
290295
with
291296
| JBasics.No_class_found _ ->
292297
(* TODO T28155039 Figure out when and what to log *)

infer/src/java/jTrans.ml

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -217,10 +217,12 @@ let get_bytecode cm =
217217
L.(die InternalError)
218218
"native method %s found in %s@." (JBasics.ms_name ms) (JBasics.cn_name cn)
219219
| Javalib.Java t ->
220-
(* Sawja doesn't handle invokedynamic, and it will crash with a Match_failure if we give it
221-
bytecode with this instruction. hack around this problem by converting all invokedynamic's
222-
to invokestatic's that call a method with the same signature as the lambda on
223-
java.lang.Object. this isn't great, but it's a lot better than crashing *)
220+
(* Java frontend doesn't know how to translate Sawja invokedynamics, but most
221+
of them will be rewritten by Javalib before arriving to Sawja. For the
222+
remainings we (still) use this hack that convert an invokedynamic
223+
into an invokestatic that calls a method with the same signature as the lambda.
224+
But the objective is to never have to do that and hope Javalib rewriting
225+
is complete enough *)
224226
let bytecode = Lazy.force t in
225227
let c_code =
226228
Array.map

infer/tests/codetoanalyze/java/infer/InvokeDynamic.java

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99

1010
import java.util.Collections;
1111
import java.util.List;
12+
import java.util.function.Function;
1213

1314
public class InvokeDynamic {
1415

@@ -32,7 +33,8 @@ void npeInLambdaBad(List<String> list) {
3233
});
3334
}
3435

35-
// we won't get this one because we don't actually translate the invocation of the lambda
36+
// we still don't get this one (even with Javalib lambda rewriting)
37+
// because Collections.sort is skipped
3638
void FN_npeViaCaptureBad(List<String> list) {
3739
String s = null;
3840
Collections.sort(
@@ -41,4 +43,15 @@ void FN_npeViaCaptureBad(List<String> list) {
4143
return s.compareTo(a);
4244
});
4345
}
46+
47+
Integer npeViaSimpleCapture() {
48+
String s = null;
49+
Function<String, Integer> f = (s1) -> s.length();
50+
return f.apply(null);
51+
}
52+
53+
Integer npeViaSimpleParamPassing() {
54+
Function<String, Integer> f = (s) -> s.length();
55+
return f.apply(null);
56+
}
4457
}

infer/tests/codetoanalyze/java/infer/issues.exp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,8 @@ codetoanalyze/java/infer/HashMapExample.java, codetoanalyze.java.infer.HashMapEx
100100
codetoanalyze/java/infer/IntegerExample.java, codetoanalyze.java.infer.IntegerExample.testIntegerEqualsBad():void, 5, NULL_DEREFERENCE, B1, ERROR, [start of procedure testIntegerEqualsBad(),Taking true branch]
101101
codetoanalyze/java/infer/InvokeDynamic.java, codetoanalyze.java.infer.InvokeDynamic.invokeDynamicThenNpeBad(java.util.List):void, 6, NULL_DEREFERENCE, B1, ERROR, [start of procedure invokeDynamicThenNpeBad(...),start of procedure callsite_codetoanalyze.java.infer.InvokeDynamic$Lambda$_3_3(),return from a call to Comparator InvokeDynamic.callsite_codetoanalyze.java.infer.InvokeDynamic$Lambda$_3_3(),Skipping sort(...): unknown method]
102102
codetoanalyze/java/infer/InvokeDynamic.java, codetoanalyze.java.infer.InvokeDynamic.lambda$npeInLambdaBad$1(java.lang.String,java.lang.String):int, 1, NULL_DEREFERENCE, B1, ERROR, [start of procedure lambda$npeInLambdaBad$1(...)]
103+
codetoanalyze/java/infer/InvokeDynamic.java, codetoanalyze.java.infer.InvokeDynamic.npeViaSimpleCapture():java.lang.Integer, 2, PRECONDITION_NOT_MET, no_bucket, WARNING, [start of procedure npeViaSimpleCapture(),start of procedure callsite_codetoanalyze.java.infer.InvokeDynamic$Lambda$_10_3(...),return from a call to Function InvokeDynamic.callsite_codetoanalyze.java.infer.InvokeDynamic$Lambda$_10_3(String)]
104+
codetoanalyze/java/infer/InvokeDynamic.java, codetoanalyze.java.infer.InvokeDynamic.npeViaSimpleParamPassing():java.lang.Integer, 1, PRECONDITION_NOT_MET, no_bucket, WARNING, [start of procedure npeViaSimpleParamPassing(),start of procedure callsite_codetoanalyze.java.infer.InvokeDynamic$Lambda$_11_0(),return from a call to Function InvokeDynamic.callsite_codetoanalyze.java.infer.InvokeDynamic$Lambda$_11_0()]
103105
codetoanalyze/java/infer/JunitAssertion.java, codetoanalyze.java.infer.JunitAssertion.consistentAssertion(codetoanalyze.java.infer.JunitAssertion$A):void, 0, PRECONDITION_NOT_MET, no_bucket, WARNING, [start of procedure consistentAssertion(...),Taking false branch]
104106
codetoanalyze/java/infer/JunitAssertion.java, codetoanalyze.java.infer.JunitAssertion.inconsistentAssertion(codetoanalyze.java.infer.JunitAssertion$A):void, 1, NULL_DEREFERENCE, B5, ERROR, [start of procedure inconsistentAssertion(...),Taking false branch]
105107
codetoanalyze/java/infer/Lists.java, codetoanalyze.java.infer.Lists.clearCausesEmptinessNPE(java.util.List,int):void, 4, NULL_DEREFERENCE, B1, ERROR, [start of procedure clearCausesEmptinessNPE(...),Taking true branch,Taking true branch]

0 commit comments

Comments
 (0)