简单看下 Tai-e 源码

官方文档代码仓库ISSTA 2023 论文静态程序分析框架“太阿”的设计之道

已完成全部作业,简单看下 Tai-e 科研版是如何实现作业的,以及作业涉及的部分接口和类的源码。

在分析的实现中,Stream 使用的比较多,然后就是某些比较好用的 API 在作业中没有注意到,代码中也有使用高版本 Java 的某些新特性。基本上每个包都有 package-info.java 文件,描述当前包的关键信息,还是很不错的。我没怎么看和作业关系不大的源码,它涉及到的东西比较多,需要额外的理论知识。

IR

FieldRef

特点:私有构造函数和静态工厂方法;Record Classes;缓存实例对象;向方法传递 Runnable 类型的对象来实现回调

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
public class FieldRef extends MemberRef {

private static final ConcurrentMap<Key, FieldRef> map =
Maps.newConcurrentMap(4096);

static {
World.registerResetCallback(map::clear);
}

public static FieldRef get(
JClass declaringClass, String name, Type type, boolean isStatic) {
Key key = new Key(declaringClass, name, type);
return map.computeIfAbsent(key, k -> new FieldRef(k, isStatic));
}

private FieldRef(Key key, boolean isStatic) {
...
}

private record Key(JClass declaringClass, String name, Type type) {
}
}

Var

特点:使用内部类存储和当前 Var 相关的语句,而不是直接包含在当前类中;使用 transientwriteObjectreadObject 显示控制序列化,避免反序列化创建多个单例对象;使用 Collections.unmodifiableList 方法返回不可修改的列表。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
public class Var implements LValue, RValue, Indexable {

private transient RelevantStmts relevantStmts = RelevantStmts.EMPTY;

@Serial
private void writeObject(ObjectOutputStream s) throws IOException {
s.defaultWriteObject();
if (relevantStmts == RelevantStmts.EMPTY) {
s.writeObject(null);
} else {
s.writeObject(relevantStmts);
}
}

@Serial
private void readObject(ObjectInputStream s) throws IOException,
ClassNotFoundException {
s.defaultReadObject();
relevantStmts = (RelevantStmts) s.readObject();
if (relevantStmts == null) {
relevantStmts = RelevantStmts.EMPTY;
}
}

private static class RelevantStmts implements Serializable {

private static final RelevantStmts EMPTY = new RelevantStmts();

private static <T> List<T> unmodifiable(List<T> list) {
return list.isEmpty() ? list : Collections.unmodifiableList(list);
}
}
}

Stmt

特点:Stmt 包含以 StmtVisitor 类型作为参数的 accept 泛型方法,可以用于实现访问者模式

1
2
3
4
public interface Stmt extends Indexable, Serializable {

<T> T accept(StmtVisitor<T> visitor);
}
1
2
3
4
5
6
7
8
9
10
11
public interface StmtVisitor<T> {

default T visit(New stmt) {
return visitDefault(stmt);
}

default T visitDefault(Stmt stmt) {
return null;
}
}

DefinitionStmt

特点:使用 <L extends LValue, R extends RValue> 泛型,对表达式进行限定,所有具体的子类都会使用具体的类型替换限定的类型。

1
2
DefinitionStmt<L extends LValue, R extends RValue>
Invoke extends DefinitionStmt<Var, InvokeExp>

Analysis

特点:LiveVariable 的实现,删除变量使用 ifPresent + lambda 处理,代码比较简洁。ConstantPropagationnewBoundaryFact 使用 Stream 来实现,而我是使用普通的方式实现的。Evaluator 类中的 evaluate 方法,使用了扩展的 Switch Expressions,可以省略 breakInterConstantPropagation 实现 Alias-Aware 时,使用访问者模式处理 Load 和 Store 语句。指针分析和作业时区别比较大,没有细看。

核心组成

作者

Ligh0x74

发布于

2024-08-30

更新于

2024-08-31

许可协议

评论