[Java frontend]Javalib's lambda rewritting is making his way through Infer

Reviewed By: ngorogiannis

Differential Revision: D19970219

fbshipit-source-id: b14bb36a4
master
David Pichardie 5 years ago committed by Facebook Github Bot
parent 865691b535
commit 64289cde4d

@ -128,7 +128,13 @@ let proc_inline_synthetic_methods cfg pdesc : unit =
let attributes = Procdesc.get_attributes pd in let attributes = Procdesc.get_attributes pd in
let is_synthetic = attributes.is_synthetic_method in let is_synthetic = attributes.is_synthetic_method in
let is_bridge = attributes.is_bridge_method in let is_bridge = attributes.is_bridge_method in
if is_access || is_bridge || is_synthetic then let is_generated_for_lambda =
String.is_substring ~substring:"$Lambda$" (Procname.get_method pn)
in
(* this is a temporary hack in order to stop synthetic inlining on
methods that are generated for lambda rewritting *)
if is_generated_for_lambda then instr
else if is_access || is_bridge || is_synthetic then
inline_synthetic_method ret_id_typ etl pd loc |> Option.value ~default:instr inline_synthetic_method ret_id_typ etl pd loc |> Option.value ~default:instr
else instr else instr
| exception (Caml.Not_found | Not_found_s _) -> | exception (Caml.Not_found | Not_found_s _) ->

@ -255,9 +255,12 @@ let get_classpath_channel program = program.classpath.channel
let get_models program = program.models let get_models program = program.models
(* this string should characterize the methods we generate for lambda rewriting *)
let lambda_str = "$Lambda$"
let add_class cn jclass program = let add_class cn jclass program =
(* [prefix] must be a fresh class name *) (* [prefix] must be a fresh class name *)
let prefix = JBasics.cn_name cn ^ "$Lambda$" in let prefix = JBasics.cn_name cn ^ lambda_str in
(* we rewrite each class to replace invokedynamic (closure construction) (* we rewrite each class to replace invokedynamic (closure construction)
with equivalent old-style Java code that implements a suitable Java interface *) with equivalent old-style Java code that implements a suitable Java interface *)
let rewritten_jclass, new_classes = Javalib.remove_invokedynamics jclass ~prefix in let rewritten_jclass, new_classes = Javalib.remove_invokedynamics jclass ~prefix in
@ -265,7 +268,9 @@ let add_class cn jclass program =
(* the rewrite will generate new classes and we add them to the program *) (* the rewrite will generate new classes and we add them to the program *)
JBasics.ClassMap.iter JBasics.ClassMap.iter
(fun cn jcl -> program.classmap <- JBasics.ClassMap.add cn jcl program.classmap) (fun cn jcl -> program.classmap <- JBasics.ClassMap.add cn jcl program.classmap)
new_classes new_classes ;
rewritten_jclass
let set_callee_translated program pname = Procname.Hash.replace program.callees pname Translated let set_callee_translated program pname = Procname.Hash.replace program.callees pname Translated
@ -286,7 +291,7 @@ let lookup_node cn program =
with Caml.Not_found -> ( with Caml.Not_found -> (
try try
let jclass = javalib_get_class (get_classpath_channel program) cn in let jclass = javalib_get_class (get_classpath_channel program) cn in
add_class cn jclass program ; Some jclass Some (add_class cn jclass program)
with with
| JBasics.No_class_found _ -> | JBasics.No_class_found _ ->
(* TODO T28155039 Figure out when and what to log *) (* TODO T28155039 Figure out when and what to log *)

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

@ -9,6 +9,7 @@ package codetoanalyze.java.infer;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.function.Function;
public class InvokeDynamic { public class InvokeDynamic {
@ -32,7 +33,8 @@ public class InvokeDynamic {
}); });
} }
// we won't get this one because we don't actually translate the invocation of the lambda // we still don't get this one (even with Javalib lambda rewriting)
// because Collections.sort is skipped
void FN_npeViaCaptureBad(List<String> list) { void FN_npeViaCaptureBad(List<String> list) {
String s = null; String s = null;
Collections.sort( Collections.sort(
@ -41,4 +43,15 @@ public class InvokeDynamic {
return s.compareTo(a); return s.compareTo(a);
}); });
} }
Integer npeViaSimpleCapture() {
String s = null;
Function<String, Integer> f = (s1) -> s.length();
return f.apply(null);
}
Integer npeViaSimpleParamPassing() {
Function<String, Integer> f = (s) -> s.length();
return f.apply(null);
}
} }

@ -100,6 +100,8 @@ codetoanalyze/java/infer/HashMapExample.java, codetoanalyze.java.infer.HashMapEx
codetoanalyze/java/infer/IntegerExample.java, codetoanalyze.java.infer.IntegerExample.testIntegerEqualsBad():void, 5, NULL_DEREFERENCE, B1, ERROR, [start of procedure testIntegerEqualsBad(),Taking true branch] codetoanalyze/java/infer/IntegerExample.java, codetoanalyze.java.infer.IntegerExample.testIntegerEqualsBad():void, 5, NULL_DEREFERENCE, B1, ERROR, [start of procedure testIntegerEqualsBad(),Taking true branch]
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] 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]
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(...)] 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(...)]
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)]
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()]
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] 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]
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] 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]
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] 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]

Loading…
Cancel
Save