function ReflectionFixing(acpair) do
collect all call sites of "<java.lang.Class: java.lang.reflect.Method getMethod(java.lang.String,java.lang.Class[])>" save them to S
for each call site s in S do
if (s gets the handler of acpair.api) {
r = s.return value
for each invoking point p on r do
if (does not check non-nullness of r before p) then
report p
fi
done
}
done
done
解释一下:
对代码中所有对 <java.lang.Class: java.lang.reflect.Method getMethod(java.lang.String,java.lang.Class[])> 的 call site 进行查找,并存在集合 S 中(第 2 行)。对于 S 中的每一处调用 s (第 3 行),如果 s 是对 acpair.api 的调用(第 4 行),对 s 的返回值 r 进行保存,并检测对 r 之后的所有调用点 p(第 6 行),如果 p 之前没有对 r 非空的判断(第 7 行),认为 s 没解决掉这个 FIC bug,并对这处进行报告。否则,继续进行遍历 S。
周报
停了近一个月的 FicFinder,这周又开始工作了!先回顾一下上次 FicFinder 周报的内容:
回顾
上次对
AnkiDroid
几个有问题(buggy)以及问题被解决后(fixed)提交版本对进行了编译,并根据编译和目前 FicFinder 的测试结果给出了几种问题解决方式(bug fixing manner):上次提到,针对以上 1-4 目前的 FicFinder 已经可以解决(针对目前的测试,还需要更多的测试来巩固和加强),但针对 4、5 仍无法完成,并且给出了针对 4、5 的简单的解决方案描述,本周针对上次的描述进行了实现,同时对遇到的新问题进行阐述。
relfection-fixing
上周提到,针对这种形式的解决开发者(可能会以如下的方式解决):
因此针对这种形式我们的解决方案如下:
解释一下:
对代码中所有对
<java.lang.Class: java.lang.reflect.Method getMethod(java.lang.String,java.lang.Class[])>
的 call site 进行查找,并存在集合S
中(第 2 行)。对于S
中的每一处调用s
(第 3 行),如果s
是对 acpair.api 的调用(第 4 行),对s
的返回值r
进行保存,并检测对r
之后的所有调用点p
(第 6 行),如果p
之前没有对r
非空的判断(第 7 行),认为s
没解决掉这个 FIC bug,并对这处进行报告。否则,继续进行遍历S
。针对这部分的代码位于
src/com/example/ficfinder/reflectionfinder/RFinder.java
中。polymorphis-fixing
上周提到,针对这种形式的解决开发者(可能会以如下的方式解决):
针对这样的解决,我们仍然沿用以前的方式,并对以前的代码进行了部分修正,从而完成这部分的检测。
问题
利用目前的 FicFinder 来对上周提到的编译版本进行测试,除了
invalidateOptionsMenu
这个例子外其他都三个都已通过(buggy 版本能够检测到,fixed 版本检测不到),现在来阐述下一些目前能想到的但仍待解决的问题:对于 reflection-fixing,除了上述的解决方案,还能预想到一种类似的解决方案:
即开发者会利用异常处理来进行处理,对这种情况,我们目前还未覆盖。
对于 reflection-fixing,仔细考虑会发现,我们的实现存在以下的问题:
上面关于
ReflectionFixing
的伪代码第 7 行,我们很含糊的表述了 “如果每处r
的调用p
前都有 non-nullness 的检测”,但我们目前的实现却仅仅是对没处调用前面的部分进行if
语句的判断,这显然是 unsound 的。正确的方式应该是对该处调用p
所在的方法进行一个空指针分析,从而保证p
前(CFG前)一定有/可能没有 non-nullness 的检测。因此下周的第一个任务就是利用 Soot 实现一个 intra-procedural 的空指针分析。对于任何形式的解决方案,我们提到,我们在剪枝阶段是检测调用链上每个调用点附近是否有对该 FIC issue 的解决,但这样形成的调用链没有考虑安卓生命周期的问题,考虑下面的情况:
可以看到,我们上面的代码实际上对
invalidateOptionsMenu
这个 FIC bug 进行了修正,但从调用链上却显示不出来:因此剪枝无法对这样的情况进行处理,考虑造成这种情况的根本原因,其实是安卓生命周期(或者说是 event driven 的方式)造成了 inter-producedural 的 CFG 不完整,导致我们无法获取到正确的 slicing 造成的。对这种问题如何解决,目前还在考虑(这也是
invalidateOptionsMenu
这个测试不通过的原因)。其他
另外,本周还对代码进行了部分重构,现在结构如下:
com.example.ficfinder.finder.reflectionfinder 中的
RFinder
主要完成对 reflection-fixing 的工作,plainfinder 中的PFinder
完成其他工作RFinder
和PFinder
都是AbstractFinder
的实现。一个AbstractFinder
包括:detection
/validation
/generation
三个部分,(顾名思义,)分别完成对一个 api-context pair 的检测与构建、剪枝、生成 issue 三方面的工作。代码仍然在 call-site-tree 分支。