// non-nullness can be ensured by: 1. if-else checking 2. try-catch block
Body body = caller.getActiveBody();
// here we will run a nullness analysis, to guarantee that the r9 is checked non-nullness via if-else
NullnessAnalysis nullnessAnalysis = new NullnessAnalysis(new BriefUnitGraph(body));
// we must guarantee that the handler got by reflection is not null
boolean fixed = true;
List<Unit> units = new ArrayList<>(body.getUnits());
int index = units.indexOf(callSiteUnit);
// get all try-catch blocks to get ready for try-catch checking
List<Trap> traps = new ArrayList<>(body.getTraps());
// traverse units after call site, guarantee that invoking of r9 is checked non-nullness
for (int i = index + 1; i < units.size(); i++) {
Unit u = units.get(i);
// u does not invoke r9, skip it
if (!Strings.contains(u.toString(), definedVar.toString() + ".")) { continue; }
// ensure that r9 is non-null via if-else
if (!nullnessAnalysis.isAlwaysNonNullBefore(u, (Immediate) definedVar)) {
// non-nullness can not be guaranteed by if-else,
// then, we must do a try-catch checking
boolean caught = false;
for (Trap trap : traps) {
SootClass exceptionClass = trap.getException();
String exceptionJavaStyleName = exceptionClass.getJavaStyleName();
int bidx = units.indexOf(trap.getBeginUnit());
int eidx = units.indexOf(trap.getEndUnit());
// this trap can catch u, and the exception to be caught
// is a NullPointerException or a NoSuchMethodException
// or a its super classes' instance
if (bidx <= i && i <= eidx &&
("NullPointerException".equals(exceptionJavaStyleName) ||
"NoSuchMethodException".equals(exceptionJavaStyleName) ||
"ReflectiveOperationException".equals(exceptionJavaStyleName) ||
"Exception".equals(exceptionJavaStyleName))
) {
caught = true;
break;
}
}
if (!caught) {
fixed = false;
break;
}
}
}
if (!fixed) {
validatedEdges.add(edge);
}
周报
这次的周报总结一下这段(挺长)时间做的事情,好久没写了,这次也写的稍微多了一点。
回顾
首先还是说一下上一次周报提到的问题,上次周报提到了这么几个问题:
if (null == someMethodHandle)
检查的解决方案,还能预想到一种类似的解决方案,利用 try-catch 来空指针等的捕获异常。someMethodHandle
调用前的是否有空指针检测进行检测,而没有考虑控制流和数据流的问题。正确的处理方式应该是对someMethodHandle
所在的方法进行 nullness analysis,从而保证在someMethodHandle
的每次调用前都能够保证someMethodHandle
的非空性。解决方案
上述 1/2 问题可以合并解决,首先对 someMethodHandle 所在的方法添加一个 NullnessAnalysis,如果每次对 someMethodHandle 的调用都能保证其非空性,我们认为开发者已经将这个 issue 进行了 fix;否则,我们将 (1) 检查此处调用是否在一个 try 语句块中,并 (2) 检查该语句块是否是用来捕获
NullPointerException
/NoSuchMethodException
的语句块,如果 (1) (2) 同时满足我们同样认为开发者已经对这个 issue 进行了 fix。否则,我们认为开发者未能预见这种情况,我们将汇报该条 issue。下面的代码展示了主逻辑部分(代码一直在我本地,昨天刚刚提交到 github 上,代码主要位于RFinder.java
里):虽然 soot/flowdroid 对安卓有了一个假入口函数 FakeMainEntry 的实现,并使我们能够获取到整个的 CFG,但从我们并不能获得正确的 slicing 这点来看,我们猜想这个 CFG 是不完整的,但这一点目前并没有获得证实(我向 soot-email-list 发了两封邮件询问几个有关 soot 的问题,一封是年前发的,一封是前几天发的,但都没有得到回应,真惨,明明我经常收到作者对其他人询问问题的回复),因此这个问题到现在仍然悬而未决,我现有的想法,或者是请教一下刘烨庞师兄像 GreenDroid (Y. Liu, etc) 一样去对 Android 进行一点建模,或者是像 EnergyPatch (A. Banerjee, etc) 一样利用 Dynodroid 获取 EFG,从而获取 CFG,然后抛弃 soot 获取 slicing 的方法,重新写一个 program slicing 的算法(我目前手边和网上也都没有找到一份完整的算法,我目前看到的 program slicing 的说法都很模糊,没看到十分精确、完整的定义),但这样都会极大地(真的是不止一点点地)增大工作量。==不知道 Lili 对这点有没有什么想法?:confused:==
其他工作
除了对上述提到的问题进行思考和部分着手解决,这段时间还在写脚本整理最后 Lili 进行实验的 27 个 App,打算利用现在的版本跑个测试试试,主要是:
if [-d xxx]
这样检查项目的代码存在,因为这脚本跑了不知道几遍。:cry:fic-finder-test-version
分支,过程中发现,有两个项目的两个分支不存在(==不知道是不是 Lili 论文里标错了 commit 号==),分别是"openvpn/9278fa4"
和"owncloud/cfd3b94"
下面先罗列下脚本(不打算上传,所以在这里写一下),然后记录一下期间的问题和解决方案(如果以后真的有问题也方便查看)。
下载 - download.sh
建立分支 - checkout.sh
构建 apk
构建过程中遇到的问题
NDK
ndk
,并将其加入环境变量$PATH
。echo "ndk.dir=${ANDROID_HOME}/../ndk"
警告与错误
因为我们需要测的都是这些项目过去的 commit,其中有一些 api 已经是 deprecated 状态,因此为了不让这些 deprecated api 阻碍我们构建,需要在所有项目的顶层 build.gradle 里加入:
strerror,memmove
有个项目使用了
strerror/memmove
等函数,却没包含头文件,这在某些编译器下是会自动添加到,但在某些编译器(如 clang)下它就挂,它位于头文件string.h
。R.string.xxxx
不存在有几个项目报这个错误,暂时性地在其
res/values/strings.xml
下为所有 i18n 的情况下都加入一条<string name="xxx">whatever</string>
来跳过这个错误,这不会对我们的分析有任何影响,但对 App 有什么影响就未可知了。:slightly_smiling_face:failed to find target with hash string 'Google Inc.:Goole APIs:21'
有几个项目写依赖时采用了这种方式(猜测这应该是一种老式写法),现在不可用了,直接将它们改成 21 (即,只需要写出版本就行)
template
有几个项目需要开发者使用自己在某些站点的用户名和用户密码或者 key 来进行填充,项目开发人员为使用这个项目的开发者提供了一些模板(template)文件,对于这种情况暂时直接使用 template(这也不会对我们的分析有任何影响,但对 App 有什么影响也未可知🙂)
Build Tools Version
有个项目使用了 23.0.0 版本的 build tools,但 sdk manager 里最低版本都是 23.0.1,找不到 23.0.0 的,因此直接把 23.0.0 改成了 23.0.1(这可能会对我们的分析有些许影响,因为我们的分析里需要使用到版本信息,但之所以说些许,是基于假设 “API 的迭代一般不会在小版本里,都是跨版本的”,这个假设的可靠性是基于开发经验和 API 设计角度的,待进一步确认)。
failed to apply plugin [id 'com.android.application']
同样是因为 commit 有点老的问题,对于这种情况,对于 Android Studio 3.0,需要在 build.gradle 里添加(或修改):
对于 Android Studio 2.3,需要改成
classpath 'com.android.tools.build:gradle:2.3.3'
。对于某些需要 23 版本的项目,需要改成
classpath 'com.android.tools.build:gradle:2.2.3'
到目前还未能编译成功的问题