Java8 invokevirtual resolution should search into super interfaces

Summary:
Since Java8, interfaces mays contain implementations
(default methods). We modify the resolve algorith in the Java frontend
to take care of that.

Reviewed By: jvillard

Differential Revision: D21785182

fbshipit-source-id: ffab8124c
master
David Pichardie 5 years ago committed by Facebook GitHub Bot
parent 1459505540
commit dbdd4413a7

@ -599,28 +599,47 @@ let rec expression (context : JContext.t) pc expr =
let method_invocation (context : JContext.t) loc pc var_opt cn ms sil_obj_opt expr_list invoke_code
method_kind =
(* This function tries to recursively search for the classname of the class *)
(* where the method is defined. It returns the classname given as argument*)
(* when this classname cannot be found *)
(* This function tries to recursively search for the classname of the class
where the method is defined. Following Java8 invokevirtual spec, it
searches first in parent classes. Then, if nothing is found, it searches in super
interfaces. If nothing is found, it returns the classname given as argument. *)
let contains_ms_implem node ms =
match node with
| Javalib.JInterface {i_methods= mmap} | Javalib.JClass {c_methods= mmap} ->
if JBasics.MethodMap.mem ms mmap then
match JBasics.MethodMap.find ms mmap with
| Javalib.AbstractMethod _ ->
false
| Javalib.ConcreteMethod _ ->
true
else false
in
let resolve_method (context : JContext.t) cn ms =
let rec loop fallback_cn cn =
let rec search_in_parents get_parents cn =
match JClasspath.lookup_node cn context.program with
| None ->
fallback_cn
| Some node -> (
if Javalib.defines_method node ms then cn
else
match node with
| Javalib.JInterface _ ->
fallback_cn
| Javalib.JClass jclass -> (
match jclass.Javalib.c_super_class with
| None ->
fallback_cn
| Some super_cn ->
loop fallback_cn super_cn ) )
None
| Some node ->
if contains_ms_implem node ms then Some cn
else List.find_map (get_parents node) ~f:(search_in_parents get_parents)
in
let super_classes = function
| Javalib.JInterface _ ->
[]
| Javalib.JClass {c_super_class} ->
Option.to_list c_super_class
in
loop cn cn
let super_interfaces = function
| Javalib.JInterface {i_interfaces} ->
i_interfaces
| Javalib.JClass {c_interfaces} ->
c_interfaces
in
match search_in_parents super_classes cn with
| None ->
Option.value ~default:cn (search_in_parents super_interfaces cn)
| Some cn_implem ->
cn_implem
in
let cn' = resolve_method context cn ms in
let tenv = JContext.get_tenv context in

@ -0,0 +1,27 @@
/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
interface I {
default Object defaultMethod1() {
return null;
}
default Object defaultMethod2() {
return "foo";
}
}
public class DefaultInInterface implements I {
public void bad() {
System.out.println(this.defaultMethod1().toString());
}
public void ok() {
System.out.println(this.defaultMethod2().toString());
}
}

@ -38,6 +38,7 @@ codetoanalyze/java/biabduction/CursorLeaks.java, codetoanalyze.java.infer.Cursor
codetoanalyze/java/biabduction/CursorNPEs.java, codetoanalyze.java.infer.CursorNPEs.cursorFromContentResolverNPE(java.lang.String):void, 8, NULL_DEREFERENCE, B1, ERROR, [start of procedure cursorFromContentResolverNPE(...)]
codetoanalyze/java/biabduction/CursorNPEs.java, codetoanalyze.java.infer.CursorNPEs.cursorFromDownloadManagerNPE(android.app.DownloadManager):int, 5, NULL_DEREFERENCE, B2, ERROR, [start of procedure cursorFromDownloadManagerNPE(...)]
codetoanalyze/java/biabduction/CursorNPEs.java, codetoanalyze.java.infer.CursorNPEs.cursorFromMediaNPE():void, 2, NULL_DEREFERENCE, B1, ERROR, [start of procedure cursorFromMediaNPE()]
codetoanalyze/java/biabduction/DefaultInInterface.java, DefaultInInterface.bad():void, 1, NULL_DEREFERENCE, B1, ERROR, [start of procedure bad(),start of procedure defaultMethod1(),return from a call to Object I.defaultMethod1()]
codetoanalyze/java/biabduction/DivideByZero.java, codetoanalyze.java.infer.DivideByZero.callDivideByZeroInterProc():int, 1, DIVIDE_BY_ZERO, no_bucket, ERROR, [start of procedure callDivideByZeroInterProc(),start of procedure divideByZeroInterProc(...)]
codetoanalyze/java/biabduction/DivideByZero.java, codetoanalyze.java.infer.DivideByZero.divByZeroLocal(java.lang.String):int, 3, DIVIDE_BY_ZERO, no_bucket, ERROR, [start of procedure divByZeroLocal(...)]
codetoanalyze/java/biabduction/DivideByZero.java, codetoanalyze.java.infer.DivideByZero.divideByZeroWithStaticField():int, 2, DIVIDE_BY_ZERO, no_bucket, ERROR, [start of procedure divideByZeroWithStaticField(),start of procedure setXToZero(),return from a call to void DivideByZero.setXToZero(),start of procedure divideByZeroInterProc(...)]

@ -106,7 +106,7 @@ codetoanalyze/java/quandary/Intents.java, codetoanalyze.java.quandary.Intents.ex
codetoanalyze/java/quandary/Intents.java, codetoanalyze.java.quandary.Intents.reuseIntentBad(android.app.Activity):void, 1, INSECURE_INTENT_HANDLING, no_bucket, ERROR, [Return from Intent Activity.getIntent(),Call to void Activity.startActivity(Intent) with tainted index 1]
codetoanalyze/java/quandary/Intents.java, codetoanalyze.java.quandary.Intents.startWithUri1Bad(android.net.Uri):void, 1, CREATE_INTENT_FROM_URI, no_bucket, ERROR, [Return from Intent.<init>(String,Uri),Call to void Activity.startActivity(Intent) with tainted index 1]
codetoanalyze/java/quandary/Intents.java, codetoanalyze.java.quandary.Intents.startWithUri2Bad(android.net.Uri):void, 1, CREATE_INTENT_FROM_URI, no_bucket, ERROR, [Return from Intent.<init>(String,Uri,Context,Class),Call to void Activity.startActivity(Intent) with tainted index 1]
codetoanalyze/java/quandary/Intents.java, codetoanalyze.java.quandary.Intents.subclassCallBad(codetoanalyze.java.quandary.IntentSubclass,codetoanalyze.java.quandary.ContextSubclass):void, 3, QUANDARY_TAINT_ERROR, no_bucket, ERROR, [Return from Object InferTaint.inferSecretSource(),Call to void Context.startActivity(Intent) with tainted index 1]
codetoanalyze/java/quandary/Intents.java, codetoanalyze.java.quandary.Intents.subclassCallBad(codetoanalyze.java.quandary.IntentSubclass,codetoanalyze.java.quandary.ContextSubclass):void, 3, QUANDARY_TAINT_ERROR, no_bucket, ERROR, [Return from Object InferTaint.inferSecretSource(),Call to void ContextSubclass.startActivity(Intent) with tainted index 1]
codetoanalyze/java/quandary/Intents.java, codetoanalyze.java.quandary.MyActivity.startServiceWithTaintedIntent():void, 2, CREATE_INTENT_FROM_URI, no_bucket, ERROR, [Return from Intent.<init>(String,Uri),Call to ComponentName ContextWrapper.startService(Intent) with tainted index 1]
codetoanalyze/java/quandary/Interprocedural.java, codetoanalyze.java.quandary.Interprocedural.FP_divergenceInCallee():void, 3, QUANDARY_TAINT_ERROR, no_bucket, ERROR, [Return from Object InferTaint.inferSecretSource(),Call to void InferTaint.inferSensitiveSink(Object) with tainted index 0]
codetoanalyze/java/quandary/Interprocedural.java, codetoanalyze.java.quandary.Interprocedural.FP_reassignInCallee():void, 4, QUANDARY_TAINT_ERROR, no_bucket, ERROR, [Return from Object InferTaint.inferSecretSource(),Call to void InferTaint.inferSensitiveSink(Object) with tainted index 0]

Loading…
Cancel
Save