1 / 40

提高程序验证能力的研究

提高程序验证能力的研究. 中科大-耶鲁高可信软件联合研究中心 报告人 陈意云 0551-3607043 yiyun@ustc.edu.cn http://staff.ustc.edu.cn/~yiyun. 报 告 提 纲. 一类基于逻辑推理的程序验证器的工作原理 通过一个简单例子了解概念 和工作流程 函数前后条件、循环不变式、 Hoare 逻辑的赋值公理,最弱前条件演算、 验证条件、 验证条件的生成、 验证条件的证明 面向实际程序验证需要解决的问题 提高程序验证能力的思路 一个程序验证系统原型. 一类程序验证器的工作原理.

anakin
Download Presentation

提高程序验证能力的研究

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. 提高程序验证能力的研究 中科大-耶鲁高可信软件联合研究中心 报告人 陈意云 0551-3607043 yiyun@ustc.edu.cn http://staff.ustc.edu.cn/~yiyun

  2. 报 告 提 纲 • 一类基于逻辑推理的程序验证器的工作原理 • 通过一个简单例子了解概念和工作流程 函数前后条件、循环不变式、 Hoare逻辑的赋值公理,最弱前条件演算、验证条件、验证条件的生成、验证条件的证明 • 面向实际程序验证需要解决的问题 • 提高程序验证能力的思路 • 一个程序验证系统原型

  3. 一类程序验证器的工作原理 function mult(m, n) { x = 0 ; y = 0 ; while y < n do { x = x + m ; y = y + 1 ; } } 例子:用加运算来实现乘运算的函数

  4. 一类程序验证器的工作原理 n  0 - - 前条件 function mult(m, n) { x = 0 ; y = 0 ; while y < n do { x = x + m ; y = y + 1 ; } } x = m  n - - 后条件 由程序员提供 由程序员提供

  5. 一类程序验证器的工作原理 n  0 function mult(m, n) { x = 0 ; y = 0 ; while y < n do { (x = my)  (y  n)- - 循环不变式 x = x + m ; y = y + 1 ; } } x = m  n 也由程序员提供

  6. 一类程序验证器的工作原理 n  0 function mult(m, n) { x = 0 ; y = 0 ; while y < n do { (x = my)  (y  n)- - 循环不变式 x = x + m ; y = y + 1 ; } } x = m  n 函数前后条件、循环不变式 都是关于程序变量的断言 本例中的断言就是编程语言 的布尔表达式

  7. 一类程序验证器的工作原理 n  0 function mult(m, n) { ( n  0 )  ((0 = m0)  (0  n)) x = 0 ; y = 0 ; ((x = my)  (y  n))  (y < n)  (x+m = m(y+1))  ((y+1)  n) while y < n do { (x = my)  (y  n) x = x + m ; y = y + 1 ; } ((x = my)  (y  n))  (y < n)  (x = mn) } x = m  n 经过最弱前条件演算,得到3个验证条件

  8. 一类程序验证器的工作原理 n  0 function mult(m, n) { ( n  0 )  ((0 = m0)  (0  n)) x = 0 ; y = 0 ; ((x = my)  (y  n))  (y < n)  (x+m = m(y+1))  ((y+1)  n) while y < n do { (x = my)  (y  n) x = x + m ; y = y + 1 ; } ((x = my)  (y  n))  (y < n)  (x = mn) } x = m  n 这3个验证条件由自动定理证明器来证明

  9. 报 告 提 纲 一类基于逻辑推理的程序验证器的工作原理 面向实际程序验证需要解决的问题 提高断言语言的表达能力 解决各种数据类型带来的特殊问题 解决非结构化控制结构带来的问题 … … 提高自动定理证明器的能力 提高程序验证能力的思路 一个程序验证系统原型

  10. 提高断言语言的表达能力 例1:表达单链表的有序性 在断言语言中引入归纳谓词 SortedList(p) p == NULL  p != NULL  p->next == NULL  p->data <= p->next->data  SortedList(p->next) 该问题用量词也能表示 n:Z.i:[0, n-2]. p(->next)i ->data <= p(->next)i+1->data 带来问题: 引入谓词或量词都增加了验证条件自动证明的难度

  11. 提高断言语言的表达能力 例2:表达二叉排序树的有序性 在断言语言中引入归纳谓词(需要多个归纳谓词) Gt(x, p) p == NULL  x > p->data  Gt(x, p->l)  Gt(x, p->r) Lt(x, p) p == NULL  x < p->data  Lt(x, p->l)  Lt(x, p->r) Bst(p) p == NULL  Bst(p->l)  Gt(p->data, p->l)  Bst(p->r)  Lt(p->data, p->r) 带来问题: 若程序利用了归纳定义的数据结构的归纳性质, 基于演绎推理的自动定理证明器难以发现这些性质 稍后举例说明

  12. 提高断言语言的表达能力 例3:二叉排序树的插入函数的前后条件 在断言语言中引入逻辑变量 { Bst(p) } Node* insert(Node* p, int data) { if (p == NULL) { … } else if (p->data > data) { p->l = insert(p->l, data); } else if(p->data < data) { … } return p; } { Bst(p) } 前后条件仅是 Bst(p)是不够的

  13. 提高断言语言的表达能力 例3:二叉排序树的插入函数的前后条件 在断言语言中引入逻辑变量 { Bst(p) } Node* insert(Node* p, int data) { if (p == NULL) { … } else if (p->data > data) { p->l = insert(p->l, data); } else if(p->data < data) { … } return p; } { Bst(p) } 前后条件仅是 Bst(p)是不够的 递归调用之后仅得到Bst(p->l), 不足以证明函数后条件

  14. 提高断言语言的表达能力 例3:二叉排序树的插入函数的前后条件 在断言语言中引入逻辑变量 { Bst(p) } Node* insert(Node* p, int data) { if (p == NULL) { … } else if (p->data > data) { 调用前断言:Bst(p->r) Lt(p->data, p->r)  Bst(p->l) Gt(p->data, p->l)p->data > data p->l = insert(p->l, data); … … } { Bst(p) } 前后条件仅是 Bst(p)是不够的

  15. 提高断言语言的表达能力 例3:二叉排序树的插入函数的前后条件 在断言语言中引入逻辑变量 { Bst(p) } Node* insert(Node* p, int data) { if (p == NULL) { … } else if (p->data > data) { p->l = insert(p->l, data); 调用后断言:Bst(p->r)  Lt(p->data, p->r)  Bst(p->l) Gt(p->data, p->l)p->data > data … … } { Bst(p) } 前后条件仅是 Bst(p)是不够的 调用前有关p->l的性质都被删除, Bst(p->l)是根据该函数的后条件加上的

  16. 提高断言语言的表达能力 例3:二叉排序树的插入函数的前后条件 在断言语言中引入逻辑变量 { Bst(p)  y > data  Gt(y, p)  z < data  Lt(z, p) } Node* insert(Node* p, int data) { if (p == NULL) { … } else if (p->data > data) { 调用前断言: …  p->data >data  Gt(p->data, p->l)  … p->l = insert(p->l, data); … … } { Bst(p)  Gt(y, p)  Lt(z, p) } 逻辑变量: 只能用于断言中 的变量,如y和z

  17. 提高断言语言的表达能力 例3:二叉排序树的插入函数的前后条件 在断言语言中引入逻辑变量 { Bst(p)  y > data  Gt(y, p)  z < data  Lt(z, p) } Node* insert(Node* p, int data) { if (p == NULL) { … } else if (p->data > data) { 调用前断言: …  p->data >data  Gt(p->data, p->l)  … p->l = insert(p->l, data); … … } { Bst(p)  Gt(y, p)  Lt(z, p) } 将y代换为p->data

  18. 提高断言语言的表达能力 例3:二叉排序树的插入函数的前后条件 在断言语言中引入逻辑变量 { Bst(p)  y > data  Gt(y, p)  z < data  Lt(z, p) } Node* insert(Node* p, int data) { if (p == NULL) { … } else if (p->data > data) { p->l = insert(p->l, data); 调用后断言:…  Bst(p->l)  Gt(p->data, p->l)… … … } { Bst(p)  Gt(y, p)  Lt(z, p) } 带来问题: 自动定理证明器 难以完成逻辑变量 的匹配

  19. 提高断言语言的表达能力 例4:断言语言需要更加复杂扩展的例子 程序不会出现内存泄漏 程序不会对dangling指针进行dereference操作 (我们把它们作为验证系统一定保证的性质) 在任何时候,最多只有一个进程处于临界区(安全性) 只要进程请求进入临界区,则最终会被允许进入(活性) 断言语言越复杂,生成的验证条件就复杂,验证条件的自动证明就越困难

  20. 报 告 提 纲 一类基于逻辑推理的程序验证器的工作原理 面向实际程序验证需要解决的问题 提高程序验证能力的思路 程序员提供对验证有帮助的提示 提高合法程序的门槛 用程序分析获得的信息来支持程序验证 … … 一个程序验证系统原型

  21. 程序员提供对验证有帮助的提示 方式1:程序员声明数据结构的形状 typedef struct node{Node* : LIST next; int data;} Node; typedef struct node{Node*:TREE left; Node* :TREE right; int data;}Node; 给程序员带来好处 免除提供有关数据结构形状的函数前后条件 免除提供有关形状的循环不变式 帮助检查引起内存泄漏的操作 帮助检查对NULL指针和dangling指针的dereference操作

  22. 程序员提供对验证有帮助的提示 方式2:提供数据结构的性质定理 删除二叉排序树根节点的函数 通过循环,找到左子树的最右叶节点,取它的数据作为根节点数据,删除该最右叶节点 函数的前条件是 p!=NULL  Bst(p) 函数的后条件式是 Bst(p) 从Bst(p)等谓词定义, 基于演绎推理, 推不出性质:绿色节点是左子树上最大 但又小于根的节点 p … … … … … …

  23. 程序员提供对验证有帮助的提示 方式2:提供数据结构的性质定理 Gt(x, p) p == NULL  x > p->data  Gt(x, p->l)  Gt(x, p->r) Lt(x, p) p == NULL  x < p->data  Lt(x, p->l)  Lt(x, p->r) Bst(p) p == NULL  Bst(p->l)  Gt(p->data, p->l)  Bst(p->r)  Lt(p->data, p->r) 这是一个基于Bst定义的归纳性质 解决办法:程序员在给出Bst等谓词 定义时,还需给出程序用到的归纳性质 好处:减轻了自动定理证明器的负担 p … … … … … …

  24. 程序员提供对验证有帮助的提示 方式2:提供数据结构的性质定理 Gt(x, p) p == NULL  x > p->data  Gt(x, p->l)  Gt(x, p->r) Lt(x, p) p == NULL  x < p->data  Lt(x, p->l)  Lt(x, p->r) Bst(p) p == NULL  Bst(p->l)  Gt(p->data, p->l)  Bst(p->r)  Lt(p->data, p->r) 简单的性质定理 x < y  Lt(y, p)  Lt(x, p) x > y  Gt(y, p)  Gt(x, p) p … … … … … …

  25. 提高合法程序的门槛 方法1:给编程语言设计一个形状系统 排除不符合形状系统规定的程序,类似于类型检查 单链表指针h作为函数的实参 nxt nxt h . . .  m个节点, m>=0 nxt 允许作为实参 指向它的是NULL指针

  26. 提高合法程序的门槛 方法1:给编程语言设计一个形状系统 排除不符合形状系统规定的程序,类似于类型检查 单链表指针h作为函数的实参 nxt nxt nxt nxt h h . . . . . . D  m个节点, m>=0 m个节点, m>=0 nxt nxt 允许作为实参 不允许作为实参 指向它的是dangling指针

  27. 提高合法程序的门槛 方法1:给编程语言设计一个形状系统 排除不符合形状系统规定的程序,类似于类型检查 单链表指针h作为函数的实参 nxt nxt nxt nxt h h . . . . . .  D m个节点, m>=0 m个节点, m>=0 nxt nxt nxt nxt nxt p nxt nxt nxt nxt h . . . . . .  m个节点, m > 0 n个节点, n >0 允许作为实参 不允许作为实参 h不允许作为实参 p允许作为实参

  28. 提高合法程序的门槛 方法1:给编程语言设计一个形状系统 排除不符合形状系统规定的程序,类似于类型检查 r r r r r . . .  l l l l l  r r r r r . . . h h  l l l l     一个双向链表 循环迭代依次把域l都赋值为NULL,然后当单链表用 形状系统拒绝这个程序,因为它偏离了声明的形状

  29. 提高合法程序的门槛 方法1:给编程语言设计一个形状系统 好处: 有助于自动推断有关形状的循环不变式 减轻自动定理证明器的负担 其他方法,例如 对有些类型的运算加以限制:有控制地使用指针算术运算和类型强制等 减少非结构化的控制流

  30. 用程序分析来支持程序验证 方法:先程序分析,后程序验证 用特定程序分析获取的信息来支持随后的程序验证 例如 { p->data == 10 } p1->nxt->data = p->data + 5 { ? } 取决于p1->nxt是否等于p。若不知道,则需要考 虑两种情况,因而后条件是: p1->nxt != p  (p->data == 10  p1->nxt->data == 15)  p1->nxt == p  p->data == 15 若先指针分析,得到指针相等信息,则大大简化

  31. 用程序分析来支持程序验证 方法:先程序分析,后程序验证 用特定程序分析获取的信息来支持随后的程序验证 例如 { p->data == 10 } p1->nxt->data = p->data + 5 { ? } p1 p nxt nxt nxt nxt nxt nxt nxt h . . . . . .  m个节点, m>=0 n个节点, n>=0

  32. 用程序分析来支持程序验证 方法:先程序分析,后程序验证 用特定程序分析获取的信息来支持随后的程序验证 例如 { p->data == 10 } p->data = p->data + 5 { ? } p1 p nxt nxt nxt nxt nxt nxt nxt h . . . . . .  m个节点, m>=0 n个节点, n>=0

  33. 用程序分析来支持程序验证 方法:先程序分析,后程序验证 用特定程序分析获取的信息来支持随后的程序验证 例如 { p->data == 10 } p->data = p->data + 5 {p->data == 15 } p1 p nxt nxt nxt nxt nxt nxt nxt h . . . . . .  m个节点, m>=0 n个节点, n>=0

  34. 报 告 提 纲 一类基于逻辑推理的程序验证器的工作原理 面向实际程序验证需要解决的问题 提高程序验证能力的思路 程序员提供对验证有帮助的提示 提高合法程序的门槛 用程序分析获得的信息来支持程序验证 … … 一个程序验证系统原型

  35. 报 告 提 纲 一类基于逻辑推理的程序验证器的工作原理 面向实际程序验证需要解决的问题 提高程序验证能力的思路 一个程序验证系统原型 技术特点 系统流程 验证实例

  36. 一个程序验证系统原型 技术特点 为操作易变数据结构的程序设计了形状图逻辑 为操作易变数据结构的程序设计了形状系统 自动推断循环不变形状图 自动推断递归函数的前后形状图 用形状分析所获得信息来支持程序其它性质的验证 设计并正在实现断言中逻辑变量的匹配方法 设计了程序员提供的性质定理的检查方法

  37. 一个程序验证系统原型 程序员提交的被验证程序包括 源程序 各函数前后条件(指针断言部分除外) 各循环的循环不变式(指针断言部分除外) 谓词定义 谓词之间的性质定理 逻辑变量声明

  38. 一个程序验证系统原型 系统流程 预处理阶段 为源代码生成抽象语法树并完成通常的静态检查 形状分析阶段 遍历语法树,生成各程序点的形状图,进行形状推断和形状检查,推断循环不变形状图,推断递归函数前后形状图 程序验证阶段 生成验证条件,证明验证条件(使用微软的SMT求解器Z3)

  39. 一个程序验证系统原型 验证实例 一维数组 快速排序程序、冒泡排序 易变数据结构 下面这些数据类型的插入函数和删除函数等 1、有序单链表、有序循环单链表 2、有序双向变量、有序循环双向链表 3、二叉排序树、平衡树(AVL tree) 4、正在调试中的有: AA 树、树堆(treap)、伸展树(splay tree) (演示:可联系孟建超同学)

  40. 谢 谢 !

More Related