Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix virtualinvoke #71

Open
wants to merge 2 commits into
base: master
Choose a base branch
from

Conversation

Akk0-Kagari
Copy link

修正动态绑定机制导致方法调用产生的误报问题

问题介绍:

https://droidyue.com/blog/2014/12/28/static-biding-and-dynamic-binding-in-java/

测试中我编写了这样的三个具有继承关系的类以及一个测试类,且其中一个子类方法进行了重写,

class Caller {
    public void call(String str) {
        System.out.println("a String instance in Caller");
    }
}

class SubCaller extends Caller {
}

class SubSubCaller extends SubCaller {
    @Override
    public void call(String str) {
        System.out.println("a String instance in SubCaller");
    }
}

public class RuntimeTest{
    Caller thisCaller = new Caller();

    public static void main(String[] args){
        RuntimeTest runtimeTest = new RuntimeTest();
        runtimeTest.runTest();
    }

    public void runTest(){
        String s = new String();
        this.thisCaller.call(s);
        Caller caller = new SubCaller();
        caller.call(s);
        Caller caller1 = new SubSubCaller();
        caller1.call(s);
    }
}

以下是生成的Jimple,可以发现如果仅考虑调用语句的方法签名会导致生成错误的调用关系

public void runTest()
 {
        SubCaller $r3;
        Caller $r2;
        java.lang.String $r0;
        RuntimeTest r1;
        SubSubCaller $r4;

        r1 := @this: RuntimeTest;

        $r0 = new java.lang.String;

        specialinvoke $r0.<java.lang.String: void <init>()>();

        $r2 = r1.<RuntimeTest: Caller thisCaller>;

        virtualinvoke $r2.<Caller: void call(java.lang.String)>($r0);

        $r3 = new SubCaller;

        specialinvoke $r3.<SubCaller: void <init>()>();

        virtualinvoke $r3.<Caller: void call(java.lang.String)>($r0);

        $r4 = new SubSubCaller;

        specialinvoke $r4.<SubSubCaller: void <init>()>(); 

        virtualinvoke $r4.<Caller: void call(java.lang.String)>($r0); //错误的调用

        return;
    }

解决方案

该问题只会在virtual invoke中发生,因此在我修改的代码中仅对该情况进行了考虑:
修改前:

// virtualinvoke $r4.<Caller: void call(java.lang.String)>($r0);
SootClass cls = invokeExpr.getMethod().getDeclaringClass(); //Caller
SootMethod invokedMethod = invokeExpr.getMethod(); //<Caller: void call(java.lang.String)>

MethodReference methodRef = dataContainer
                .getOrAddMethodRef(invokeExpr.getMethodRef(), invokedMethod);

修改后

if (invokeExpr instanceof VirtualInvokeExpr) {
    // 尝试访问base查找caller的实际类型
    VirtualInvokeExpr virtualInvokeExpr = (VirtualInvokeExpr) invokeExpr; 
    Type type = virtualInvokeExpr.getBase().getType(); //$r4 --> SubSubCaller
    cls = SemanticHelper.getSootClass(type.toString());
    if (cls != null && !virtualInvokeExpr.getMethod().
            getDeclaringClass().getName().equals(cls.getName())){ //方法声明类与base类型不同
        try{
            // 当前caller对象所在类中重写了该方法
            String subSignature = invokeExpr.getMethod().getSubSignature(); 
            invokedMethod = cls.getMethod(subSignature); 
            targetMethodRef = Scene.v().makeMethodRef(cls, invokedMethod.getName(), invokedMethod.getParameterTypes(),
                    invokedMethod.getReturnType(),invokedMethod.isStatic());
        }catch(RuntimeException runtimeException){
            // 类中没有重写该方法,直接使用父类方法,cls保留caller类型,这种情况对应 SubCaller
            invokedMethod = invokeExpr.getMethod();
            targetMethodRef = invokeExpr.getMethodRef();
        }
    }
}
if (invokedMethod == null){
    // 上述情况的补集,同时处理其他invoke类型
    cls = invokeExpr.getMethod().getDeclaringClass();
    invokedMethod = invokeExpr.getMethod();
    targetMethodRef = invokeExpr.getMethodRef();
}

@wh1t3p1g
Copy link
Owner

wh1t3p1g commented Dec 1, 2023

你好,感谢提交。
关于这个问题,1.x 版本构建的是CHA,暂时没有处理这种情况,最早设计的方案是通过tabby-path-finder去处理的。
另外,这个问题下个版本已经处理了,因为很久没有看之前版本的代码了,最近有时间把这部分代码更新一下。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants