【静态分析】软件分析课程实验A1-活跃变量分析和迭代求解器

1 作业导览

  • 为 Java 实现一个活跃变量分析(Live Variable Analysis)。
  • 实现一个通用的迭代求解器(Iterative Solver),用于求解数据流分析问题,也就是本次作业中的活跃变量分析。

Live Variable Analysis 详见【静态分析】静态分析笔记03 - 数据流分析(应用)-CSDN博客。

我们已经在 Tai-e 的框架代码中提供了你需要的一切基础设施,包括但不限于:程序分析接口、常用数据结构(如数据流信息的表示)、必要的程序信息(如控制流图)等内容。由此,你就可以便利地在 Tai-e 上实现各类数据流分析了。例如在本次作业中,你要在框架代码中补全一些关键部分,从而实现要求的活跃变量分析与迭代求解器。

需要特别注意的是,所有作业文档都只会简要地介绍本次作业中必要的一些 API。因此,如果要搞清楚 API 的实现机制、真正理解框架代码,你必须留出时间阅读、理解相关类的源代码和相应的注释。这是你提升快速上手复杂代码能力的必经之路。

2 实现活跃变量分析

2.1 Tai-e 中你需要了解的类

为了在 Tai-e 中实现活跃变量分析,你需要了解的类有:

  • pascal.taie.analysis.dataflow.analysis.DataflowAnalysis

    这是一个抽象的数据流分析类,是具体的数据流分析与求解器之间的接口。也就是说,一个具体的数据流分析(如活跃变量分析)需要实现它的接口,而求解器(如迭代求解器)需要通过它的接口来求解数据流。

    需要注意的是,这里的API与课程中介绍的稍有区别:为了简单起见,这里的transfer函数处理的是单条语句而非程序块。

  • pascal.taie.ir.exp.Exp

    这是 Tai-e 的 IR 中的一个关键接口,用于表示程序中的所有表达式。它含有很多子类,对应各类具体的表达式。下面是一个 Exp 类继承结构的简单图示:

在 Tai-e 的 IR 中,我们把表达式分为两类:LValue 和 RValue。前者表示赋值语句左侧的表达式,如变量(x = … )、字段访问(x.f = …)或数组访问(x[i] = …);后者对应地表示赋值语句右侧的表达式,如数值字面量(… = 1;)或二元表达式(… = a + b;)。而有些表达式既可用于左值,也可用于右值,就比如变量(用Var类表示)。因为本次作业只进行活跃变量分析,所以你实际上只需要关注 Var 类就足够了。

pascal.taie.ir.stmt.Stmt

这是 Tai-e 的 IR 中的另一个关键接口,它用于表示程序中的所有语句。对于一个典型的程序设计语言来说,每个表达式都属于某条特定的语句。为了实现活跃变量分析,你需要获得某条语句中定义或使用的所有表达式中的变量。Stmt 类贴心地为这两种操作提供了对应的接口:

Optional<LValue> getDef()
List<RValue> getUses()

每条 Stmt 至多只可能定义一个变量、而可能使用零或多个变量,因此我们使用 Optional 和 List 包装了 getDef()getUses() 的结果。

  • pascal.taie.analysis.dataflow.fact.SetFact<Var>

    这个泛型类用于把 data fact 组织成一个集合。它提供了各种集合操作,如添加、删除元素,取交集、并集等。

  • pascal.taie.analysis.dataflow.analysis.LiveVariableAnalysis

    这个类通过实现 DataflowAnalysis 的接口来定义具体的活跃变量分析。你需要按照第 2.2 节中的说明补全这个类。

需要注意:

  • 本次作业的每个基本块仅含有一条指令
  • 实验的结果最后存储在参数 DataflowResult<Node, Fact> result
  • 用到了Java的一些特性
    • Optional特性:isPresent() 和 get()的使用
    • 泛型特性

2.2 你的任务

你的第一个任务是实现 LiveVariableAnalysis 中的如下 API:

  • SetFact newBoundaryFact(CFG)
  • SetFact newInitialFact()
  • void meetInto(SetFact,SetFact)
  • boolean transferNode(Stmt,SetFact,SetFact)

此处 meetInto() 的设计可能与你设想的稍有差别:它接受 facttarget 两个参数并把 fact 集合并入 target 集合。这个函数有什么用呢?考虑一下上图中 meetInto() 附近的那行伪代码,它会取出 B 的所有后继,然后把它们 IN facts 的并集赋给 OUT[B]。如果这行代码用 meetInto() 来实现,那么我们就可以根据下图所示,用 meetInto(IN[S], OUT[B])B 的每个后继 SIN fact 直接并入到 OUT[B] 中:

这种设计还有更多的优化空间:我们可以忽略一些不变的 IN fact 来提高效率。例如在某次迭代中,如果 IN[S2] 有改变而 IN[S3] 没有,我们就不必依照课堂上讲述的办法求出 IN[S2]IN[S3] 的并,而大可以忽略 IN[S3],只把 IN[S2] 并入 OUT[S1]。不过这个优化超出了本次作业的范畴,你不用考虑实现它。

当然,为了实现上面所说的 meet 策略,你需要在初始化阶段给每条语句的 OUT[S] 赋上和 IN[S] 一样的初值。

除了 meetInto() ,其他 API 的实现都直接依照了课上讲述的算法。需要注意的是,框架中LiveVariableAnalysis 的 API 都继承自 DataflowAnalysis,而该类为了支持各种数据流分析,接口中可能包含了一些你用不上的参数。因此,某些参数在作业中用不上是正常现象。

我们已经提供了四个 API 的框架代码,你的任务就是补全标有“TODO – finish me”的部分。

import pascal.taie.ir.exp.*;
import java.util.List;
import java.util.Optional;/*** Implementation of classic live variable analysis.*/
public class LiveVariableAnalysis extendsAbstractDataflowAnalysis<Stmt, SetFact<Var>> {/*** 负责创建和初始化虚拟结点的 Data Flow Fact** @return 初始化好的节点*/@Overridepublic SetFact<Var> newBoundaryFact(CFG<Stmt> cfg) {// TODO - finish mereturn new SetFact<>();}/*** 负责创建和初始化控制流图中除了 Entry 和 Exit 之外的结点的 Data Flow Fact* 控制流图中一个结点的 IN 和 OUT 分别对应一个 Data Flow Fact ,记录当前程序点时变量的状态** @return 初始化好的节点*/@Overridepublic SetFact<Var> newInitialFact() {// TODO - finish me// 节点初始化为空return new SetFact<>();}/*** 负责处理 transfer function 之前可能遇到多个 IN 时的合并处理*/@Overridepublic void meetInto(SetFact<Var> fact, SetFact<Var> target) {// TODO - finish metarget.union(fact);}/*** 负责实现控制流图中结点的 transfer function:* IN[B] = 本块中 use 出现在 define 之前的变量 U(OUT[B] 的 live 情况 - 本块中 define 的变量)。* 由于本次作业的每个基本块仅含有一条指令,所以可以不用考虑变量的 use 是否出现在 define 之前** @return 如果 IN 改变,返回 true;否则返回 false*/@Overridepublic boolean transferNode(Stmt stmt, SetFact<Var> in, SetFact<Var> out) {// TODO - finish meOptional<LValue> def = stmt.getDef();List<RValue> uses = stmt.getUses();SetFact<Var> newSetFact = new SetFact<>();newSetFact.union(out);if(def.isPresent()) {if(def.get() instanceof Var) {newSetFact.remove((Var) def.get());}}for (RValue use : uses) {if (use instanceof Var) {newSetFact.add((Var) use);}}if (!in.equals(newSetFact)) {in.set(newSetFact);return true;}return false;}
}

3 实现迭代求解器

3.1 Tai-e 中你需要了解的类

为了在 Tai-e 中实现迭代求解器,你需要了解的类有:

  • pascal.taie.analysis.dataflow.fact.DataflowResult

    该类对象用于维护数据流分析的 CFG 中的 fact。你可以通过它的 API 获取、设置 CFG 节点的 IN factsOUT facts

  • pascal.taie.analysis.graph.cfg.CFG

    这个类用于表示程序中方法的控制流图(control-flow graphs)。它是可迭代的,也就是说你可以通过一个 for 循环遍历其中的所有节点:

CFG<Node> cfg = ...;
for (Node node : cfg) {...
}

你可以通过 CFG.getPredsOf(Node)CFG.getSuccsOf(Node) 这两个方法遍历 CFG 中节点的所有前驱和后继,比如你可以写:

for (Node succ : cfg.getSuccsOf(node)) {...
}
  • pascal.taie.analysis.dataflow.solver.Solver

    这是数据流分析求解器的基类,包含了求解器的抽象功能。本次作业要实现的迭代求解器就是它的一个派生类(下次作业中的 worklist 求解器也是)。Tai-e 会构建待分析程序的 CFG 并传给 Solver.solve(CFG),然后世界就开始运转了。你可能注意到了,这个类中有两组 initializedoSolve 方法,分别用于处理前向和后向的数据流分析。虽然稍显冗余,但在这样的设计下代码结构会更干净、直接一些。这个类也是需要你补全实现的,这在第 3.2 节中进一步解释。

  • pascal.taie.analysis.dataflow.solver.IterativeSolver

    这个类扩展了 Solver 的功能并实现了迭代求解算法。当然,它也有待你补全。

3.2 你的任务

你的第二个任务是实现上面提到的 Solver 类的两个方法:

  • Solver.initializeBackward(CFG,DataflowResult)
  • IterativeSolver.doSolveBackward(CFG,DataflowResult)

因为活跃变量分析是一个后向分析,所以你只需要关注后向分析相关的方法就足够了。在 initializeBackward() 中,你需要实现第 2.2 节中算法的前三行;在 doSolveBackward() 则要完成对应的 while 循环。

提示

每个 Solver 对象都在字段 analysis 中保存了相应的数据流分析对象,在本次作业中就是一个 LiveVariableAnalysis 对象。你需要用它提供的相关接口来实现分析求解器。

/*** 实现算法前三行的初始化操作* 调用函数 newBoundaryFact 和 newInitialFact (DataflowAnalysis 中)*/protected void initializeBackward(CFG<Node> cfg, DataflowResult<Node, Fact> result) {// TODO - finish me// Init Exit noderesult.setInFact(cfg.getExit(), analysis.newBoundaryFact(cfg));// Init other nodesfor (Node node : cfg) {if (!cfg.isExit(node)) {result.setInFact(node, analysis.newInitialFact());result.setOutFact(node, analysis.newInitialFact());}}}
/*** 完成 while 循环*/@Overrideprotected void doSolveBackward(CFG<Node> cfg, DataflowResult<Node, Fact> result) {// TODO - finish meboolean flag = true;while (flag) {flag = false;for (Node node : cfg) {if (cfg.isExit(node)) continue;  // 出口节点不需要特殊处理// 获取当前节点的 OUT 和 INFact outFact = result.getOutFact(node);Fact inFact = result.getInFact(node);// 对于每个节点,调用函数 meetInto 和 transferNode (DataflowAnalysis 中)for (Node succs : cfg.getSuccsOf(node)) {Fact succsInFact = result.getInFact(succs);  // 获取 succs 节点的 IN 的 Fact 值analysis.meetInto(succsInFact, outFact);}if (analysis.transferNode(node, inFact, outFact)) {flag = true;}}}}

4 运行与测试

你可以按我们在 Tai-e 框架(教学版)配置指南 中提到的方式来运行你的分析。

在本作业中,Tai-e 对输入类的每个方法进行活跃变量分析,并输出分析的结果,也就是每个语句的 OUT fact 所包含的数据流信息(活跃变量):

--------------------<Assign: int assign(int,int,int)> (livevar)--------------------
[0@L4] d = a + b; null
[1@L5] b = d; null
[2@L6] c = a; null
[3@L7] return b; null

输出结果的每一行以该语句的位置信息开始,例如 [0@L4] 表示该语句在 IR 中的索引为 0,且在源码中处于第 4 行。输出结果的每一行末尾为该语句的 OUT fact,(当你未完成作业时结果为 null)。当你完成了所有的空缺代码后,分析的输出应当形如:

--------------------<Assign: int assign(int,int,int)> (livevar)--------------------
[0@L4] d = a + b; [a, d]
[1@L5] b = d; [a, b]
[2@L6] c = a; [b]
[3@L7] return b; []

注意:此处 return b; 这条语句也用到了 b 变量。

此外,Tai-e 将被分析方法的控制流图输出到 output/ 文件夹,它们被存储为 .dot 文件,你可以用可视化工具 Graphviz来查看这些控制流图。

我们为本次作业提供了测试驱动类 pascal.taie.analysis.dataflow.analysis.LiveVarTest,你可以按照 Tai-e 框架(教学版)配置指南 中描述的方式来测试你的实现是否正确。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/625534.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

视频AI野生动物保护智能监管方案,撑起智能保护伞,守护野生动物

一、背景 在当今世界&#xff0c;野生动物保护已经成为全球性的重要议题。然而&#xff0c;由于野生动物生存环境的不断恶化以及非法狩猎等活动的盛行&#xff0c;保护野生动物变得尤为迫切。为了更有效地保护野生动物&#xff0c;利用视频智能监管技术成为一种可行的方案。 …

Java Spring 框架下利用 MyBatis 实现请求 MySQL 数据库的存储过程

Java Spring 框架下利用 MyBatis 实现请求 MySQL 数据库的存储过程 环境准备与前置知识1. 创建 MySQL 存储过程2. 配置数据源3. 创建实体类4. 创建 Mapper 接口5. 创建 Mapper XML 文件6. 创建 Service 接口及Impl实现类7. 创建 Controller 类8. 测试与总结 在现代的 Web 应用开…

揭秘!网络安全“4法2例”国家安全体系背后基石

今年的四月十五日&#xff0c;承载着特殊的意义&#xff0c;它标志着我国迎来了第九个全民国家安全教育日。今年的主题活动聚焦于“总体国家安全观 创新引领10周年”&#xff0c;唤醒了我们对新时代国家安全多元维度的深刻认知。 网络安全&#xff0c;作为国家总体安全架构中的…

2024五一杯数学建模A题思路分析

文章目录 1 赛题思路2 比赛日期和时间3 组织机构4 建模常见问题类型4.1 分类问题4.2 优化问题4.3 预测问题4.4 评价问题 5 建模资料 1 赛题思路 (赛题出来以后第一时间在CSDN分享) https://blog.csdn.net/dc_sinor?typeblog 2 比赛日期和时间 报名截止时间&#xff1a;2024…

攻防世界---misc---hit-the-core

1.下载附件&#xff0c;用记事本打开&#xff0c;在记事本中发现一串可疑的字符串&#xff0c;很像flag 2.注意观察会发现&#xff0c;它的大写字母出现的很有规律&#xff1a;除第一个字母外&#xff0c;其余的都是每隔4个字母出现大写字母 3.接着用C语言写脚本 #include <…

LINUX网卡一般性问题分析

一、网卡相关概念 网卡&#xff1a;网卡是一块被设计用来允许计算机在计算机网络上进行通讯的计算机硬件。 网络模型&#xff1a;OSI网络模型、TCP/IP网络模型 LINUX网络收发流程&#xff1a; 1. 内核分配一个主内存地址段&#xff08;DMA缓冲区)&#xff0c;网卡设备可以在…

Linux中进程和计划任务

一.程序 1.什么是程序 &#xff08;1&#xff09;是一组计算机能识别和执行的指令&#xff0c;运行于电子计算机上&#xff0c;满足人们某种需求的信息化工具 &#xff08;2&#xff09;用于描述进程要完成的功能&#xff0c;是控制进程执行的指令集 二.进程 1.什么是进程…

docker网路和主机通讯问题

#注 1&#xff0c;安装docker和启动容器服务的时候如果防火墙处于开启状态&#xff0c;那么重启docker里面的容器的时候必须开启防火墙&#xff0c;否则会出现iptable错误&#xff1b; 2&#xff0c;linux开启防火墙会导致主机和docker网络之间单向通讯&#xff0c;主机可以访…

2024蓝桥杯每日一题(最大公约数)

备战2024年蓝桥杯 -- 每日一题 Python大学A组 试题一&#xff1a;公约数 试题二&#xff1a;最大公约数 试题三&#xff1a;等差数列 试题四&#xff1a;最大比例 试题五&#xff1a;Hankson的趣味题 试题一&#xff1a;公约数 【题目描述】 …

呵护童心:儿童情感测试的关怀指南

引言&#xff1a; 儿童的情感健康对于其成长和发展至关重要。情感测试作为了解和评估儿童情感状态的重要工具&#xff0c;需要在专业人士的指导下进行&#xff0c;并且需要家长的配合和关注。本文将探讨儿童情感测试的注意事项&#xff0c;以期为儿童的情感健康提供更全面的保障…

记【k8s】:访问 Prometheus UI界面:kubernetes-etcd (0/1 up) Error : out of bounds

记【k8s】&#xff1a;访问 Prometheus UI界面&#xff1a;kubernetes-etcd &#xff08;0/1 up&#xff09; Error &#xff1a; out of bounds 1、报错详情2、解决方法 &#x1f496;The Begin&#x1f496;点点关注&#xff0c;收藏不迷路&#x1f496; 出现 “out of bound…

街景图片语义分割后像素类别提取,用于计算各种指标。

语义分割代码见之前博文&#xff08;免费&#xff09;&#xff1a;deeplabv3街景图片语义分割&#xff0c;无需训练模型&#xff0c;看不懂也没有影响&#xff0c;直接使用。cityscapes 语义分割之后&#xff0c;如下图&#xff0c;想要统计各类像素所占的比例&#xff0c;用于…