soot-oss / SootUp

A new version of Soot with a completely overhauled architecture
https://soot-oss.github.io/SootUp/
GNU Lesser General Public License v2.1
593 stars 81 forks source link

[Bug]: A flaw in the implementation of the Class Hierarchy Algorithm #1101

Open p4d0rn opened 1 month ago

p4d0rn commented 1 month ago

What happened?

Some cases in the Class Hierarchy Algorithm are not considered. The program for inputting into the CHA is as follows:

package org.demo;

class A {
    public void foo(){}
}

class B extends A {
}

class C extends B{
    @Override
    public void foo() {
        super.foo();
    }
}

The Call Graph result is <org.demo.C: void foo()> -> <org.demo.B: void foo()> But the expected result should be <org.demo.C: void foo()> -> <org.demo.A: void foo()>

In class C, the foo method contains a call to the parent class's foo method. (super.foo(); is a specialinvoke) However, it is clear that class B's foo method inherits from the parent class A.

let's examine the resolveCall method of the ClassHierarchyAnalysisAlgorithm class.

  SootMethod targetMethod = findConcreteMethod(view, targetMethodSignature).orElse(null);

  if (targetMethod == null
      || MethodModifier.isStatic(targetMethod.getModifiers())
      || (invokeExpr instanceof JSpecialInvokeExpr)) {
    return Stream.of(targetMethodSignature);
  }

If the invocation statement is a JSpecialInvokeExpr, return the method signature of the current invocation expression which is the variable targetMethodSignature. In the above case, if targetMethod is not null, resolveCall should return targetMethod.getSignature() for JSpecialInvokeExpr. This is because when calling a method from the parent class, the callee method could be a method that was inherited (not overridden) from its parent class. For the two other cases of JSpecialInvokeExpr, which are the invocation of constructor methods and private methods, this issue does not exist. Additionally, static methods can also be inherited, so looking at the method signature alone cannot determine the class where the target method resides.

Therefore, it is recommended to make the following modifications:

SootMethod targetMethod = findConcreteMethod(view, targetMethodSignature).orElse(null);

if (targetMethod == null) {
    return Stream.of(targetMethodSignature);
}

if(MethodModifier.isStatic(targetMethod.getModifiers())
        || (invokeExpr instanceof JSpecialInvokeExpr)){
    return Stream.of(targetMethod.getSignature());
}

Version

Latest develop branch

Relevant log output

see above.