高级软件工程第十一讲高效的静态分析.ppt
合集下载
相关主题
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
– 路径条件(PC: Path Condition)
– 程序标记(后面执行什么)
路径条件非常重要
– 积累了路径的约束条件
符号执行树
– 刻画程序符号执行过程中的执行路径
例子:
最初,x 与 y 分别具有符号值X、 Y 在每个分支点,PC 根据输入的假定确定不同的值 如果PC不成立,该路径不可达 可以大大减少路径组合
int x, y; 1: if (x > y) {
x: X, y: Y (x>y?) x: X, y: Y (X>Y) x: X+Y, y: Y (X>Y) x: X+Y, y: X (X>Y) x: X, y: Y (X<Y)
2: x = x + y;
3: y = x - y; 4: x = x - y; 5: if (x > y) foo1(); 6: else } foo2();
x: Y, y: X (X>Y)
x: Y, y: X (X>Y)& (Y>X) x: Y, y: X (X>Y)& (Y<=X)
符号执行可以被看作是路径敏感分析、演 绎方法及抽象解释的组合 对路径条件进行近似使得抽象解释的属性区 间值收缩,因此更加灵活 约束近似了许多状态,降低了分析量 经常被应用于测试输入的生成 传统上,符号执行对有限个整数变量进行符 号化,后来扩展到了处理复杂的输入数据结 构和并发
对所有可能的状态进行穷举搜索,开销大 对系统的行为进行近似,可能导致这类结果不精确 对于数据密集的系统分析困难 在边界处对路径、时序属性近似困难,故复合困难
缺点
– – – –
抽象解释
优点
– – – –
由于对路径、状态进行抽象,扩展性好 可以对许多有价值的属性构造格 易于组合 提供了坚实的数学基础
12
result[0] = 0;
当 size <= 0 时,函数试图解析一 个未被初始化的指针 (malloc in line 9 will not be executed).
缺点
– 适合的属性需要是简单的、“状态”“值”
型的 – 对时序性质支持弱 – 属性格的定义不容易 – 有时近似过强
演绎方法(定理证明)
优点
– 支持灵活的属性 – 易于扩展
缺点
– 开发人员需要提供额外的信息
– 自动化程度不高 – 路径不敏感,对并发系统不适合
符号执行
记录执行的状态,包括:
– 程序变量的符号值
高级软件工程
第十一讲 高效的静态分析
---符号执行 与 缺陷模式
内 容
一、符号执行 1、符号执行简介 2、代表工具:PREfix 二、缺陷模式 1、缺陷模式简介 2、安全漏洞
一、符号执行
1、符号执行简介 2、代表工具:PREfix
观察下面程序:
int x, y; 1: if (x > y) { 2: x = x + y; 3: y = x - y; 4: x = x - y; 5: if (x > y) foo1(); 6: else foo2(); }
观察右边代码 有什么问题?
1 #include <stdlib.h> 2 #include <stdio.h> 3 4 char *f(int size) 5 { 6 char *result; 7 8 if (size > 0) 9 result = (char *)malloc(size); 10 if (size = = 1)
1 #include <stdlib.h> 2 #include <stdio.h> 3 4 char *f(int size) 5 { 6 char *result; 7 8 if (size > 0) 9 result = (char *)malloc(size); 10 if (size = = 1) 11 return NULL;
12
result[0] = 0;
13 return result; 14 }
当size >0, 但malloc失败,result 返回 NULL 指针时,对其赋值出现错误
算法伪代码:
while (there are more paths to simulate) { initialize memory state simulate the path, identifying inconsistencies and updating the memory state perform end-of-path analysis using the final memory state, identifying inconsistencies and creating per-path summary } combine per-path summaries into a model for the function
3)主要步骤
路径
– – – –
– 但不一定是唯一的路径 可能是多条路径累积的结果
1 #include <stdlib.h> 2 #include <stdio.h> 3 4 char *f(int size) 5 { 路径跟踪很容易发现一些问题 6 char *result; 7 路径中包括“功能调用、语句、结果” 8 if (size > 0) 模拟执行是基于路径进行的 9 result = (char *)malloc(size); 为定位缺陷提供依据 10 if (size = = 1) 11 return NULL;
– 例如,扩展 JPF 工具以进行符号执行Java 程序
2、典型工具:PREfix
1)基本特点 2)主要思路 3)主要步骤
1)基本特点
模拟执行单个的函数!
模拟过程顺序地跟踪不同的执行路径,模拟每个操 作符的动作。在路径执行过程中,通过跟踪内存的 状态,应用各种一致性规则,查找不一致性。 在对条件选择后,通过检查内存的当前状态,分析 器可以限制可达的路径。由于对路径、值的跟踪都 很仔细,可以获得精确的信息。 函数的行为被描述为:条件、一致性规则及表达式 值的集合。行为的这种描述被称为函数的一个模型。 在路径执行过程中,不论何时进入一个函数,该模 型被使用,以决定应用哪个操作
有什么问题?
1、符号执行简介
J. C. King 于 1976 年提出Symbolic Execution 使用符号值,而不是实际数据,作为输入 将程序变量的值表示为符号表达式 程序计算的输出表达为输入符号值的函数
模型检验
优点
– – – –
分析是路径敏感的 因为没有对路径、状态做近似,结果精确 适合做状态检查、时序检查 对并发类型的错误十分有效
Path includes 4 statements on the following lines: 8 9 10 11
11
return NULL;
12 result[0] = 0; 13 return result; 14 }
example1.c(9) : used system model ‘malloc’ for function call: ‘malloc(size)’ function returns a new memory block memory allocated
模拟单个函数需要模拟可达的路径。可达路径的集合包含 所有可能的控制流路径集合 。这个集合的大小往往小于明 显的控制流路径。因为相同的条件往往控制多个条件模块。 通常可以选择有代表性的路径来模拟。具体路径数可以由 用户进行配置 模拟一条路径涉及遍历函数的抽象语法树,对树上相关的 语句、表达式求值。被模拟函数的内存状态随着语句的执 行被不断更新。许多缺陷 (例如, 未初始化的内存,NULL, 或者无效的指针解析) 可以通过在路径模拟过程中对内存 的状态应用一致性规则发现。其他 (例如,内存泄漏,将 指针返回给一个释放的内存) 在到达路径终点时可以被发 现 当路径被模拟时,函数的最终内存状态被综合处理 (summarized)。当所有的路径被模拟后, per-path summaries 被组成一个函数的模型
Hale Waihona Puke Baidu
在模拟过程中产生的信息足够自动地产生该函数的 一个模型 为在整个程序中应用这些技术,分析起始于调用图 的叶节点,自底向上地向根处理。随着函数被逐层 模拟,缺陷被不断发现,函数模型被高层的后续模 拟所使用 这种自底向上的方法使用一个函数的实现来产生函 数的约束,供上层使用。这对于程序不完整时(程 序还没有开发完,或者被分析的代码需要适合多个 不同的程序)尤其有效
2)主要思路
1 #include <stdlib.h> 2 #include <stdio.h> 3 4 char *f(int size) 5 { 6 char *result; 7 8 if (size > 0) 9 result = (char *)malloc(size); 10 if (size = = 1) 11 return NULL; 12 result[0] = 0; 13 return result; 14 }
错误消息1: example1.c(11) : warning 14 : leaking memory
problem occurs in function ‘f’ The call stack when memory is allocated is: example1.c(9) : f Problem occurs when the following conditions are true: example1.c(8) : when ‘size > 0’ here example1.c(10) : when ‘size == 1’ here
当 size <= 0 时,函数试图解析一 个未被初始化的指针 (malloc in line 9 will not be executed).
12
result[0] = 0; 错误消息2:
13 return result; 14 }
example1.c(12) : warning 10 : dereferencing uninitialized pointer ‘result’ problem occurs in function ‘f’ example1.c(6) : variable declared here Problem occurs when the following conditions are true: example1.c(8) : when ‘size <= 0’ here
错误消息3:
example1.c(12) : warning 11 : dereferencing NULL pointer ‘result’ problem occurs in function ‘f’ example1.c(9) : value comes from return value of ‘malloc’ here Problem occurs when the following conditions are true: example1.c(8) : when ‘size > 0’ here example1.c(10) : when ‘size != 1’ here problem occurs when ‘memory exhausted’ Path includes 4 statements on the following lines: 8 9 10 12 example1.c(9) : used system model ‘malloc’ for function call: ‘malloc(size)’ function returns 0 memory exhausted
当 size = 1 时,直接返回 NULL, 被分配的内存未被释放,也未被返回。
1 #include <stdlib.h> 2 #include <stdio.h> 3 4 char *f(int size) 5 { 6 char *result; 7 8 if (size > 0) 9 result = (char *)malloc(size); 10 if (size = = 1) 11 return NULL;