高完整性系统:Separation Logic for Automated Verification

news2024/10/7 16:19:08

目录

1. INTRODUCTION TO SEPARATION LOGIC 分离逻辑

1.1 霍尔推理(Hoare Reasoning)

1.2 堆指针的影响

1.3 全局和局部推理(Global and Local Reasoning)

1.4 组合推理(Compositional Reasoning)

1.5 The Frame Rule

1.6 The Side Condition 

1.7 Validity of Triples 三元组的有效性

1.8 Memory Safety 内存安全性

2. A LITTLE MORE FORMALLY

2.1 Expressions, Commands

2.2 Heap Read Rule (Simplified)

2.3 Assignment Rules

2.4 Frame Rule

2.5 Example Proof 

​编辑

2.6 Inductive Predicates 

2.7 Example: Tail


1. INTRODUCTION TO SEPARATION LOGIC 分离逻辑

1.1 霍尔推理(Hoare Reasoning)

霍尔推理是一种用于推理程序正确性的形式化方法,其主要组成部分是霍尔三元组(Hoare Triple):{P} prog {Q},表示在前置条件P成立的情况下,执行程序prog,之后后置条件Q会成立。对于局部变量x和y,这种推理方式在x和y不相互引用(即不能为别名)的情况下才有效。

  • 赋值规则(ASSIGN):{Q[e/x]} x := e {Q},这个规则表示,如果在赋值后的状态Q中将x替换为表达式e可以得到前置状态,那么这个霍尔三元组是有效的。

  • 顺序规则(CONSEQ):(P → P’ {P’} prog {Q’} Q’ → Q) / ({P} prog {Q}),这个规则表示,如果从前置条件P可以推导出另一个前置条件P’,并且从后置条件Q’可以推导出另一个后置条件Q,那么原本的霍尔三元组的效果可以通过新的三元组来实现。

这两个规则在处理基本赋值语句和逻辑推导时十分有用。但是,它们在处理指针和别名等更复杂的数据结构时会变得不够用。

1.2 堆指针的影响

在处理像 *x := 2 这样的语句时,我们需要引入一种新的断言,称为映射断言(Maps-To Assertion):p ↦ e,表示通过p识别的堆位置保存了值e。但这并不能完全解决问题,因为当x和y指向同一个位置,也就是别名的情况时,这个霍尔三元组就会失效。因此,我们需要一种能够处理别名情况的方法。

1.3 全局和局部推理(Global and Local Reasoning)

在霍尔逻辑中,谓词P和Q都是对全局状态进行描述的。这在处理全局变量或者独立的局部变量时没有问题,但是在处理像堆这样的共享结构时就会变得复杂。

为了解决这个问题,分离逻辑引入了一种新的想法:谓词P只描述它关心的状态部分,这部分被称为谓词的领域(也叫足迹),记作 dom(P)。对于映射断言 p ↦ e,它的领域就是{p}。

1.4 组合推理(Compositional Reasoning)

分离逻辑引入了一种新的连接符:分离连词 P ⋆ Q,表示P和Q各自描述了各自的状态部分,并且这两部分是分离的。这就为处理别名问题提供了一种手段。在 P ⋆ Q 中,如果 P 和 Q 有共同的领域,那么 P ⋆ Q 就无法成立。这可以用来表达 x 和 y 不可能是别名的情况。

1.5 The Frame Rule

分离逻辑的一个重要理论是帧规则(FRAME Rule):({P} prog {Q} modv(prog) ∩ fv(R) = {}) / ({P ⋆ R} prog {Q ⋆ R})。这个规则的意思是,如果一个程序没有修改R中的任何变量,那么就可以从{P} prog {Q}推导出{P ⋆ R} prog {Q ⋆ R}。也就是说,如果我们知道在P的情况下执行prog可以得到Q,那么在P和R同时成立的情况下执行prog,我们不仅可以得到Q,还可以得到R。

1.6 The Side Condition 

在上述帧规则中,有一个旁注条件:程序修改的变量集合和R中的自由变量集合不相交。如果这个条件不成立,那么我们就无法保证R在程序执行后仍然成立。

1.7 Validity of Triples 三元组的有效性

在分离逻辑中,霍尔三元组{P} prog {Q}的含义是部分正确性(Partial Correctness):如果P在程序开始时成立,那么只要程序正常终止,Q就会成立,而且,程序绝对不会出错。

1.8 Memory Safety 内存安全性

在一个所有内存不安全访问都会导致失败的语言语义中,分离逻辑可以保证内存安全。比如访问一个未初始化的指针这样的情况,在分离逻辑中是不被允许的。 

2. A LITTLE MORE FORMALLY

2.1 Expressions, Commands

表达式 (e) 是指可以由变量 (x) 或数字 (n) 组成的。它可以提及局部变量,但不能提及堆。表达式在一个存储 s 中求值,其中 s 是一个函数,将变量映射到整数上。

命令 (c) 是构造程序的基本元素。以下是一些基本的命令类型:

  • c1 ; c2:命令序列,首先执行c1,然后执行c2。
  • if e then ct else cf:条件语句,如果表达式 e 为真,则执行 ct,否则执行 cf。
  • while e do c:循环语句,只要表达式 e 为真,就执行命令 c。
  • x := e:将表达式 e 的值赋给变量 x。
  • x := *e:将地址 e 所在的值赋给变量 x。
  • *e1 := e2:将表达式 e2 的值写入到地址 e1 所在的位置。

注意:堆和存储的更新在语法上是不同的。

2.2 Heap Read Rule (Simplified)

 

堆读取规则描述了从堆中读取数据的过程。简化版的堆读取规则为:

  • 当变量x不在表达式e的地址集(ars(e))中时,我们可以读取存储位置e,得到值v,并将其赋值给x。也就是说,我们可以这样写:{e ↦ v} x := *e {x = v},表示将存储位置e的值v赋给变量x。

这个规则的应用例子:

  • 如果s(y) = 19,执行命令x := *(y+1),并且如果y+1 ↦ 3 holds,那么执行后s(x) = 3。也就是说,将y+1的存储位置中的值3赋给了x。

如果变量 x 在表达式 e 的地址集中,我们需要更一般的规则,但这已超出了本次课程的讨论范围。

2.3 Assignment Rules

  • HEAPW {e1 ↦ _} *e1 := e2 {e1 ↦ e2}:这是堆写入规则,表示将表达式 e2 的值写入到存储位置 e1 所在的位置。
  • ASSIGN {x ≐ n} x := e {x ≐ e[n/x]}:这是基本赋值规则,表示将表达式 e 的值赋给变量 x。这里的 e[n/x] 表示将表达式 e 中的 x 替换为 n。
  • ASSIGN’ (x /∉ vars(e)) / ({emp} x := e {x ≐ e}):这是特殊的赋值规则,只有当变量 x 不在表达式 e 中时,才可以使用。这表示将表达式 e 的值赋给变量 x。

2.4 Frame Rule

Frame 是一种用于跟踪命令 c 修改了哪些变量的工具。以下是一些基本的规则:

  • modv(x := e) = {x}:表示命令 x := e 修改了变量 x。
  • modv(x := *e) = {x}:表示命令 x := *e 修改了变量 x。
  • modv(*e1 := e2) = {}:表示命令 *e1 := e2 没有修改任何变量。
  • modv(while e do c) = modv(c):表示 while 循环修改了 c 修改的所有变量。
  • modv(if e then ct else cf) = modv(ct) ∪ modv(cf):表示 if 语句修改了 ct 和 cf 修改的所有变量。
  • modv(c1 ; c2) = modv(c1) ∪ modv(c2):表示命令序列 c1 ; c2 修改了 c1 和 c2 修改的所有变量。

Frame 规则 ({P} prog {Q} modv(prog) ∩ fv(R) = {}) / ({P ⋆ R} prog {Q ⋆ R}):表示如果 prog 修改的变量与 R 的自由变量 fv(R) 没有交集,则可以在 P 和 Q 上加一个 R 来得到新的断言。

2.5 Example Proof 

这个程序的目的是交换两个指针x和y所指向的值。首先,我们初始化t和u为x和y的值,然后将u和t的值分别赋给x和y。根据Hoare逻辑,我们可以为这个过程创建三元组,并对每个步骤应用Hoare序列规则(Hoare sequencing rule)。Hoare序列规则是用于组合程序语句的一个规则,它允许我们将两个或多个程序语句串联在一起,并形成一个具有前提和后置条件的新的程序语句。

这个过程如下:

  1. {x ↦ vx ⋆ y ↦ vy} t := *x; {(x ↦ vx ∧ t = vx) ⋆ y ↦ vy}
  2. {(x ↦ vx ∧ t = vx) ⋆ y ↦ vy} u := *y; {(x ↦ vx ∧ t = vx) ⋆ (y ↦ vy ∧ u = vy)}
  3. {(x ↦ vx ∧ t = vx) ⋆ (y ↦ vy ∧ u = vy)} *x := u; {(x ↦ u ∧ t = vx) ⋆ (y ↦ vy ∧ u = vy)}
  4. {(x ↦ u ∧ t = vx) ⋆ (y ↦ vy ∧ u = vy)} *y := t; {x ↦ vy⋆ y ↦ vx}

在以上过程中,x ↦ vx表示指针x指向值vx,⋆表示堆中的分隔,即表示x和y指向的是堆中的不同位置。

2.6 Inductive Predicates 归纳谓词

归纳谓词是一种描述堆的工具,可以处理大小不定的堆。比如,e1 ↦ e2 和 emp 只能描述大小为 1 和 0 的堆,但我们如何描述更大的、或者说无界的堆数据结构呢?

例如,我们定义一个归纳谓词 list(e) 来表示一个链表。list(e) 的定义如下:(e = 0 ∧ emp) ∨ (∃e’. e ↦ e’ ⋆ list(e’))。也就是说,如果 e 是 0,那么表示一个空的链表;否则,e 指向一个元素 e’,并且 e’ 后面跟着一个链表。

2.7 Example: Tail

以下是一个使用了上述规则和概念的例子。这是一个简单的交换 x 和 y 的值的程序。

所以,我们成功地证明了这个程序可以交换 x 和 y 的值。

  1. 首先,我们假设 {x ↦ vx ⋆ y ↦ vy}。也就是说,变量 x 的值是 vx,变量 y 的值是 vy。

  2. 执行 t := *x。根据堆读取规则,我们可以将 x 的值 vx 赋给 t。所以,我们得到新的断言 {(x ↦ vx ∧ t = vx) ⋆ y ↦ vy}。

  3. 执行 u := *y。根据堆读取规则,我们可以将 y 的值 vy 赋给 u。所以,我们得到新的断言 {(x ↦ vx ∧ t = vx) ⋆ (y ↦ vy ∧ u = vy)}。

  4. 执行 *x := u。根据堆写入规则,我们可以将 u 的值 vy 写入 x 的位置。所以,我们得到新的断言 {(x ↦ u ∧ t = vx) ⋆ (y ↦ vy ∧ u = vy)}。

    • 执行 *y := t。根据堆写入规则,我们可以将 t 的值 vx 写入 y 的位置。所以,我们得到新的断言 {x ↦ vy⋆ y ↦ vx}。

考虑另一个更复杂的例子,我们想要证明一个操作链表的程序。假设我们有一个链表,它的头是变量 x。

  1. 我们首先假设 {x ≠ 0 ∧ list(x)}。也就是说,x 不是 0,并且它指向一个链表。

  2. 执行 t := *x。根据堆读取规则,我们可以将 x 的值读入 t。所以,我们得到新的断言 {list(t)}。

  3. 为了证明这个断言,我们需要展开 list(t) 的定义。所以,我们得到新的断言 {x ≠ 0 ∧ (∃e’. x ↦ e’ ⋆ list(e’))}。

  4. 由于我们知道 x 的值被赋给了 t,所以我们得到新的断言 {x ≠ 0 ∧ x ↦ e’ ∧ t = e’}。同时,由于 x 指向一个链表,所以我们还有 {x ≠ 0 ∧ x ↦ e’ ∧ t = e’ ⋆ list(e’)}。

这就完成了证明。这个程序将链表的头赋值给了变量 t。

summary

堆是计算机内存中的一种动态数据结构,它通常被用来存储程序运行时产生的数据。然而,要表达堆中数据结构的行为可能非常复杂,因为我们需要考虑到所有可能的内存配置。为了解决这个问题,我们可以使用归纳谓词。

这里的slides中给出的一个归纳谓词的例子是list(e),它用来描述一个列表数据结构,它的定义如下:

list(e) = (e = 0 ∧ emp) ∨ (∃e’. e ↦ e’ ⋆ list(e’))

这个归纳谓词表示,一个列表要么是空的(即e = 0 ∧ emp,emp表示空堆),要么由一个元素和另一个列表组成(即存在一个元素e’使得e ↦ e’ ⋆ list(e’),这里的e ↦ e’表示e指向e’)。

在你提供的slides中,给出了使用这个归纳谓词的一个证明过程。这个过程就是从列表中取出第一个元素。我们首先定义前提条件{x ≠ 0 ∧ list(x)},然后执行t := *x;,最后得到后置条件{list(t)}。我们可以将归纳谓词展开来证明这个过程,如下:

  1. {x ≠ 0 ∧ (∃e’. x ↦ e’ ⋆ list(e’))} t := *x; {list(t)}
  2. {x ≠ 0 ∧ x ↦ e’ ⋆ list(e’)} t := *x; {list(t)}
  3. {x ≠ 0 ∧ x ↦ e’} t := *x; {x ≠ 0 ∧ x ↦ e’ ∧ t = e’}
  4. {x ≠ 0 ∧ x ↦ e’ ⋆ list(e’)} t := *x; {x ≠ 0 ∧ x ↦ e’ ∧ t = e’ ⋆ list(e’)}

这个过程中,我们在每一步都将归纳谓词进一步展开,直到我们可以清楚地看到在执行t := *x;之后,满足后置条件{list(t)}。

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

chatgpt赋能python:Python中怎样输入数据以及数据类型

Python中怎样输入数据以及数据类型 Python是一种高级编程语言,常用于数据处理和分析、机器学习和Web开发等任务。输入数据是Python编程中的重要环节,因此本文将介绍Python中输入数据的方法和数据类型。 什么是数据输入? 数据输入是指将数据…

国内主流AI大模型盘点

今年年初,轰动科技圈的大事就是ChatGPT的面世,它的到来打响了AI智能时代的第一枪,同时展开了一场别开生面的智能科技革命。 随着ChatGPT迅速走红,国内各大企业纷纷发力认知大模型领域。经过一段时间的酝酿,国内的AI领域也开启了“…

StableStudio,比Midjourney还牛逼的绘画平台,免费!

大家好,我是鸟哥。 之前给大家推荐过Midjourney和Bluewillow两个AI绘画平台:简直了!比Midjourney更刺激,还免费!Midjourney功能超级强大,但比较傲娇,很贵,是否让用户免费体验要看心…

数据可视化系列指南之地图类图表大全

导语 随着数据在各行业中的应用越来越广泛,大家也逐渐认识到数据可视化在企业生产经营中的重要作用,在数据可视化过程中,图表是处理数据的重要组成部分,因为它们是一种将大量数据压缩为易于理解的格式的方法。数据可视化可以让受…

jar包和war包的区别;项目打包成jar或者war且运行在Linux上的tomcat

jar包和war包的区别: war包:通常是web应用后,例如网站,打成包部署到容器(可以是tomcat)中。含有包括WEB-INF包。war包通常就是放在tomcat包的/webapps下然后自动编译和运行。 jar包:通常是开发时要引用的类&#xff…

怎样使用Fiddler进行移动端抓包?附视频教程包你学会

目录 前言 抓包 什么是抓包 哪些场景下需要抓包 Fiddler Fiddler抓包原理 安装 Fiddler移动端抓包 第一步:允许远程计算机连接 第二步,设置手机网络代理 第三步,允许捕获HTTPS连接 第四步,手机安装证书 前言 本篇文章…

chatgpt赋能python:Python中如何提取字段中的数字

Python中如何提取字段中的数字 在数据分析和处理中,经常需要提取文本中的数字数据。在Python中,有多种方法可以实现这一操作。本篇文章将介绍Python中提取字段中的数字的方法,并给出示例代码。 使用正则表达式 正则表达式是Python中处理文…

二十、C++11(上)

文章目录 一、前言二、C11诞生简介三、列表初始化(一){}初始化(二)initializer_list容器1. initializer_list 概念2. initializer_list的使用场景3. initializer_list接口函数模拟实现 四、关键字(一)auto&…

duilib中使用mfc控件

我在界面相隔挺远的位置添加2个mfc控件, 需要添加: 1. 添加 CMfcWndUI 类,这是为了调用mfc控件用的 2. 添加 duilib界面 CDuiFrameWnd 3.重写 2中界面的virtual CControlUI* CreateControl(LPCTSTR pstrClassName); 函数 需要注意的地方…

xray工具—代理扫描、爬虫扫描、Burp联动

xray工具—代理扫描、爬虫扫描、Burp联动 1. Xray介绍1.1. 支持漏洞检测类型1.2. 官网地址 2. 常用扫描模式2.1. 生成证书2.1.1. 浏览器安装证书 2.2. Xray基础主动扫描2.2.1. 基础主动扫描命令2.2.2. 基础主动扫描结果 2.3. Xray代理模式扫描2.3.1. 代理模式配置代理2.3.2. 代…

一场变革来到零售业,盖雅「劳动力账户」助力连锁门店全面管理人效

‍ 上半年,逐渐回暖的出游,为文旅和线下零售业的营收创造了希望, 但面对高周转率和低利润率的行业竞争格局,比起令人兴奋的营收,大部分零售企业仍在焦虑营收背后的成本。 或许是过去三年的环境让更多企业学会了「精…

Microsoft Build 两大主题:Copilots 和插件

在 Microsoft Build 中,贯穿会议的两个主要主题是 Copilots - 涵盖广泛产品和服务的 AI 助手 - 以及插件,它们有效地将 Copilots 转变为聚合器,可能使其成为企业和消费者客户的一站式商店。 微软MVP实验室研究员 张善友 深圳友浩达 CTO&…

Python:Python编程:金融量化交易

金融量化交易 1. numpy2. scipy3. Pandas3.1 : Series 3.2: DataFrame代码示例 在金融量化交易中,下面几个模块是应用的比较广泛的 numpy (Numberic Python) : 提供大量的数值编程工具,可以方便的处理:向量矩阵等运算,…

cuda编程学习——CUDA内存介绍(七)

前言 参考资料: 高升博客 《CUDA C编程权威指南》 以及 CUDA官方文档 CUDA编程:基础与实践 樊哲勇 文章所有代码可在我的GitHub获得,后续会慢慢更新 文章、讲解视频同步更新公众《AI知识物语》,B站:出门吃三碗饭 …

Linux 中断子系统中GIC 中断控制器基本分析

GIC 是 ARM 公司给 Cortex-A/R 内核提供的一个中断控制器,类似 Cortex-M 内核(STM32)中的 NVIC。 GIC:Generic Interrupt Controller,通用中断控制器。 NVIC:Nested Vectored Interrupt Controller&#…

RTX4060Ti上演史诗级尴尬,线下核心商区斩获个位数销量

时隔两年半,一代甜品 RTX 3060 Ti 显卡继任者 RTX 4060 Ti 终于上架了。 经过几天网上对比测试,情况就这么个情况,综合性能提升堪堪 10% 左右,价格上涨至 3199 元起。 来源:clubic 参考 RTX 4090 超 50% 性能提升&am…

聊聊 220V交流 过零检测

聊聊过零检测,以及如何实现过零检测 ...... by 矜辰所致目录 前言一、什么是过零检测1.1 为何需要过零检测 二、如何做过零检测2.1 光耦2.2 比较器/运放2.3 三极管/MOS管2.4 过零检测芯片 三、过零检测电路结语 前言 最近正好项目需求遇到需要做过零检测&#xff…

【刷题之路Ⅱ】LeetCode 1823. 找出游戏的获胜者(约瑟夫问题)

【刷题之路Ⅱ】LeetCode 1823. 找出游戏的获胜者 一、题目描述二、解题1、方法1——单向环形链表1.1、思路分析1.2、代码实现 2、方法2——队列2.1、思路分析2.2、先将队列实现一下2.3、代码实现 一、题目描述 原题连接: 1823. 找出游戏的获胜者 题目描述&#xff…

Java基础篇 | Java基础语法

✅作者简介:大家好,我是Cisyam,热爱Java后端开发者,一个想要与大家共同进步的男人😉😉 🍎个人主页:Cisyam-Shark的博客 💞当前专栏: Java从入门到精通 ✨特色…

2023年上半年网络工程师上午真题及答案解析

1.固态硬盘的存储介质是( )。 A.光盘 B.闪存 C.软盘 D.磁盘 2.虚拟存储技术把( )有机地结合起来使用,从而得到一个更大容量的“内存”。 A.内存与外存 B.Cache与内存 C.寄存器与Cache D.Cache与外存 3.下列接口协议中&…