connglli / ELEGANT

ELEGANT - a tool to Effectively LocatE fraGmentAtion-iNduced compaTibility issues.
MIT License
3 stars 0 forks source link

weekly report: 2017.11.29-2017.12.05 #10

Closed connglli closed 6 years ago

connglli commented 6 years ago

周报

2017.11.29 ~ 2017.12.05

回想上周,我们本周的关注点只有一个:如何提高 canHandleIssue 的精确性,并进一步降低误报率。

提高精确性

上周我们提到,要提高精确性可能要涉及到对判断语义的理解。目前打算的实现方式是这样的:

首先对现在的 slicing 进行改写,目前的 slicing 是 Unit 的集合,现在打算将 slicing 改为 从 ObjectSet<Unit> 的映射,即 map<Object, Set<Unit>>

根据我们寻找 slicing 的算法,我们知道:

slice = "dependents of a Callsite" + 
        "dependents of some IfStmts"

Callsite 的依赖通常是一系列 Unit。而 IfStmt 的依赖则是它所使用的两个变量的依赖语句。对于 IfStmt,若其中一个变量是某个方法的返回值,那么我们将对该方法的所有语句进行遍历,对其中使用“特殊字串”(如 android.os.Build$VERSION: int SDK_INT 等)定义的变量及使用过它的 IfStmt 语句(及其依赖)进行递归查找,并以 Value -> Set<Unit> 的映射存储。即,我们构造的 slicing 将是如下的形式:

slicing = {
  Callsite: dependent Units of Callsite,
  IfStmt1: 2 definition Units of 2 variables used by IfStmt1,
  Value1:  Units which defines or uses Value1, and Value1 is a value used by some IfStmt,
  ...
}

这样,在 canHandleIssue 的时候,我们采用以下启发式方式来检测是否能够被处理:

使用现在的方式,即检测其 slicing 中是否包含相应的字符串。

将对语义进行解析:上面提到,IfStmt 的依赖一般是 IfStmt 使用的变量的定义语句,因此,我们将:

假设该 IfStmt 使用的两个 expr 为 e1 和 e2:
  1. 若 ei(i = 1,2) 为常量,且为 0 或者 1,且 ej(j != i,j = 1,2)
     为变量,令 ej 的定义语句为 dj:
    1.1. 若 dj 包含方法调用语句,且该调用语句的参数部分(一般是个数字)满足我们的
      acpair(在最大最小值之间),我们认为该处被 fix。
  2. 若 ei(i = 1,2) 为常量,且不为 0 也不为 1,且 ej(j != i,j = 1,2)
    为变量,令 ej 的定义语句为 dj:
    2.1. 若 dj 包含相应的字符串,且 ei 对应的常量满足我们的 acpair,我们认为该处
      被 fix。
  3. 对其他任何情况,我们都认为该 IfStmt 不能 fix 此处。

上述提到的两种 fix 方式一般对应于以下两种 fix 方式:

1.1 if (Xxx.isCompatible(11)) { ... }

2.1 if (os.Build.VERSION.SDK_INT > 11) { ... }

我们将随着测试用例的增加进一步扩展对 IfStmt 的检测

我们将按照上述提到的 IfStmt 的检测方式对每条使用该 Value 的 IfStmt 进行检测。

降低误报率

关于误报率,这几天在测试的时候发现,(我)目前的实现还是有提高误报率的操作,是在 computeCallsite 的时候:

我们知道,callgraph 是程序的静态表示,其中并不包含控制流信息,因此利用我们寻找到的仅仅针对某个 acpair.api 的 callsites 并不能精确地告诉我们该 acpair 在某个 callsite 处是否被 fix。说起来可能很费力,举个例子:

private void _acpair_check_getActionBar() {
  ActionBar actionBar = getActionBar();
  actionBar.setTitle("123");
}

private void directCheck() {
  if (Build.VERSION.SDK_INT > 11) {
    _acpair_check_getActionBar();
  }
}

上面的代码中,getActionBar 在 api < 11 的时候是个 FIC issue,无论是利用 callgraph 还是像 Lili 一样一条一条语句地进行检测,我们最终找到的 callsite 都是第 2 行,即 _acpair_check_getActionBar 会调用 getActionBar,而对第 2 行的代码利用我们目前的方式进行 slicing 的时候实际上并不能追溯到 directCheck 方法(或许真正的 SDG 可以追溯到,因为 SDG 里面包含了控制流和数据流信息),所以利用 fic-finder 在进行检测的时候会报告第 2 行有个 FIC issue 没有被 fix,但显然这是一个 FP(因为第 7 行已经 fix 掉了)。

不知道 Lili 的实现里有没有可能这种会误报的情况。目前我考虑的针对这种问题的解法也跟之前提到的 IfStmt 寻找类似,即寻找 K 层调用,不光寻找某个 acpair.api 的 caller(我们暂称为 acpair.api 的 direct caller ),还要寻找 acpair.api.direct_caller 的 caller(我们暂称为 acpair.api 的 1-indirect-caller),一直找到 acpair.api 的 K-indirect-caller。

总结

  1. 上面的所有思考是这周在一遍进行测试的时候一边想到的,现在还没有转换为代码,其中应该也有一些问题,Lili 和 许老师 先看下,讨论一下其中可能存在的问题并进行修正后再转换为代码。
  2. 我已经提前把代码转换到了安卓,因为在做纯 java 的时候对一些 fix 方式还是不是很好模拟。代码在 [j2a]() 分支